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