1. 61
  1. 14

    Gleam is my favorite language that I haven’t actually tried yet (but I will as soon as I get home from my traveling).

    I read the language tour on my phone one evening, and the next evening I was reading and understanding source code. That’s how approachable the language is!

    use is interesting because it’s a fairly complex feature, but it opens up so many options (as shown in the link). At first I was skeptical, but I think I agree. It’s worth the added complexity.

    To give two examples of where Gleam has made (imo) interesting design decisions to keep the language simple:

    • There is no Option[T], only Result[T, E]. If you don’t want an error, just use Result[T, Nil]. Is it more typing? Sure, but now you only have one type instead of two.
    • A type (think struct) can have multiple constructors, each with their own fields. This means they effectively double as enums. Have a look at the docs, they explain it better than I can.

    Anyway, congrats Louis! Very inspiring work :-)

    1. 4

      A type (think struct) can have multiple constructors, each with their own fields. This means they effectively double as enums. Have a look at the docs, they explain it better than I can.

      This sounds like it’s taken straight from Haskell. (Not a criticism, just background.)

      1. 4

        One could do worse things then take inspiration from Haskell!

        I did not know this. :-)

        1. 4

          It’s not specifically inspired by Haskell, it was mostly inspired by Erlang. I didn’t realise that Haskell had the same feature but now I read the documentation it seems very similar. Cool stuff!

          1. 3

            I mean, Gleam does belong to the ML family of languages IMO, so we may as well say the feature is inspired by Standard ML! /s

            1. 1

              In what sense does it relate to ml?

              1. 7

                Some examples of “ML-like” features include…

                • Sum types as a primary data modeling tool, in some cases even displacing records for small-ish data structures

                • First-class functions and some use of recursion, often used to constrain and thereby elucidate control flow. This is sometimes in lieu of imperative-/procedural-style constructs such as…

                  • If/else statements (not if/else expressions)
                  • Switch/case statements (not if/else expressions)
                  • Goto, which has basically been a strawman against this style of programming for the past decade or so
                  • Defer, which though it allows code to be written out-of-order, still introduces a discrete procedural “step” to computation

                  In languages like Javascript and Gleam, this extends to the use of a syntactic construct you may know as a callback function.

                • Type inference (usually Damas–Hindley–Milner type inference)

                • Other idioms that, like the above, help to obviate and/or discourage the use of global state in implementations as they scale

                There are plenty of ML-like languages for different runtimes, including a few that are used for systems programming.† Languages often described as “ML-like” include…

                • Scala, ‘an ML for the JVM
                • F#, ‘an ML for the CLR
                • Elm, which also takes some inspiration from Haskell while not going quite as far with the generics, apparently for sake of error message readability
                • Facebook’s Reason, which is sometimes even called ReasonML for clarity
                • Rust, one of the only systems programming languages to have this distinction. Check for the features above if you don’t believe me!

                Haskell is explicitly inspired by ML, but is often considered its own category due to the radical departures it makes in the directions of a) purely functional programming and b) requiring (in most cases) the use of monads to represent effects in the type system.

                My educated guess: This is largely because the core syntax and feature-set is relatively well understood at this point. As such syntactic sugar is rarely necessary in order to express intent directly in efficient code. This is unlike in “dynamic” languages such as Python, Ruby, and Elixir, which tend to make liberal use of metaprogramming in order to make the syntax more directly express intent. This can often make it unclear what is actually happening to make a given piece of code run.

                1. 3

                  I find it interesting that nothing on that list is inherent to functional languages. All these sweet goodies might as well exist in an imperative language, but outside of Rust, they don’t.

                  I’m still sad Go completely missed the boat on that one.

                  1. 1

                    Yup. Maybe someday we’ll have an approach in between those of Go and Rust; that’s some of what I’m looking to Gleam for, even if it’s not primarily a systems programming language.† In the meantime, we have the sometimes-insightful, sometimes-regressive minimalism of Go; and the sometimes-insightful, sometimes-overwhelming maximalism of Rust.

                    † It is my broad understanding that the BEAM VM—on which I expect most* Gleam code will run—helps concurrent applications scale by denying granular control of threaded execution. This can be thought of as vaguely similar to the Go runtime’s decision to have a blessed implementation of cooperative multitasking, namely goroutines. In contrast, the Erlang ecosystem benefits from having a blessed provider and model (respectively) for all concurrent computation, thanks to the OTP supervision tree combined with the actor model of concurrent computation. It takes power away from the developer, but to the benefit of the system at large. Boy, is it ever exciting that we might actually have a statically-typed language built atop that excellent multitasking infrastructure!

                    1. 1

                      From my PoV Go and Rust are incomparable since Go is a GC’d language and Rust is a non-GC’d language. So on this basis Gleam, too, can never compete with Rust but is for sure a strong contender in the space Go plays in.

                      1. 1

                        If all that matters is the engine that runs your code, the sure. If a project is performance-sensitive, then its options for reasonable programming language are constrained anyway IMO. When I compare these languages, I have their developer experience in mind. At least, relative to how much performance they leave on the table.

                    2. 1

                      It honestly depends what one even means by “functional language” lots of ML and ML-like things exist which are not particularly functional including possibly: SML, OCaml, Swift, Scala, Kotlin, Haxe

                      1. 2

                        What’s not-functional about SML, OCaml, and Scala? Are you perhaps comparing them to the purely functional Haskell?

                        1. 1

                          What’s functional about them? Every language I listed is equally functional and not-functional depending how you use it. They’re all ML variants after all.

                    3. 2

                      Facebook’s Reason, which is sometimes even called ReasonML for clarity

                      Credit where credit is due: Reason is a syntax extension for OCaml. It’s not a whole cloth creation by Facebook.

                    4. 4

                      I think it is an ML language in every way, although we moved away from the traditional ML syntax in the end.

            2. 10

              Oh, this is monadic do-syntax! It’s always awesome to see a more conventional language adopt generalized monads.

              (For the uninitiated, the basic premise of monads is “a thing that is then-able”, and it looks like Gleam’s flavor is “a function that takes a callback as its final argument”.)

              In JavaScript, the equivalent is async/await, which is a monadic do-syntax that’s hardcoded to the Promise monad. It’s awesome that Gleam has chosen to provide a general do-syntax here rather than taking the common route of only providing hard-coded support for specific common monads.

              1. 6

                Do-notation! Wonderful

                1. 3

                  My knee jerk reaction is to lament the loss of indentation to visually represent scope.

                  But deep indentation is also a readability problem. For example, Python’s solution to have special case syntax to initialise immediately adjacent contexts in one long statement. In contrast, perhaps Gleam is right and a variable’s lifetime rather than indentation is the way here!

                  1. 2

                    Huh. Do-notation but adapted to callbacks. Fascinating. Loved the examples, too. Excited to see what this opens up!

                    1. 1

                      I think the main problem is if you want to stop useing something earlier than the end of the scope. For example I want to use a database connection to read some data then release connection and process the data.

                      I guess then you go back to explicit callbacks which isn’t a big problem.

                      1. 2

                        You can also introduce a new scope using { ... }, both would work.

                        1. 1

                          Which re-add an indentation level :/

                          1. 1

                            One level is OK, the intent is to avoid repeated intendation that grows across the page.