6 ms·
Channels in Common Lisp
- wtbob 10y agoThis illustrates the power & the problem of Common Lisp: the power is that it really is easy to add channels (and pretty much every other feature) to the language yourself; the problem is that it's generally easier to write your own code to do this than to use (or fix …) someone else's. I've experienced exactly this: I too looked at ChanL. In my case it had a bug for one of my use cases, and it was honestly easier to roll my own channels (with, of course, their own bugs) than to understand & fix ChanL's bug. The problem is that this leads to a proliferation of different libraries, all doing similar things. The power is that one really can write just about anything, and it will work well enough for your use case.
- codr4life 10y agoWhat you're saying is really that it's too powerful for it's own good. And I agree. But what's good for Lisp isn't necessarily good for me, I prefer more power to one size fits all libraries. I think it comes down to experience in the end; the more you have, the more unwilling you are to give it up.
- reikonomusha 10y agoI disagree about it being "too powerful for its own good". If it was, we would have a magnificently efficient and useful library come out of this that brings Go- or Erlang-style programming to Lisp. But alas, this code does not. A lot of hardcore Lisp aficionados do the equivalent of a mathematician writing a "sketch of a proof" and saying "left as an exercise", without ever writing the details of the proof. It's occasionally aggravating when you pull in a library and discover that this is the case. To be clear, there are many Lisp folks do not do this. Some go the full mile and implement something completely and robustly. Edi Weitz has been the canonical example in the community.
- codr4life 10y agoCompletely, what is that? Doesn't that depend on context (as in problem being solved)? Simple is often faster, and these are pretty fast without even trying. There is plenty of room for simple, fast enough code. Owning code you understand is an advantage.
- rtpg 10y agoCompleteness means being as performant as possible on all the possible axes. You might want simplicity, but users also want performance. So a complete solution will be performant, but simple. You have one use case, but other users have others. A complete solution will work in as many use cases as possible given its constraints. Scala's parser combinators are a good example of a complete solution. It offers the "elegant" solution of parser combinators. But it also offers an implementation of this using things like Packrat parsing that are extremely efficient. The non-complete example of this is someone who writes a parser combinator library that is simple, but simply not performant for real world use. For example, you might write a simple version in Python, but not properly apply TCO and so your parser can't handle deeply nested structures because of a stack overflow. --- With regards to owning code, I remember hearing that it took 9 years of the initial publication of quicksort for there to be a bugfree implementation of it. Even easy things can be tricky.
- jonathanstrange 10y agoCompletely, what is that? Well, comprehensive unit tests for a start...
- codr4life 10y agoWhat's comprehensive? Doesn't that too depend on context? I'm with Kent Beck on tests. I'll test as much as I have to too move forward with confidence. In the end, my goal is to write working code, not tests.
- TeMPOraL 10y ago> A lot of hardcore Lisp aficionados do the equivalent of a mathematician writing a "sketch of a proof" and saying "left as an exercise", without ever writing the details of the proof. It's occasionally aggravating when you pull in a library and discover that this is the case. That's exactly "too powerful for its own good". It's so easy to write a half-assed sketch of a library that nevertheless gives you some new powerful feature, that some people end there, and publish the sketch that was enough for their use case.
- wtbob 10y agoI guess I should have mentioned that Lisp is my language of choice. I like the ease with which I can implement anything. But it does have a cost: everyone else implements everything himself, too. I actually think Quicklisp has helped. It's even easier to do (ql:quickload "foo-lib") than it is to write my own foo library.
- nickik 10y agoEverybody can do that stuff in Clojure too, and it does not suffer from the same thing CL does. It seems to me that it is a culture/ecosystem problem more then anything else.
- reikonomusha 10y agoAs you sort of imply, it doesn't help that each implementation is half-baked, incomplete, and unmaintained after 16 months. I've seen similar libraries that do the following, for example: * Serialization and deserialization * Promises * Generators * CPS Somehow none of these "100 line wonders" make it into idiomatic usage, despite their purported utility. These channels as presented don't solve many problems well. They will be very slow and contentious, they will be expensive to make, and they will not guard against memory ownership issues because you're just passing pointers to objects around, which message passing is supposed to solve. But, it'll become another library on Quicklisp that 3 people use and that people's applications will inadvertently depend on. Lisp is a fantastic language for many things, including a plethora of production applications, but it being a local optimum for exploratory programming means we get lots of very incomplete, scratch-an-itch code that is pawned off as a library intended for mass consumption. In fact, the author links to his GitHub repository, where you find exactly this random assortment of disparate utilities. If I had my way, the rhetoric of this post would be closer to a pedagogical exposition of channels, how they're used, what their benefits are, a proof-of-concept implementation, and a non-trivial example application. I would vehemently stay away from having the thesis be anything about Lisp or the ease of implementing small POCs in Lisp.
- codr4life 10y agoThis implementation is yours to maintain, that's why it's simple enough to make that possible. There is plenty of room for simple. They allow building networks of cooperating threads, which is the purpose. Erlang isolates, Go doesn't, in the end I like the choice.
- reikonomusha 10y agoCopy-pastable blog post code is the antithesis of good software engineering practices. DRY, encapsulation, reusability, broadly applicable abstractions, and so on should ideally be heralded as the thing to strive for.
- codr4life 10y ago
- deleted 10y ago[deleted]
- dfox 10y agoIn this case particular case, what is being shown is that channels in itself are pretty simple concept, especially when done on top of language with preemptive multithreading. Same thing can be implemented in essentially any imperative language with necessary primitives by code that looks more or less exactly same.
- codr4life 10y agoC with pthreads won't look the same, I know because I've tried hard. Java most definitely won't. Which languages are we talking about here anyway?
- junke 10y ago> The problem is that this leads to a proliferation of different libraries, all doing similar things. This is not "left-pad" either. I'd say you have the same problems in C or C++, where people are reluctant to depend on libraries they don't control or appear to be bloated (boost, etc.). As far as Lisp is concerned, this post talks about the problem more directly: http://fare.livejournal.com/169346.html http://fare.livejournal.com/169346.html
- teddyh 10y agoThis is known as the “Lisp Curse”: http://www.winestockwebdesign.com/Essays/Lisp_Curse.html http://www.winestockwebdesign.com/Essays/Lisp_Curse.html
- maxekman 10y agoReally interesting read for me as an experienced Go developer currently learning Lisp. Not sure if I will ever use Lisp or this for a real project, I see it more as some kind of Sudoku in code, and a indirect training ground for Elixir (which is a wonderful complement to Go for backend tasks).
- codr4life 10y agoDo it. I spent years nervously fingering On Lisp on lunch breaks without really getting anywhere. But Paul Grahams early essays kept pulling me back into Emacs, and on each iteration something fell into place. It me took a long time to feel comfortable, but I wouldn't trade the feeling for anything. It's an alien chain saw; chain saws are intimidating enough in themselves, one with completely alien controls and instructions even more so. To paraphrase Graham, power looks weird from below.
- progman 10y agoI use Common Lisp for real projects. My recommendations: - Always follow the KISS principle (https://en.wikipedia.org/wiki/KISS_principle https://en.wikipedia.org/wiki/KISS_principle). Don't use Lisp's "super features" too much. The same applies to Haskell, by the way. - Use QuickLisp as much as possible. In many cases you don't need to add your own lib. Read Quickdos [QDC]. - Comment your code well, even if others don't ever see it lest you could not be able to understand your own code later. What's the purpose of the function, which arguments are expected, of which expected type are they, what are the possible results, possible side effects, etc. - Read and understand how Lisp's package system really works. This is important to avoid strange behaviors in your own code. - Use SLIME (https://common-lisp.net/project/slime/ https://common-lisp.net/project/slime/). It is an awesome interactive debugger which catches bugs and presents different options how to deal with that. SLIME is also useful as manual for Hyperspec (http://www.lispworks.com/documentation/HyperSpec/Front/ http://www.lispworks.com/documentation/HyperSpec/Front/) which is a basic tool to look quickly for code examples. - Don't use Hyperspec too much because it is really confusing. Use proper reference manuals like Peter Seibel's Practical Common Lisp [PCL] and Edi Weitz' Common Lisp recipes [CLR] - If you cannot get used to Emacs (which is a wonderful tool with a steep learning curve, really the best editor ever) then you can use proprietary IDE's like LispWorks or Franz Allegro. [QDC] http://quickdocs.org/ http://quickdocs.org/ [PCL] http://www.gigamonkeys.com/book/ http://www.gigamonkeys.com/book/ [CLR] http://weitz.de/cl-recipes/ http://weitz.de/cl-recipes/
- oskarth 10y agoSurprised that a thread about CSP in Lisp doesn't mention Clojure's core.async. CSP in Clojure is implemented as just another library and it's rock solid. While I don't claim to understand the implementation in detail, it's one of the more interesting and high leverage uses of macros I've seen in Clojure. It makes concurrent programming a breeze in Clojurescript as well, despite JS being single-threaded. As someone who programs in both Clojure and Go there's absolutely nothing I miss from CSP in Go, and I would much rather do concurrent programming in Clojure. Rationale: http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html http://clojure.com/blog/2013/06/28/clojure-core-async-channe... Code: https://github.com/clojure/core.async/blob/master/examples/walkthrough.clj https://github.com/clojure/core.async/blob/master/examples/w... Presentations: https://github.com/clojure/core.async#presentations https://github.com/clojure/core.async#presentations
- jgalt212 10y agoAs I understand it, there are multiple ways to do concurrency in Clojure. Is there a best way or a way that fits most use cases so that you should at least try feature X before features Y, Z, and/or roll your own?
- deleted 10y ago[deleted]
- deleted 10y ago[deleted]
- nickik 10y agoThere is no easy path you can follow sadly. It depends on your use case quite a bit. Clojure gives you a lot of options and you have to find your own way. What Clojure gives you by default, are thread safe mutation constructs, atoms, agents and refs that help a lot if you want to do simply concurrent things without worrying about race conditions. Clojure also has support to get some data parallelism, you can easily do a lot with reducers and transducers. Its quite nice. For more complex stuff, core.async gives you a powerful CSP library, its as powerful as what the Go programming language gives you (I think its nicer because Go has statements instead of expressions). Because Clojure is on the JVM, you get access to all the Java stuff, java.util.conncurrent, and you can get a lot of powerful tools there (ThreadPools and stuff like that).
- haspok 10y agoSorry for the nitpicking, but: "One of the things that Go (and Erlang) got right was using channels as the main mechanism for synchronising and communicating between threads." Erlang doesn't have threads and doesn't use channels either. Erlang has lightweight processes, which might map onto OS threads (but user code has no control over this). Erlang uses async communication which is always non-blocking (of course, you can emulate sync communication, the gen_server:call behaviour in the OTP library does that, for example). Otherwise, spot on! :)
- zzzcpan 10y agoOnly Erlang got it right, not Go. And channels were not even invented for real life programming, they were just an easy notation for mathematicians. But an interesting thing about concurrency is that the Erlang myth is actually true, getting deeper into concurrency always leads to reinventing Erlang. The road typically goes from synchronous multithreaded applications to asynchronous single threaded to event loops to higher-order abstractions around events to wrapping them into killable process/context abstractions to adding message passing and to reinvented Erlang.
- codr4life 10y agoCool, just wanted to add that there's nothing wrong with reinventing Erlang either. We're all in the same boat, ideas are universal.
- farray 10y agoI once tried ChanL but it was buggy, and concurrency bugs are the worst to debug. lparallel on the other hand was solid to me, though I didn't like its API and had to (trivially) build my own message-passing abstractions on top of it.
- fiddlerwoaroof 10y agoI've been a bit interested in this, basically an attempt to bring some of the nice things of the Erlang/OTP platform to CL: http://mr.gy/blog/erlangen-intro.html http://mr.gy/blog/erlangen-intro.html
- lispm 10y agoThe book by Hoare on CSP http://www.usingcsp.com/cspbook.pdf http://www.usingcsp.com/cspbook.pdf published in 1985 actually used Lisp: > The proposed implementations are unusual in that they use a very simple purely functional subset of the well-known programming language LISP. This will afford additional excitement to those who have access to a LISP implementation on which to exercise and demonstrate their designs.
- jsjolen 10y agoI think a lot of people in this thread are being absolutely ridiculous. It's not easy to implement channels in Lisp because of Lisp, it's because the work is already done for you. What mainstream language doesn't have structs, condition variables, locks, threads and... Wait, I think that was all of it? Oh, and linked lists. I mean come on, you could do this just as easily in Java. And all this talk of the Lisp curse, Jesus Christ. I mean, there's a point in that there are a lot of lackluster libs (but what language doesn't have that), but Quicklisp and a switch in Lisp culture means that there's a large amount of collaboration (and usage of libs) between programmers. There's the potential to start to use the same libraries and a will in the community to do so.
- junke 10y agoThanks.