Table of Contents for Programming Languages: a survey
always use timeouts!
and futures etc
con: "...the cumbersome use of callbacks. This, of course, is a problem with many asynchronous computations: you gain concurrency but lose the natural code flow. It’s hard for a programmer to reason about which line of code executes on which thread, and passing information from one callback to another is cumbersome as well." -- http://blog.paralleluniverse.co/post/64210769930/spaceships2
TJ Holowaychuk describes how callbacks can be more error-prone than some other concurrency techniques:
"In Go when my code is done, it’s done, you can’t get re-execute the statement. This is not true in Node, you could think a routine is completely finished, until a library accidentally invokes a callback multiple times, or doesn’t properly clear handlers, and cause code to re-execute." [1]
todo: i think: With callbacks, programmers can forget to propagate errors, leading to an error crashing a thread without the rest of the program noticing.
An alternative to callbacks that allows you to write the code in an easier-to-read manner.
'promises' are used somewhat interchangably, although some languages have both 'promises' and 'futures' and distinguish between them
implicit (it's just a value from the program's point of view) vs. explicit (it's a structure that you query to see if it's been bound yet)
in some languages, the writable side of the future is separated from the readable side (like a pipe). This allows you to e.g. copy the readable side and pass it to 5 consumers, and pass the writable side to 1 producer, without fearing that one of the consumers will overstep their authority and try to write to the future.
in clojure, it's easy to make futures behave like ordinary variables, because stateful variables must be 'deref'd anyway
clojure has something called a 'promise' and something called a 'future'. The difference is that with a clojure 'future', at the time of future creation you bind an expression that will be evaluated to give the result; whereas with a clojure 'promise', the promise is just a structure that you later bind a result to, e.g. the computation that will produce the result need not be determined yet at the time of promise creation. (see http://stackoverflow.com/questions/4623536/how-do-clojure-futures-and-promises-differ ). Promises are read-only. (this terminology is flipped in the C++ Folly Futures library [2])
in c++, futures are (see http://stackoverflow.com/questions/12620186/futures-vs-promises ) the read side and promises are the write side.
A hardware version is full/empty bits, found for example in the https://en.wikipedia.org/wiki/Cray_MTA : "For example, an array A is initially written with "empty" bits, and any thread reading a value from A blocks until another thread writes a value.". In the Cray MTA, the blocking on empty bits eventually times out. Opcodes are provided which ignore full/empty status.
There is a standard for promises in Javascript, http://promisesaplus.com/ . It was referenced by https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 , so perhaps it is canonical.
facebook's C++ Folly Futures library has a good explanation of various things (if you can read C++):
some constructs in the Folly library mentioned in that introduction are:
Rust futures:
C# await: http://msdn.microsoft.com/en-us/library/hh156528.aspx
the idea is that if you have a promise, you give that promise to the 'await' keyword, which puts the current block of code 'on hold' until the promise completes, and in the meantime yields control to YOUR caller.
Python 3.5's async/await:
Javascript's (contrasted with callbacks, and (raw) promises):
like neuro -- always have an answer even if your inputs aren't ready (the answer can be 'i don't know')
(just like in the serial case with coroutines)
(just like in the serial case)
alternative: callbacks
generalize to unordered eventcounts (cite Unify: A scalable, loosely-coupled, distributed shared memory multicomputer; that article reserves the term 'eventual consistency' when there is a maximum time duration until consistency)
supports 3 operations
wait: go to sleep until you get woken (see below)
signal: wake one thread waiting on condVar
broadcast: wake all threads waiting on condVar
example usage: producer/consumer: Every now and then, the producer sends some data, and then the consumer is supposed to do something with it. It would be a waste of time for the consumer to busy wait for new data. Solution: The producer signals the condition variable when they produce something. the consumer sleeps on the condition then wakes up and processes what the producer produced.
todo should this also be mentioned in 'locks and friends'?
? or should this be in a different chapter
Data Flow and Systolic Array Architectures, "Computer Architecture" Chapter 8, M.Zargham
? or should this be in a different chapter
'observable' = 'stream'
you can treat streams like lazy lists; you can filter and map over streams
a promise is a stream with only one event to be emitted on it
to apply an async operation (which returns a 'promise' type of stream) to a stream, you flatmap that operation over the stream; this (a) maps the operation over the stream, transforming each event (input to the async operation) into a promise stream (output of the async operation), (b) takes the resulting stream of streams and flattens (merges) it into one stream (since each promise stream only had one event on it, each one will contribute one event to the final, flattened stream)
Links:
? should this be subsumed under dataflow or event-driven programming? ? maybe not: a key feature two-way (symmetric) updates or even cyclic dependencies
Links: