Concurency is important to make full use of modern hardware. Lots of tasks really don't benefit: they are boring data manipulation and UI management. But when you have a CPU-intensive task, you really want to parallelize it. And you want data-structures that allow this. But if you don't have all that many CPUs, you want very light-weight tasks to do the work. We definitely want data structures like bag and lists that can be accessed concurrently safely, and we want dependencies to be sufficiently clear that some normally-sequential steps can run in parallel. This is where message passing comes in - having a 'channel' that is used to pass a message from one code block to another can then be a simple variable, or can be a synchronization object. You might need a lot of such objects, so they need to be created dynamically - like stack-frames. I probably need to experiment with some specific examples: - quick sort - unordered search - image scale - .. The other perspective on concurrency is the need to be non-blocking, even when using a single CPU. This needs to be more explicit, probably with a fork/join model. This could look like a 'continuation' where we store code in a variable, but the code starts running immediately and the variable changes value somehow when the code completes. Having thought about this during my run this morning, my current position is: 1/ we have locking primitives, fields which indicate what lock protects them, and pointers which are typed to say what lock they own. Locks are generally nreader-xor-1writer and spin or wait on a queue, possibly dedicated, possibly chosed by hash. a refcount is a lock that is mostly in the nreader state. A 'writer' which frees the object might get queued at object creation. 2/ we have "completions" in the language which are a bunch of code combined with some data state - a bit like an object, but described dynamically in-line. A completion can be created easily and might be: - run immedately - stored and run later - run asynchronously. In this case the returned value is a queue that is easily waited on. A completion might return a 'channel' which returns a seqeunce of values. In the run-immediately case, this is like a loop. In the stored-and-run-later, it is like a generator. A completion combines code and data. The data is sucked from the environment. Any borrowed pointers need to have their owner too, and ownership needs to be duplicated or moved or whatever. For a generator, we need explicit "use" calls. So want them for regular completions too.??? or is "return" cleaner because it doesn't go to a channel exactly...?? I need a clean syntax for this. foo := continuation ? no, I think that looks weird. I want it to be obvious from the start. But where do we store the handle? cont foo:= code fork foo:= code