4 ms·
I’m not familiar with E’s promises, but as far as I know, JavaScript promises have no equivalent of heterogeneous selects (select in Go, select! in Tokio, sync
by nsm 3y ago
I’m not familiar with E’s promises, but as far as I know, JavaScript promises have no equivalent of heterogeneous selects (select in Go, select! in Tokio, sync in ConcurrentML) that guarantee that when one channel/future/event is chosen, the others definitely do not make progress (I.e. a select on a read and a write means only one of them happens on each turn). That seems important.
Promises don’t prevent data races. They only don’t exist in JavaScript because the runtime is implicitly single threaded.
- kragen 3y agoit's true, being implicitly single threaded is what prevents data races; promises are an alternative to shared-memory multithreading that does a better job of preserving that property than shared-memory multithreading does if you want to select on multiple promises, it's relatively easy to do in javascript; you make a new promise for the disjunction of the multiple promises (e.g., using .withResolvers()), and attach a callback to each of the original promises that resolves the disjunction promise when it fires this of course does not prevent the other promises from getting resolved, because that would happen in some other piece of code, perhaps in response to a network i/o event or a filesystem i/o event; knowing whether a particular turing-complete event handler is going to resolve a particular promise (so you could avoid running it) would require solving the halting problem
- nsm 3y ago> this of course does not prevent the other promises from getting resolved, because that would happen in some other piece of code, perhaps in response to a network i/o event or a filesystem i/o event; knowing whether a particular turing-complete event handler is going to resolve a particular promise (so you could avoid running it) would require solving the halting problem It does not if you control the implementation of the language primitives ;) I’m not smart enough to answer exactly how, but Andy Winford explains how CML does it using the notion of optimistic and pessimistic stages. https://wingolog.org/archives/2017/06/29/a-new-concurrent-ml https://wingolog.org/archives/2017/06/29/a-new-concurrent-ml
- kragen 3y agothanks, this is a really interesting article! but it seems to be about something different fundamentally one of the major things promises are useful for is waiting on network packets which may never arrive. (in the small, sometimes the network in question is sata or usb, but that makes surprisingly little difference.) there's really nothing you can do to keep some other host from sending you a response packet to a request you've already sent it, and when your network interrupt fires, unless you've brought the network interface down entirely, your interrupt handler needs to do work to buffer the packet (if necessary) and inspect it to see where to route it to. if that turns out to be a promise, all of this is 'making progress on' a promise that may be canceled or whose fulfillment may have no effect. (you could, however, limit the resources you dedicate to such useless work: an important optimization in many contexts, but not one that needs language-level support) so even controlling the implementation of the language primitives doesn't help
- nsm 3y agoYour point is entirely valid. I had not thought of it. Makes sense for resource consumption. I think selection is about what is visible to your program. I.e. that even if that packet arrives, if you choose another path in the select, then the recv() is guaranteed not to happen. You are right that a program doing this has to handle this case correctly, which I think is what the whole Rust future cancellation conversation is about.
- nsm 3y agoI meant Andy Wingo, damn autocorrect!
- zozbot234 3y agoYou can have a single-threaded executor in Rust too, which can also share data across tasks with no synchronization. So Rust futures can be both.
- kragen 3y agoagreed!