But I have a give a warning again, when you try to avoid allocation
overhead, you have to face the risk of the side-effect. To me, I'd
prefer pure-functional. ;-P
Your solution seems reasonable, but I have found another way, which lead me to some new problems.
I realised that since sockets are ports in guile, I could process them with the plain "read" (which is what I have been using them for anyway).
However, this approach caused some new problems. The thing is that if I'm trying to read some message from port, and that message does not end with a delimiter (like a whitespace or a balancing, closing parenthesis), then the read would wait forever, possibly gluing its arguments.
The solution I came up with is through soft ports. The idea is to have a port proxy, that -- if it would block -- would return an eof-object instead.
The current implementation is rather straightforward:
(define (nonblocking port)
"returns a port proxy that returns eof-object on read attempt \
if a read would block"
(make-soft-port
(vector
;; 0. procedure accepting one character for output
(lambda(c) (write c port))
;; 1. procedure accepting a string for output
(lambda(s) (display s port))
;; 2. thunk for flushing output
(lambda () (force-output port))
;; 3. thunk for getting one character
(lambda () (and (char-ready? port)
(read-char port)))
;; 4. thunk for closing port (not by garbage collection)
(lambda () (close-port port))
;; 5. (if present and not `#f') thunk for computing the number of
;; characters that can be read from the port without blocking
(lambda () (if (char-ready? port)
1
0)))
(string-append (if (input-port? port) "r" "")
(if (output-port? port) "w" ""))))
One problem is that two messages, if not formatted properly, can still be glued together (although they no longer cause read to hang).
The other thing that puzzles me is the last function provided to the soft port vector -- the one that computes the number of characters that can be read.
Its only public interface I know of is through the "char-ready?" procedure. So there is no way for me to check the number of characters available in the original port. This is strange.
The other thing is that I would like to have some means to make sure that an eof object is emited after reading each package sent through the socket, so that it wouldn't be possible to glue together data sent in two separate packages.
I could of course create a more sophisticated soft-port, that would be implemented entirely using send and recv!, but I wonder if there's any simpler way.