Comment by jorkadeen
3 days ago
Flix supports type classes (called "traits") with higher-kinded types (HKTs) and with associated types and associated effects. A Flix trait can provide a default implementation of a function, but specific trait instances can override that implementation. However, Flix has no inheritance. The upshot is that traits are a compile-time construct that is fully eliminated through monomorphization. Consequently, traits incur no runtime overhead. Even better, the Flix inliner can "see through" traits, hence aggressive closure elimination is often possible. For example, typical usage of higher-order functions or pipelining is reduced to plain loops at the bytecode level without any closure allocation or indirection.
Flix does not yet have macros-- and we are afraid to add them due to their real (or perceived) (ab)use in other programming languages.
We are actively looking for library authors and if you are interested, you are more than welcome to stop by our Gitter channel.
> The upshot is that traits are a compile-time construct that is fully eliminated through monomorphization.
So, apparently, I can't re-implement distage for Flix.
I don't mind a little bit of overhead in exchange for a massive productivity boost. I don't even need full nominal inheritance, just literally one level of interface inheritance with dynamic dispatching :(
> their real (or perceived) (ab)use in other programming languages.
Without macros I can't re-implement things like logstage (effortless structured logging extracting context from AST) and izumi-reflect (compile-time refleciton with tiny runtime scala typer simulator).
The reality is that careless programmers will do bad things with any tool they happen to pick up. Using that as an excuse to reduce the power of a tool is poor form.
Another way of putting it is to point out that removing goto from a language isn't going to reduce the occurrence of spaghetti code. The average skill and care of the developers who happen to be using that language is what does that.
Not sure I agree. A simple example: If your language has null as a subtype of every type then you will have null ptr exceptions everywhere. If your language does not have a null value then you won't. The situation is not as clear cut as you suggest.
Yes, you can write spaghetti code in any language. But a good language design can help (a) reduce errors and (b) nudge the developer towards writing better code.
7 replies →
> Flix does not yet have macros-- and we are afraid to add them due to their real (or perceived) (ab)use in other programming languages.
I think the abuse is not that much of a problem. It's rather that it makes it much much harder to change the language later on because it will break macros (like it did between Scala 2 and 3, causing many people to be stuck on Scala 2 due to libraries using macros heavily).
If I might add a suggestion: add type providers to the language (like in F#). It solves a lot of the problems that macros are often used for, such as generating code from SQL DDLs, API specs, etc. (or vice versa).
Sorry to hijack, but since you are involved, can you explain why tail call optimization would incur a run time perf penalty, as the docs mention? I would expect tail call optimization to be a job for the compiler, not for the runtime.
We have to emulate tail calls using trampolines. This means that in some cases we have to represent stack frames as objects on the heap. Fortunately, in the common case where a recursive function simply calls itself in tail position, we can rewrite the call to a bytecode level loop and there is no overhead.
Thanks for explaining that term. That sounds really bad indeed. Maybe this is way too technical, but representing them as stack pointers was unfeasible?
1 reply →
TCO (tail call optimization) is often confused with TCE (tail call elimination), the latter is a runtime guarantee whereas the former is a compiler's best effort attempt to statically optimize tail calls.
Thanks! So you are implying that `TCO :: Maybe TCE`?
I am trying to think of a situation where a functional language compiler does not have enough information at compile time, especially when effects are witnessed by types.
1 reply →