For those that don't know its also built upon OTP, the erlang vm that makes concurrency and queues a trivial problem in my opinion.
Absolutely wonderful ecosystem.
I've been wanting to make Gleam my primary language, but I fear LLMs have frozen programming language advancement and adoption for anything past 2021.
But I am hopeful that Gleam has slid just under the closing door and LLMs will get up to speed on it fast.
Positive:
- It can be pretty performant if you do it right. For example, with some thought I got many days down to double digit microseconds. That said, you do need to be careful how you write it and many patterns that work well in other languages fall flat in Gleam.
- The language server is incredibly good. It autoformats, autocompletes even with functions from not-yet-imported-but-known-to-the-compiler packages, shows hints with regarding to code style and can autofix many of these, autofills missing patterns in pattern matches, automatically imports new packages when you start using them and much much more. It has definitely redefined my view of what an LSP can do for a language.
- The language is generally a joy to work with. The core team has put a lot of effort into devex and it shows. The pipe operator is nice as always, the type system is no haskell but is expressive enough, and in general it has a lot of well-thought out interactions that you only notice after using it for a while.
Negative:
- The autoformatter can be a bit overly aggressive in rewriting (for example) a single line function call with many arguments to a function call with each argument on a different line. I get that not using "too much" horizontal space is important, but using up all my vertical space instead is not always better.
- The language (on purpose) focuses a lot on simplicity over terseness, but sometimes it gets a little bit much. Having to type `list.map` instead of `map` or `dict.Dict` instead `Dict` a hundred times does add up over the course of a few weeks, and does not really add a lot of extra readability. OTOH, I have also seen people who really really like this part of Gleam so YMMV.
- Sometimes the libraries are a bit lacking. There are no matrix libraries as far as I could find. One memoisation library had a mid-AoC update to fix it after the v1.0 release had broken it but nobody noticed for months. The maintainer did push out a fix within a day of realizing it was broken though. The ones that exist and are maintained are great though.
To me it felt less elegant than Scheme (GNU Guile) which I usually use (with nice parallelism if I want to, pipelines, and also pattern matching), and, aside from syntax, conceptually perhaps less elegant than Erlang. On the other hand it has static typing.
I also tried OCaml this year, but there are issues in the ecosystem making a truly reproducible environment/setup, because opam doesn't produce proper lock files (only version numbers) and it seemed silly to not be able to even include another file, without reaching for dune, or having to specify every single file/module on command line for the OCaml compiler. So I was left unsatisfied, even though the language is elegant and I like its ML-ness. I wish there was a large ecosystem around SML, but oh well ...
Might be I should take another look at Erlang soon, or just finally get started with Haskell. Erlang using rebar3 should have proper lock files, has pattern matching, and if I remember correctly no such limitations for calling functions recursively. No longer sure how or whether Erlang did inner functions though.
array
.slice(0, 10)
.filter(s => s[0].toLowerCase() < 'm') // a<->l
.map(s => s.toUpperCase());
It seems like it should be a common feature to be able to view between each array operation in a debugger without having to augment the code with `echo`The out of bounds handling didn't seem all that good to me. Sure you can filter out undefined. You could also just make a function that returns an empty array if out of bounds, or array of 1 element if not.
// JS
function getElemFromGrid(grid, x, y) {
return (x < 0 || x >= grid.width ||
y < 0 || y >= grid.height)
? []
: [grid.elems[y][x]]
}
...
neighbors = [
...getElemFromGrid(grid, x + 1, y + 0),
...getElemFromGrid(grid, x + 1, y + 1),
...getElemFromGrid(grid, x + 0, y + 1),
...getElemFromGrid(grid, x - 1, y + 1),
...getElemFromGrid(grid, x - 1, y + 0),
...getElemFromGrid(grid, x - 1, y - 1),
...getElemFromGrid(grid, x + 0, y - 1),
...getElemFromGrid(grid, x + 1, y - 1),
]
I also find grids made of 2 dimensional array to be code small. An array of arrays is NOT A GRID as there is nothing enforcing the inner arrays to be the same length as each other. Also, in efficienct code it would be better to provide a 1 dimensional array and bounds. Now, out of bounds checks based on accessing outside the array won't work. You need to check actual bounds. Again giving preference using a helper list.map(fn(line) { line |> calculate_instruction })
Could be written list.map(calculate_instruction)
?And I wonder if Gleam + Lustre could become the new Elm.
But I think two things really hold it back:
* it's verbose.
* they compose awkwardly.
Neither of these are showstoppers, but I think fixing these problems--maybe with something like syntax-level support--could really lead to a beautiful programming language.
> But you cannot do [first, ..middle, last].
I don't think you're supposed to do that! It's probably expensive!
By the developers own action of adding generics ultimately the golang team admits they were wrong or that generics are better. If gleam gets popular I think much of the same will occur.
There’s simply too much repeated code without generics. I tried writing a parser combinator in gleam and it wasn’t pretty.