On Mar 21, 2011, at 8:52 AM, James Reeves wrote:

> On 21 March 2011 11:29, Chas Emerick <cemer...@snowtide.com> wrote:
>> The notion of "passing around Clojure data structures" does get watered down 
>> because of the non-sexpr-nature of e.g. *out* and *err*, and it's all 
>> message-oriented so as to support asynchronous evaluation from the same 
>> client, but that's pretty much what nREPL does.  Expressions are sent, 
>> results are printed and sent back.
> 
> That wasn't quite what I meant :)
> 
> You could use a Clojure data structure protocol (henceforth known as
> CDSP) to send the just data you want evaluated by the REPL, e.g.
> 
>>>> (+ 1 1)
> <<< 2
> 
> But that's probably too simplistic. Instead, you'd probably encase
> messages in a map, e.g.
> 
>>>> {:id 1, :eval (+ 1 1)}
> <<< {:id 1, :return 2}
> 
> Which would allow you to handle more sophisticated streaming stuff as well:
> 
>>>> {:id 2, :eval (do (Thread/sleep 1) (print "world"))}
>>>> {:id 3, :eval (print "hello")}
> <<< {:id 3, :out "hello"}
> <<< {:id 3, :return nil}
> <<< {:id 2, :out "world"}
> <<< {:id 2, :return nil}
> 
> My point was more that network protocols should be designed in layers.
> Take a streaming protocol like TCP, layer netstrings on top of it so
> you have a safe way of passing fixed-length messages. Then use the
> Clojure read-string and pr-str functions to encode data.
> 
> You then have a very basic protocol that allows you to communicate in
> more complex data structures, like maps, vectors and lists, which you
> can use as a basis for a more sophisticated protocol.
> 
> In essence, we want to build a compound network protocol out of simple
> components. You don't have to use netstrings and Clojure data
> structures to do it, but they seem like a good fit.

I think we're in violent agreement.  Here's a sample nREPL exchange from 
https://github.com/clojure/tools.nrepl:

> [catapult:~] chas% telnet localhost <port-number>
> Trying 127.0.0.1...
> Connected to localhost.
> Escape character is '^]'.
> 2
> "id"
> "foo"
> "code"
> "(println 5)"
> 3
> "ns"
> "user"
> "id"
> "foo"
> "value"
> "nil\n"
> 3
> "ns"
> "user"
> "out"
> "5\n"
> "id"
> "foo"
> 3
> "status"
> "done"
> "ns"
> "user"
> "id"
> "foo"


It's probably not clear from the listing, but only the first message is being 
sent; the next three are received.  There's really not a lot of sophistication 
here; indeed, it's even less sophisticated than if the messages were being sent 
using sexpressions, that that would require a lisp reader and printer (of some 
diminished capacity, presumably) on the client side.

As Kevin was saying elsewhere, the entry count that precedes each message could 
be replaced with a terminator, or start and end tags if one so wishes.  Those 
that really, really like sexpressions might use braces:

{"id"
 "foo"
 "code"
 "(println 5)"}

I considered doing this, but thought it better to not imply that the protocol 
allowed for any ol' readable data structure to be passed along.

- Chas

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to