Interesting. there are some parts i like a lot here, but two things that I really dislike syntax wise. One is the lean towards a chainable syntax - this has proven to a big footgun for many devs in both java streams and typescript, making it very easy to go from O(n) to O(2n). The other part i really dislike is the first argument principle noted. If i myself define `string_and_reverse` and I can call it both through `string_and_reverse(42)` and `42.string_and_reverse()` i could definitely see this leading to some very funky looking chaining.
Perhaps it's just one point from me - not liking chaining :D
Is it just me that doesnt like automatically returning the last statement in functions? It makes it hard to see where a function returns, and I dont see how you would do a guard clause at the start of a function without having the entire rest of the function in an else block
In most functional languages however you can view the end of any statement/expression as a return/assign which makes it very easy and trivial to assign anything to variables, or split anything into function calls.
It does make me think that the usual types of guards might typically happen higher up (handled by the caller) or hidden with safe / monadic type operators that simply pass through rather than bailing out, so to speak.
I remember really bumping up against this learning OCaml in college after having experienced oodles of imperative programming.
I understand the sort of philosophy and ergonomics of not having an early return, but it really does hurt certain kinds of code that otherwise would be more readable
I think it is much more obvious than being able to return from anywhere in a function. If the last expression is a match, I know every match body must return the same type. if the last is a (cond ...) I know ever cond branch must return a value. I vastly prefer that.
Perhaps it's just one point from me - not liking chaining :D
Strictly speaking I assume everyone knows O(n) = O(2n) =O(kn) for k in R.
But I see your point. I assume any decent compiler would merge the loops though
In most functional languages however you can view the end of any statement/expression as a return/assign which makes it very easy and trivial to assign anything to variables, or split anything into function calls.
https://github.com/kablorp/blorp/blob/main/benchmarks/blorp/...
Then again, there's really not too many examples of early return guards, but I did manage to find one where the body is stuffed in an `else`:
https://github.com/kablorp/blorp/blob/main/benchmarks/blorp/...
It does make me think that the usual types of guards might typically happen higher up (handled by the caller) or hidden with safe / monadic type operators that simply pass through rather than bailing out, so to speak.
I understand the sort of philosophy and ergonomics of not having an early return, but it really does hurt certain kinds of code that otherwise would be more readable