4 ms·
Let's say a language A is syntactic sugar over a language B if A can be translated to B by macro expansion. In that case, if B is sufficiently expressive, e.g.,
by fmap 9y ago
Let's say a language A is syntactic sugar over a language B if A can be translated to B by macro expansion. In that case, if B is sufficiently expressive, e.g., has first class functions, then in many cases A will be syntactic sugar over B. On the other hand, there are many language features that are orthogonal to first class functions, for which the translation is no less complicated than the frontend of most compilers. For example:
- Delimited continuations
- Related to this, algebraic effects and handlers.
- Implicit types.
- Join patterns for concurrency.
- Linear/Affine ressource management.
- Related to this, type state and session types.
- Probabilisitic programming.
- Differential programming.
And many more. The point is that you do not want a language that includes all of these extensions at the same time, since many are mutually exclusive. For example, differential programming does not mix with state or first-class functions. Linear types ensure safe ressource management, but you need an escape hatch both for efficiency and your sanity. Algebraic effects or delimited continuations in a language which already has imperative features will lead to very fun bugs as soon as someone unfamiliar with the language implementation tries to mix the two features.
On the other hand, for every single example in this list I can point to an application domain where the additional expressivity is beneficial.
E.g., delimited continuations are extremely nice when implementing some complicated backtracking search. A DSL with (pure functions and) first class support for delimited continuations can express such a search function very naturally and later on - in the compiler for the DSL - we can decide how to implement this feature.
This allows for additional optimizations, which would otherwise be implemented in an ad-hoc manner. For example, several linear return continuations can be implemented by having several return addresses and stack pointers and restoring one of them, rather than using a cactus stack. Another example, rarely used return continuations can be tracked out of line as in "zero-cost exception handling".
Mixing these implementation details with the implementation of your search function is just a bad idea, since they are orthogonal to the problem you actually want to solve. And, as we all know, mixing continuations into an existing imperative language just gives continuations a bad name, which is precisely why you want a DSL. :)
- marvy 9y agoThank you for writing this. I wanted to say something like this yesterday, but couldn't find the words and decided to wait for today to try. But I would have never put it this well even if I spent a year.