Hacker News new | past | comments | ask | show | jobs | submit login

> The one bone I have to pick is the juxtaposition of PFP and imperative as opposites.

Well, I most certainly didn't say FP and imperative are opposites; quite the contrary: most FP languages are imperative. Part of the confusion is that there is no definition of FP. PFP, OTOH, is well defined: it is a style of programming where all functions are pure. If you can write impure functions, you're not doing PFP, and if you're doing PFP, you can't write impure functions.

> I'm not sure I buy the idea that scoped continuations should replace this monad usage.

I'm not entirely sure what you mean by "this usage" (lists?), but, like I say in the talk, I think monads are great for parallel streams, where you explicitly don't care about the stack context.

> I wonder how this jives with the actor model... When the author mentioned the thread being the atom of imperative programming, actors immediately came to mind.

Exactly. Threads (and by that I mean any thread implementation, not just kernel threads) are the best use of continuations, and blocking actors like Erlang's (or our own Quasar) make great use of (lightweight) threads, as do Go's goroutines (and Quasar fibers).

> may come down to how easily it can be expressed and comprehended within real programming languages. I found the examples in the original talk and the blog post to both be rather difficult to follow.

My opinion is that it's not important for scoped continuations to be directly exposed at all, and if they are, they should be rarely used directly. Using them to create lightweight threads solves almost all of the problems with the monadic style, and the code looks just like any plain-old thread-blocking code (we've had very good success with that in Quasar; Code stays the same, but instead of blocking a kernel thread, it blocks a fiber; the APIs don't even need to change).

> The former, probably because of the use of = to select the scope

I admit that when I gave the talk the precise details of the API and usage weren't yet clear to me, which is why I wrote the post.

> because of the verbosity of Java

Where does Java's verbosity bother you here? (although I'm probably biased, as I like Java's, or Go's, intentional verbosity)




Fair point on PFP.

> I'm not entirely sure what you mean by "this usage" (lists?) [...]

By "this usage", I meant containers, generally. Maybe algebraic data types would be more specific.

> [...] blocking actors like Erlang's (or our own Quasar) make great use of (lightweight) threads [...]

Have you been following the Reactive Manifesto [1] and reactive streams [2]? If so, do you have any thoughts on whether this it builds out design practice in a complementary way to your suggestion here, or is it divergent?

> Using them to create lightweight threads solves almost all of the problems with the monadic style, [...]

My concern here would be whether you'd then be recreating the old problem you mentioned of having many implicitly monadic constructs in imperative programming but no good way of adding your own. In the analogous case in PFP, even if the continuation monad is the mother of all monads (and I haven't finished reading that post you linked to), I'd have to imagine it wouldn't be a whole lot of fun to use it exclusively. Or else people would do it!

> Where does Java's verbosity bother you here?

I probably should have withheld comment on Java's verbosity. There's probably nothing wrong with it. I think I'm just used to Scala and dynamically typed languages.

Anyway, awesome work. You make a lot of great points.

[1] http://www.reactivemanifesto.org/

[2] http://www.reactive-streams.org/


> Have you been following the Reactive Manifesto [1] and reactive streams [2]? If so, do you have any thoughts on whether this it builds out design practice in a complementary way to your suggestion here, or is it divergent?

Reactive streams' design is the dual to threads/fibers/continuations, and I believe that as a user facing construct it is the wrong one (I'll get to that in a minute), but, as Java does not yet have a standard, built-in implementation of continuations/fibers, Reactive Streams is meant as an interoperability standard and does a very good job at that. I like that it exists and I like the spec, which is why Quasar is also RS compliant (turning every stream to a channel and vice-versa).

I don't like the reactive manifesto, though. It conflates some well-known design practices -- which we simply used to call "robust soft-realtime" -- with a specific implementation (nonblocking), and in the process, overloads a term, "reactive programming", which has a very different meaning (dataflow, i.e. spreadsheet style). Even Erlang, the inspiration to the manifesto, doesn't conform to it (because it discusses implementation). Also, I'm not too fond of manifestos in general.

As to push-based streams, I didn't have time to get into that in the talk (the slide is there, though), but I believe that in imperative languages a pull-based API (like channels) is always superior to a push API for several reasons:

* It is more general -- both are duals, but going from pull to push only requires a while loop. Going the other way requires adding a queue.

* It conveys more information to the developer -- in the push approach, the concurrency is clear: the item is received on the same thread that calls `receive` (the only thing you need is maybe just a tag saying if `receive` itself is thread-safe or not). With a push API, the developer needs to read the documentation to figure out whether the callback can be called on multiple threads concurrently, and, if not, whether it's always called on the same thread.

* It conveys more information to the library -- a pull API has implicit, automatic backpressure. Calling `receive` means we're ready to receive more. With a push API you either don't have backpressure, or, like with reactive streams, you need explicit backpressure (`request`) along with more documentation on when `request` may be called. Look how much of the RS spec is devoted to specifying exactly that, and how much shorter it would be if it were a pull API (like Go or Quasar channels).

> My concern here would be whether you'd then be recreating the old problem you mentioned of having many implicitly monadic constructs in imperative programming but no good way of adding your own.

Well, yeah, but that's a secondary issue. I'm not a language purist, and you always need to weigh which is better -- a very general abstraction that is then put to use by everyone to create their own incompatible DSLs, or choose the most useful specific abstractions and make sure everyone can read everybody's code, even if not everything now has the most elegant expression. For large projects I think the latter is preferable.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: