6 ms·
Reading through the Design Principles [1]: > Separate pure and impure code So IIUC, the effect system [2] means impurity is contagious. This seems reasonable
by tw25513397 6y ago
Reading through the Design Principles [1]:
> Separate pure and impure code
So IIUC, the effect system [2] means impurity is contagious. This seems reasonable to me, though I wonder what that means in practice. `Console.printLine` is impure [3], and presumably any debug logging would be too; the contagion might spread pretty far. I wonder if this is why seemingly pure functions like `Array.find` are flagged as impure [4].
> Principle of least surprise: ... and when there is no immediately obvious default, we should not have a default at all, but force the programmer to be explicit about his or her intention.
I like that they called this part out. I'd wager most code really doesn't have sane defaults, just the defaults that made sense to the developer at the time.
> Local type inference
I find that in languages with type signatures (without inference), folks lean on the type to convey information, and in dynamic languages like Clojure, folks lean on good naming. Based on my not-much experience with type inference, the code ends up with neither. Sure the compiler can figure out what it is, but the humans not so much.
> Uniform function call syntax: ... the function call length(xs) can also be written as xs.length()
I wonder what their motivation was for this; my guess is to appeal to both FP and OO devs. IMO, having multiple ways of writing the same thing is likely to lead to unnecessary style wars.
> Private by default: ... declarations are hidden by default (i.e. private) and cannot be accessed from outside of their namespace
I like this a lot, though I foresee running into issues with unit testing, and thereby arguments over at what level things should be tested.
> Bugs are not recoverable errors: ... For recoverable errors, we should enforce that they are checked and handled. For program bugs, we should terminate execution as quickly as possible
This seems reasonable to me, but I'm curious what counts as a "program bug", or how to know that some error is recoverable.
> No null value
Meh. I've think Option is just null with extra steps. NPEs arise because of method invocation, e.g., `x.foo()` while `x` is null. In FP languages like Clojure, NPEs don't really happen since `x` is just a value being passed to a function. With nil-punning and reasonable behavior of core functions (e.g., `(get m k)` yields nil when `m` is nil), an unexpected nil is really a type error.
> No dead or unreachable code / No unused variables
Perhaps it's from my REPL-driven, exploratory style of development, but I think having to constantly comment out code I'm ambivalent about just to get it to compile would be a bit annoying. I'd think something like this should be a compile option, but I think that runs afoul of their "One Language"/"no flags" principle.
> No variadic (varargs) functions
Having worked with enough Clojure, and seen enough bugs when using `apply` on vararg fns, I think this is a good choice. IIUC, their approach would replace, e.g., `(+ x y z ...)` with `(sum [x y z ...])`.
> No binary or octal literals: ... It is our understanding that these features are rarely used in practice.
Until you need to do some bit-twiddling; maybe they still have hex. I wonder what they considered the downside of including it.
[1] https://flix.dev/principles/ https://flix.dev/principles/
[2] https://flix.dev/innovations/ https://flix.dev/innovations/
[3] https://api.flix.dev/Console https://api.flix.dev/Console
[4] https://api.flix.dev/Array https://api.flix.dev/Array
- herbstein 6y agoYou've written a lot, and I can't respond to everything. I'd just like to point out that the Array type is backed by proper JVM arrays. Operations on those are inherently impure. For a better representation of the effect system on a collection I'd suggest looking at the List type instead. Source: i worked a bit with the language during Spring.
- tw25513397 6y agoIt just struck me as odd for reads like `find` (which itself requires a pure fn arg). Is that because given the same reference, the function could yield different outputs? Or because it could be mutated concurrently? Would that imply every function that takes a mutable data structure will be impure? Edit: I just noticed that `List.toArray` -- which just returns a new array, so no concern over references or mutation -- is also marked as impure. This seemed wrong to me, but then I noticed that even `Array.new()` is marked impure. To my mind, a function that allocates a new mutable collection is itself not inherently impure.
- lmm 6y ago> Would that imply every function that takes a mutable data structure will be impure? That always has to be true, no? Reading from a mutable datastructure is impure in the same way that reading from standard input is. > Edit: I just noticed that `List.toArray` -- which just returns a new array, so no concern over references or mutation -- is also marked as impure. This seemed wrong to me, but then I noticed that even `Array.new()` is marked impure. To my mind, a function that allocates a new mutable collection is itself not inherently impure. Two different arrays with the same members are not generally equivalent. E.g. (x.toArray, x.toArray) is semantically something very different from {val y = x.toArray; (y, y)}.
- tw25513397 6y ago> That always has to be true, no? Reading from a mutable datastructure is impure in the same way that reading from standard input is. If the function internally reads from stdin, I'd agree. But if a fn takes an input stream as an arg, and if given input streams that yield the same bytes the fn always yields the same result, then why consider it an impure fn? The input stream is just a fancy data structure for bytes. > Two different arrays with the same members are not generally equivalent. Derp, of course! And though I guess it would be possible to have the `Mut*` collections use value equality instead of reference equality, that'd probably conflict with the performance goals of the mutable variant.