5 ms·
Would waiting on a mutex or signaling a semaphore require explicit awaiting in Dada? What about faulting in an mmaped memory buffer?
by gpderetta 3y ago
Would waiting on a mutex or signaling a semaphore require explicit awaiting in Dada? What about faulting in an mmaped memory buffer?
- avianlyric 3y agoI honestly don’t understand why you seem to be getting so upset about this. Dada isn’t a real language, it’s a thought experiment. It’s whole purpose to ask exactly these questions, and discuss the consequences, so those learnings can be used to inform other languages. Arguing that a particular design choice is silly from a purely ergonomic or usage perspective is kind of absurd, given you literally can’t use the language at all. Maybe waiting for a mutex, signalling a semaphore, or waiting for page faults should require an await (although it’s literally impossible for a language to await a page fault without a lot cooperation from the OS). The whole point of Dada is you can make those design choices, then work through the consequences. Maybe it turns out they’re actually fantastic ideas, once you get past the surface level issues, or maybe they’re terrible ideas. But once again, Dada doesn’t actually exist! It’s a thought experiment to test all kinds of ideas, but without having to waste all the time and energy building those ideas to discover issues that could have been discovered by simply having a conversation.
- gpderetta 3y agoSorry for appearing that way, I'm genuinely not getting upset. I'm just passionate about this relatively minor corner of language design. Exactly because Dada is just a thought experiment it interesting to push the boundaries of such a model in various ways with low stakes. Constructively, I'm partial to full coroutine abstractions that hide the asynchronouness of functions or on the other side of the spectrum, to full effect systems. I think async is a necessary evil on some high performance languages (like rust, C++, certainly not python), but elevating it to an actually desirable from the ergonomic point of view seems just wrong.
- avianlyric 3y agoI think there is value in elevating it from an ergonomic point of view, especially when walking that boundary between concurrency and parallelism. Pure concurrency has the advantage that you can do away with a lot of complex and nuanced synchronism mechanisms, by virtue of the fact you’re not actually sharing memory between parallel lines of computation. Something that makes writing correct concurrent code quite a bit easier and friendlier. In that world have clear and explicit markers of when a function call might result in you yielding to the event loop, and thus memory values you read previously in your function might change, is very handy. Especially if there’s a nice mechanism to delay that yield until after you’ve completed all your important memory operations, and have confidence that your computed values are consistent. Coroutines are certainly a different approach to the same problem, so hide the blocking nature of functions in a neat way, but at the cost of requiring you to start using those complex synchronisation primitives, because any function call or operation might result in an implicit yield, and thus you can’t predict when memory values might change. My first introduction to async/await was the Twisted framework for Python. It wasn’t called async/await back then, the principles were identical. Twisted made it possible to write pretty high performance concurrent network code in python, in a way that was very understandable, and _safe_, without resorting to multi-threading or multi-processing. As a result I think the async/await in Python is actually a really good idea. When used correctly, it makes it possible to write really nice, performant, code in python, without resorting to parallelism, and all the pitfalls that come with that (I.e. synchronisation). Async/await provides a nice middle ground between full on parallelism, and single threaded blocking code with no ability to interleave IO operations.
- gpderetta 3y ago> concurrency has the advantage that you can do away with a lot of complex and nuanced synchronism mechanisms, by virtue of the fact you’re not actually sharing memory between parallel lines of computation. That's the bit I reject. In practice you are saying that there are no reentrancy concerns between preemption points (async calls), and marking those points explicitly in code help avoid bugs. I claim that: a) there can be are reentrancy issues even in regions only performing sync calls (due to invoking callbacks or recursively reentering the even loop) b) if we value explicit markers for reentrancy, we should be instead explicitly marking reentrancy-unsafe regions with atomic blocks instead of relying on the implicit indirect protection of within-async regions. With async you still have to think about synchronization, but instead of being explicit and self-documenting in code with synchronized objects and critical sections, you have to rely on the implicit synchronization properties. And if you write code that rely on it, how do you protect against that code breaking when someone (including ourselves) shuffles some async calls around in three months? In fact something like rust, thanks to lifetimes and mutable-xor-shared, has much better tools to prevent accidental mutation. Don't get me started on python, asyncio is terrible in its own unique ways (the structured concurrency in trio and similar seems much saner, but I have yet to use). [Sorry for continuing this argument, as you can tell I have quite strong opinions on it; feel free to ignore me if you are not interested]