1. 2

    Are there plans for a first-class mix compiler? I see tooling commits that have been sitting at the top of the changelog for a while. I’d love to use gleam inside my elixir umbrella apps!

    1. 3

      The gleam compile-package API is perfect for use by mix etc, and it has been out for some time! Mostly we need someone to make a mix plugin that uses it. I’m focusing on the Gleam tooling and I’m not an Elixir user at present so I won’t be doing it myself any time soon.

    1. 2

      Conditional compilation looks super cool. I wonder how messy it gets as the number of supported targets increases. PureScript has had to have had the entire package-sets forked to support Purerl (Erlang). It seems they keep the JS FFI code to mirror its implementation in Erlang, but a lot of libraries might be easier to maintain with these conditionals.

      1. 4

        It’s already a bit messy in the standard library, but I’m hoping that most libraries won’t need to use conditional compilation at all. There’s no plans for other targets and there’s only to be one package repository so that’ll help.

        If it becomes an issue we’ll revisit this before v1.

      1. 1

        is the integer type still a big integer in the javascript version?

        1. 1

          No, it uses the JavaScript integer type by adding bitwise hints to their number literals.

        1. 2

          It’s exciting to see the progress on Gleam! How do you plan to handle the heavily object-oriented nature of DOM code in general? Your examples use Reflect for assignment, but what if I want to call document.addEventListener or mutationObserver.takeRecords()? Or use the built-in Map type?

          1. 1

            I expect we will have quite thick wrappers around DOM APIs that expose a limited subset of what is avalible that offers a stateful functional interface over the DOM’s OOP API. Similar libraries in PureScript and ReScript would be a good place to look for ideas.

            The Map type can be wrapped fairly cleanly, it has quite a small and basic API.

            1. 9

              In my experience, thick wrappers around platform APIs with huge surface areas like the DOM not effective in the long run unless they allow immediate escape hatches to the underlying platform. With strict segmentation or difficult interop, experts in the underlying APIs need to re-learn the facade abstractions you produce, and online learning resources need to be translated in the mind of the developer before they can be applied. Thick wrappers need maintenance to keep up with the platform, which is taxing on an emerging community. That isn’t to say wrappers are pointless, but they are a (in my opinion) very low local maximum unless there’s an easy escape hatch.

              My case study here is React. React is a thick library over UI tree manipulation and state lifecycle. On the web, ReactDOM does great because users who want more can trivially access the underlying platform APIs: getting a DOM node and calling methods directly on it is a one line affair. But on mobile, React Native is extremely isolated from the platform. To call an unwrapped (or poorly wrapped) platform API requires writing platform-native code, serializing messages over a bridge between language runtimes etc. I rewrote Notion’s Android mobile app to remove React Native. I am not planning to rewrite Notion’s web app to remove React. Of course Gleam is not going to be so isolated from the platform — just using it as an extreme example.

              Here’s how ReScript low-level interop looks directly against DOM objects:

              // The type of document is just some random type 'a
              // that we won't bother to specify
              @val external document: 'a = "document"
              
              // call a method
              document["addEventListener"]("mouseup", _event => {
                Js.log("clicked!")
              })
              
              // get a property
              let loc = document["location"]
              
              // set a property
              document["location"]["href"] = "rescript-lang.org"
              

              Does Gleam have a similar less-typed but more direct syntax for building the wrapper libraries?

              It seems that Purescript prefers to write an “externs” header like file, and have the wrapper actually implemented in JS. Looking at the Purescript wrapper for MutationObserver object’s takeRecords method. Here’s the signature

              foreign import takeRecords :: MutationObserver -> Effect (Array MutationRecord)
              

              And the implementation in the adjacent .js file:

              exports.takeRecords = function (mo) {
                return function () {
                  return mo.takeRecords();
                };
              };
              

              Between the two approaches, I much prefer ReScript.

              1. 1

                Both are possible in Gleam, you can do whatever you like using the FFI. Pick the approach that fits each use case.

              2. 1

                One of the “newer” Browser API libraries I’ve worked with is https://erratique.ch/software/brr. It’s been a real pleasure to work with in js of oCaml, and the API seems to be very understandable. If you haven’t seen it yet it’s worth a look.

            1. 3

              Sweet! Any plans for a non-Erlang backend?

              I love Erlang, would like Gleam to run in more places. Wasm?

              1. 3

                Thanks!

                I would like to target wasm in future but no work has been done here. We are currently working on a JavaScript backend.

                1. 2

                  This has more to do with alternative backends for the BEAM bytecode rather than Gleam itself.

                  With regards to WASM, the best bet could be Lumen

                  1. 2

                    Lumen is very cool but Gleam compiling to wasm directly should be able to out-perform Lumen compiled code as it can break Erlang compatibility in that environment and perform much greater optimisations using the type information. I’m interested in making a wasm backend, but we may never get there as the current backends are the focus.

                1. 7

                  I would love to use Nomad but the agressive feature gating is a problem for me. I have to go through the sales pipeline and commit to an enterprise licence to use basic k8s features such as resource quotas, and audit logging.

                  1. 1

                    Which of the following is more painful to you:

                    • the price of the extra feature?
                    • not knowing what the price is?
                    • having to go through a sales pipeline?
                    1. 1

                      It’s hard to split them out, they’re part of the same thing. Probably the sales pipeline is the worst bit.

                    2. 1

                      I’m talking out loud here: Is “feature gating” a common word choice for charging for extra features? When I hear feature gating, I think of https://en.wikipedia.org/wiki/Feature_toggle

                      Ah, I see, here is an example of “feature gating” in such a context: https://growthhackers.com/questions/ask-gh-feature-gating-work

                    1. 4

                      Love to see it. I use Elixir everyday at work, and am a big fan of static types, so in principle I’m the target audience. However, I’m reluctant to give up the Elixir ecosystem I love do much. E.g. I’m really excited LiveView, Livebook, Nx, etc.

                      What are the benefits / necessity of a whole new language as opposed to an improved dialyzer, or maybe a TypeScript style Elixir superset with inline type annotations?

                      1. 11

                        One issue is that existing Elixir code will be hard to adapt to a sound type system, more specifically in how pattern matching is used. For example, consider this common idiom:

                        {:ok, any} = my_function()
                        

                        (where my_function may return {:ok, any} or {:error, error} depending on whether the function succeeded)

                        Implicitly, this means “crash, via a badmatch error, if we didn’t get the expected result”. However this is basically incompatible with a sound type system as the left-hand side of the assignment has the type {:ok, T} and the function has the return type {:ok, T} | {:error, Error}.

                        Of course we could add some kind of annotation that says “I mismatched the types on purpose”, but then we’d have to sprinkle these all over existing code.

                        This is also the reason why Dialyzer is based on success typing rather than more “traditional” type checking. A consequence of this is that Dialyzer, by design, doesn’t catch all potential type errors; as long as one code path can be shown to be successful Dialyzer is happy, which reflects how Erlang / Elixir code is written.

                        1. 5

                          Of course we could add some kind of annotation that says “I mismatched the types on purpose”, but then we’d have to sprinkle these all over existing code.

                          This is what Gleam does. Pattern matching is to be total unless the assert keyword is used instead of let.

                          assert Ok(result) = do_something()
                          

                          It’s considered best practice to use assert only in tests and in prototypes

                          1. 1

                            What do you do when the use case is “no, really, I don’t care, have the supervisor retry because I can’t be bothered to handle the error and selectively reconcile all of this state I’ve built up, I’d rather just refetch it”?

                            1. 1

                              Maybe we need another keyword:

                              assume Ok(result) = do_something()
                              
                              1. 1

                                That is what assert is for.

                              2. 1

                                That’s what assert is. If the pattern doesn’t match then it crashes the process.

                                1. 1

                                  So why not use it in production?

                                  1. 2

                                    You can for sure. I was a bit too simple there. I should have said “It is best to only use assert with expected non-exceptional errors in prototypes`. There’s place for Erlang style supervision in Gleam in production.

                            2. 3

                              Great, succinct explanation!

                              1. 2

                                This is an interesting example. I’m still not sure I understand how it’s “basically incompatible”, though. Is it not possible to annotate the function with the possibility that it raises the MatchError? It feels kind of like Java’s unchecked exceptions a bit. Java doesn’t have the greatest type system, but it has a type system. I would think you could kind of have a type system here that works with Elixir’s semantics by bubbling certain kinds of errors.

                                Are you assuming Hindley Milner type inference or something? Like, what if the system were rust-style and required type specifications at the function level. This is how Elixir developers tend to operate already, anyway, with dialyzer.

                                1. 1

                                  I don’t see how that’s a problem offhand. I’m not sure how gleam does it, but you can show that the pattern accommodates a subtype of the union and fail when it doesn’t match the :ok.

                                  1. 4

                                    The problem is the distinction between failing (type checking) and crashing (at runtime). The erlang pattern described here is designed to crash if it encounters an error, which would require that type checking passes. But type checking would never pass since my_function() has other return cases and the pattern match is (intentionally) not exhaustive.

                                    1. 1

                                      Ah, exhaustive pattern matching makes more sense. But also feels a little odd in Erlang. I’ll have to play with Gleam some and get an understanding of how it works out.

                                2. 4

                                  One thing is that TypeScript is currently bursting at the seams as developers aspirationally use it as a pure functional statically-typed dependently-typed language. The TypeScript developers are bound by their promise not to change JavaScript semantics, even in seemingly minor ways (and I understand why this is so), but it really holds back TS from becoming what many users hope for it to be. There’s clearly demand for something more, and eventually a language like PureScript / Grain / etc will carve out a sizable niche.

                                  So, I think starting over from scratch with a new language can be advantageous, as long as you have sufficient interoperability with the existing ecosystem.

                                  1. 2

                                    I won’t go too much into Dialyzer as I’ve never found it reliable or fast enough to be useful in development, so I don’t think I’m in a great place to make comparisons. For me a type system is a writing assistant tool first and foremost, so developer UX is the name of the game.

                                    I think the TypeScript question is a really good one! There’s a few aspects to this.

                                    Gradual typing (TypeScript style) offers different guarentees to the HM typing of Gleam. Gleam’s type system is sound by default, while with gradual typing you opt-in to safety by providing annotations which the checker can then verify. In practice this ends up being quite a different developer experience, the gradual typer requires more programmer input and the will to resist temptation not to leave sections of the codebase untyped. The benefit here is that it is easier to apply gradual types to an already existing codebase, but that’s not any advantage to me- I want the fresh developer experience that is more to my tastes and easier for me to work with.

                                    Another aspect is just that it’s incredibly hard to do gradual typing well. TypeScript is a marvel, but I can think of many similar projects that have failed. In the BEAM world alone I can think of 4 attempts to add a type checker to the existing Elixir or Erlang languages, and all have failed. Two of these projects were from Facebook and from the Elixir core team, so it’s not like they were short on expertise either.

                                    Lastly, a new language is an oppotunity to try and improve on Elixir and Erlang. There’s lots of little things in Gleam that I personally am very fond of which are not possible in them.

                                    One silly small example is that we don’t need a special .() to call an anonymous function like Elixir does.

                                    let f = fn() { 1 }
                                    f()
                                    

                                    And we can pipe into any position

                                    1
                                    |> first_position(2)
                                    |> second_position(1, _)
                                    |> curried_last_position
                                    

                                    And we have type safe labelled arguments, without any runtime cost. No keyword lists here

                                    replace(each: ",", with: " ", in: "A,B,C")
                                    

                                    Thanks for the questions

                                    edit: Oh! And RE the existing ecosystem, you can use Gleam and Elixir or Erlang together! That’s certainly something Gleam has been built around.

                                    1. 1

                                      Two of these projects were from Facebook and from the Elixir core team, so it’s not like they were short on expertise either.

                                      Oh, wow, I don’t think I’ve heard of these! Do you have any more info? And why was Facebook writing a typechecker for Elixir? Are you talking about Flow?

                                      1. 1

                                        Facebook were writing a type checker for Erlang for use in WhatsApp. It’s not flow, but it is inspired by it. I’m afraid I don’t think much info is public about it.

                                  1. 3

                                    As someone who hasn’t tried any of the Beam languages; what’s the package ecosystem like? Can Gleam consume elixir/erlang packages?

                                    1. 6

                                      Yes, there should be no problem. However there may be some additional work to be done in Gleam to provide typing for such functions.

                                      Here you have docs for that. It should be also perfectly possible to call Gleam functions from other BEAM languages as well.

                                      1. 2

                                        Thanks to the great work of Elixir and Erlang there’s a good package ecosystem which can be used by all the languages on the VM. The website has details https://hex.pm/

                                      1. 2

                                        Sounds and looks very interesting. Can’t wrap my mind around the way message passing can be done, though.

                                        1. 2

                                          We use a channels abstraction to type messages, similar to Go or Rust. They can be combined to make type safe selective receives.

                                          See the OTP library for details -> https://github.com/gleam-lang/otp

                                          1. 1

                                            IDK how Caramel does it, but one way to do it is to type functions on the messages it can receive. This type then gets “inherited” by processes that are spawned with that function. This means all match clauses inside the function’s receive / all messages sent to the process must match the function’s “receive type”

                                            1. 2

                                              We originally tried this but found it was too limiting. It was impossible to implement things like supervisors and gen:call, so at best you could write a thin typed layer on top of untyped Erlang code.

                                              Gleam OTP by contrast is a small ~200 line Erlang core, and the rest is type safe Gleam.

                                          1. 6

                                            Congrats on moving to full-time Gleam, Louis! I heard your episode with Inference and understand how difficult it is to have to switch between open source and paid work, especially with such a demanding project as Gleam and your work in Elixir.

                                            I’m hoping others start seeing the value of Gleam more and that you don’t have to worry about switching back and forth.

                                            1. 4

                                              Do you mind sharing the name of the episode or a link to it? I don’t seem to be able to find it…

                                                1. 1

                                                  Thank you!

                                              1. 1

                                                Thank you! I hope so too!

                                                I’m going to try and only pick up short term contracts in future, as to be less disruptive to Gleam development.

                                              1. 2

                                                Gleam aside this is a very clear introduction to phantom types, thanks!

                                                1. 2

                                                  In Gleam, could you constrain the Currency phantom type to require a formatting interface?

                                                  1. 2

                                                    Gleam doesn’t have type classes or other forms of implicit interfaces, so no. You could however explicitly pass in an implentation of the format function for the given type, which is what type classes desugar to.

                                                  1. 10

                                                    oh my gosh, the new errors are beautiful! my favorite:

                                                    error: Syntax error
                                                       ┌─ /Users/a/parser_test/src/parser_test.gleam:13:38
                                                       │
                                                    13 │ pub external fn a(name: String, Int, ,) -> Bool =
                                                       │                                      ^ This is an extra delimiter.
                                                    
                                                    Hint: Try removing it?
                                                    
                                                    1. 5

                                                      Thank you, Greg did a fantastic job there!

                                                    1. 3

                                                      Best price per performance is a very important server metric. Does this telegraph a move into the server space?

                                                      1. 8

                                                        ARM on AWS is already extremely competitive and for many workloads is more cost efficient.

                                                        1. 1

                                                          Not everyone has AWS’ scale to make their own chips. Seems like the little guys might consider buying chips from Apple.

                                                          1. 2

                                                            I like the idea, but I don’t see Apple earnestly moving into a space unless they really find it exciting. And they just don’t love the backend world; the company treats it like a chore.

                                                            1. 1

                                                              Not everyone has AWS’ scale to make their own chips. Seems like the little guys might consider buying chips from Apple.

                                                              Given how much Apple is positioning first-party silicon as a differentiator, it’s highly unlikely that they’d sell chips to anyone else. Even if they did, there’s a lot of work to do to make this into a good datacenter chip. Phone, laptop, and tablet SoCs are a lot more similar to each other than any of them are to server SoCs.

                                                              1. 1

                                                                AWS chips use stock Arm cores, not any custom design. The only benefit of custom SoC for them is that they can integrate their “Nitro” peripherals (NIC/storage/security) onto the SoC directly.

                                                                The little guys can buy Ampere (or Nuvia when that happens?) and enjoy better performance (I’m pretty sure Ampere Altra will clock higher than Graviton2 and it has more cores).

                                                                Though of course it would be a dream if Apple did an ARM Xserve, with full ACPI standard support and everything :)

                                                                1. 1

                                                                  AWS are not making their own chips, they use standard off the shelf ARM processors.

                                                              2. 2

                                                                Not a chance. Apple tolerates professional users who aren’t in media production, but they’re a consumer product company.

                                                                1. 2

                                                                  Maybe for their own datacenters, but I don’t really see them getting back into selling them externally again.
                                                                  They kicked Xserve to the curb back in 2011 – I assume it just ended up not being worth it. Maybe one of: inability to differentiate in on a market segment that is typically only price sensitive (eg. server market is not really UI/UX driven), thinner margins, customers wanting long support lifetimes, longer product lifetimes to ensure capex… who knows?

                                                                  1. 9

                                                                    They kicked Xserve to the curb back in 2011 – I assume it just ended up not being worth it.

                                                                    The Xserve was built for a single customer: Pixar. Back in 2002, Steve Jobs was CEO of Pixar and Apple and, as Apple CEO, was telling the world that Apple made the fastest computer. At the same time, as Pixar CEO, he was buying huge numbers of Dell servers for his render farms. This was incredibly bad for Apple’s marketing. It made sense to create the Xserve so that Pixar could loudly tell everyone that they were buying Apple hardware for their render farms.

                                                                    Disney bought Pixar in 2006 and Jobs took a less active role. The last Xserves were released in 2009 and by then Apple was the iPhone company, no one cared if Pixar render farms used their hardware.

                                                                    1. 2

                                                                      I never made that connection, and this makes a ton of sense. Thanks for sharing!

                                                                1. 5

                                                                  pattern matching doesn’t work all that well

                                                                  Anybody know what the author means by this? I haven’t used Rust a whole lot but pattern matching seemed fine to me, other than having to add a few &s here and there to satisfy the compiler.

                                                                  1. 16

                                                                    In Rust, you can’t pattern match through Box<T> or Vec<T>. But you often need those indirection to implement recursive data types.

                                                                    That means that, practically, you are restricted to one-layer pattern matching for recursive types, and have to split deep matches into a series of nested shallow matches.

                                                                    1. 5

                                                                      There is a nightly feature (box_patterns) that lets you match on boxes.

                                                                      1. 6

                                                                        Sadly, that isn’t generalizable, so marching on nested String, Vec, etc. remains cumbersome.

                                                                        1. 1

                                                                          Could you not match on the slice? Or perhaps I’m misunderstanding

                                                                          1. 4

                                                                            Say if you match on a variant that contains a Vec, you can’t match on that directly - you have to pull it out, then call as_slice on it.

                                                                            1. 2

                                                                              Oh yes! My eyes skipped over the word “nested”. Thank you

                                                                            2. 2

                                                                              To Rust, Vec is just a regular struct {len, capacity, pointer}, so that’s what it’s pattern-matching on, not its elements.

                                                                              For values at the top level you can usually easily transform them like match vec.as_slice() {}, but if you want to match a nested value, there’s no room for that:

                                                                              match compound_value {
                                                                                 Foo(Bar([first, ..])) => …
                                                                              }
                                                                              

                                                                              Then in Foo(Bar(Vec)) Rust doesn’t know how to match on Vec‘s content. There’s no language feature to explain that [first, ..] should compile to first = vec.remove(0) or that it should perform vec.as_slice() before matching.

                                                                              1. 1

                                                                                I think match_default_bindings might do this.

                                                                                1. 2

                                                                                  match_default_bindings (match ergonomics RFC) is for now only a syntax sugar that makes patterns forgiving about missing ref or &, but the actual behavior stays the same, with the same fundamental limitations.

                                                                                  Specifically moving out of a Vec is far off, as it depends on DerefMove, which is at the stage of “hmm, maybe we should have something like that, but not sure how to pull that off”.

                                                                          2. 2

                                                                            I think they are now preferring match_default_bindings, but I could be wrong. This is definitely a pain for me as a language implementer. :(

                                                                        2. 7

                                                                          It’s discussed on the other post at https://blog.darklang.com/first-thoughts-on-rust-vs-ocaml/#pattern-matching.

                                                                          That section is just a summary of the last post, sorry for the confusion!

                                                                        1. 11

                                                                          Seems entirely fair: author doesn’t need the low-level control and performance that Rust offers, and prefers ease and flexibility that comes from having a GC in the language.

                                                                          1. 14

                                                                            I think Rust is a wonderful community, ecosystem, and tooling, wrapping a language that nicely solves a problem very few of us have.

                                                                            This is my feeling exactly. I think it is head and shoulders above the alternatives in the space it’s in, but I have never needed to work in that space, because for the problems I work on, the downsides of GC tends to be irrelevant.

                                                                            I am very glad it exists, because it prevents more new code from being written in C and C++. I just don’t have a use for it myself.

                                                                            1. 2

                                                                              And not just GC per se. I have written very little code in the last decade that would have benefitted from Rust’s ownership model (which to me is the language’s killer feature) so there would be no payoff from the added cognitive overhead.

                                                                              I’ve worked on low-level code bases earlier in my career that would have been great fits for Rust had it existed (lots of parallelism and mutable shared state that needed careful lock management and disciplined adherence to order-of-operations rules) so I’m well aware of the pain points it addresses, but it appears to bring very little of use to the table for a lot of software.

                                                                              The right tool for the job!

                                                                              1. 8

                                                                                And not just GC per se. I have written very little code in the last decade that would have benefitted from Rust’s ownership model (which to me is the language’s killer feature) so there would be no payoff from the added cognitive overhead.

                                                                                Hm, interesting, because I see that very differently: I write a lot of code where “handing from one component to another” is a fundamental operation that Rust makes strict. Think “write this to a channel/database/etc., invalidating usage on my side”.

                                                                                I could live without borrowed references and with pervasive and more ergonomic smart pointers much more.

                                                                                1. 6

                                                                                  I suspect this is a matter of personal taste. I’m working on a high level project now and I’m not finding Rust’s ownership any more hassle now that I’m comfortable with the language, and web applications ported from Go became less code + easier to work with.

                                                                                  It was however a real pain learning how to use Rust because of ownership.

                                                                                  1. 1

                                                                                    And not just GC per se. I have written very little code in the last decade that would have benefitted from Rust’s ownership model (which to me is the language’s killer feature)

                                                                                    Interesting; having not used Rust, I assumed that the ownership model existed primarily in order to support avoiding GC. Is there more to it than that? I guess it can also solve data race conditions when sharing mutable data across threads? (another problem I don’t have, because I never write concurrent code without immutable data structures!)

                                                                                    1. 3

                                                                                      Single ownership gives you automatic and deterministic resource cleanup as a side effect. You don’t need to remember to write defer f.close() or be limited to a single scope with f.open().

                                                                                      Another benefit is that you don’t have shared mutable state, but you don’t have to go all the way to purely immutable. Exclusive owners can mutate their data without causing side effects. This helps understanding what is going on in a program: if I pass an object to a function is it going to keep a copy or reference the original? Can I mutate that object afterwards? Always clear with ownership.

                                                                                      1. 3

                                                                                        Sure but there are other languages where you do not need to remember these things either or have shared mutable state. I think F# is a sweet spot because I can do ~90% immutable ~10% mutable code and it just works extremely well. The 10% mutability happens in a short context and I never give out mutable references. Having to deal with mutability or disposable things in a small amount of your code is doable and I do not need to fight with the compiler to get basic code to work (as opposed to Rust).

                                                                                        I pass an object to a function is it going to keep a copy or reference the original? Can I mutate that object afterwards?

                                                                                        These are sort of questions we do not need to ask with F# either.

                                                                                      2. 1

                                                                                        Rust used to have a GC, in its early days (@T), so it can’t be just that. I don’t know if there is an official answer to “why rust”. There is a section in the old FAQ about the garbage collector that tells a bit more about the other benefits of tracking ownership: https://prev.rust-lang.org/en-US/faq.html#is-rust-garbage-collected (got to scroll up a bit because the “try the new site” banner hides the start of the section).

                                                                                        Apart from the matter of concurrency, there’s also non-memory resources (like file handles), which get tracked like memory.

                                                                                1. 2

                                                                                  What is the motivation behind Gleam? Are there different design choices that you wanted to explore compared to Elixir?

                                                                                  1. 5

                                                                                    I believe the big one is a static type system, but there’s more on the Gleam website: https://gleam.run/

                                                                                    1. 3

                                                                                      Like Elixir it aims to bring a new style of programming to the Erlang VM.

                                                                                      Elixir polymorphism and metaprogramming inspired by Clojure, and Ruby. Gleam brings type safety and static analysis inspired by Elm, OCaml, and Rust.

                                                                                    1. 5

                                                                                      Not sure if I’m misunderstanding something, but sounds like you’re planning on re-implementing OTP in Gleam? Which would be impressive, but also sounds like users will not be able to make use of the awesomeness of Erlang OTP. Or will you be able to bridge the Gleam abstractions to Erlang’s OTP?

                                                                                      1. 1

                                                                                        We have reimplemented OTP in Gleam, yes.

                                                                                        I tried to explain in the article that it maintains full compatibility with Erlang’s OTP (in the “primary goals” section) so Gleam users can use Erlang OTP and Erlang users can use Gleam OTP transparently and without problems. Sorry if I didn’t make that clear!

                                                                                        1. 2

                                                                                          On re-reading, yes it is clear! I was probably just too surprised to fully take it in. Again — impressive!

                                                                                      1. 7

                                                                                        Gleam is my favorite new language in 2020. I hope it is taking off.

                                                                                        1. 3

                                                                                          Thank you!

                                                                                        1. 4

                                                                                          Looks really good. I like that the syntax is basically rust/ML, on the Beam runtime. I wonder if there’ll be a way to write reasonably self-contained programs with it (a bit like deno does for javascript), especially since the compiler is in rust?

                                                                                          1. 5

                                                                                            You still will need BEAM runtime. Doesn’t matter what is the language the compiler is written in, the output is what matters

                                                                                            1. 2

                                                                                              Maybe the beam runtime can be linked against a rust-compiled binary? Deno uses bindings to V8 to do the equivalent with javascript.

                                                                                              1. 2

                                                                                                I couldn’t say whats possible there, I’m not a C programmer and I’ve not looked into this. It would be a very cool feature though! Maybe one day

                                                                                                1. 2

                                                                                                  I have been meaning to see if Gleam will run on https://github.com/lumen/lumen a BEAM VM written in Rust that targets Wasm.

                                                                                                  1. 2

                                                                                                    I intend to investigate this future. I’ve had some quick chats with the Lumen devs and it sounds like it would work nicely.

                                                                                                    One of the main things I’m interested in is providing additional type information to Lumen so that they can enable type based optimsations. This would make Gleam on Lumen outperform Erlang on Lumen, which is an exciting idea!

                                                                                                    1. 1

                                                                                                      What are some mechanisms to deliver type information to the VM? Could it be generalized so that other languages on the BEAM could also benefit?

                                                                                                      1. 1

                                                                                                        At present there’s no type based optimisations AFAIK on the BEAM or Lumen, but Lumen’s dev team said they may be able to add an API for this at a later date. Gleam and Lumen are both written in Rust so I could imagine Gleam having a backend that generated type annotated Lumen IR.

                                                                                                        1. 1

                                                                                                          Right, but I was thinking of a how to encode the type information in-band so that other typed languages on the Beam could also take advantage of any possible speedups.

                                                                                                          Like if a module had a Map(Fn => TypeTuple{}) if it exists, the alternative Beam implementation (Lumen in this case) could use it, it might even be a way to provide entirely alternate implementations for functions, it could be a Map(Fn => WasmBlob) and implement BIFS.

                                                                                                2. 1

                                                                                                  There is no fully working BEAM runtime implemented in Rust right now. AFAIK Lumen is still in progress and other implementations didn’t lift off.

                                                                                                  EDIT: And releases (the deployment units in Erlang) often contains BEAM implementation provided, so if you build release for your target machine and the external libraries have compatible versions (libc and OpenSSL) then it should work with plain tarball of release.

                                                                                                  1. 2

                                                                                                    I was more thinking of binding against an existing BEAM runtime, like deno does with V8 :-)

                                                                                                    1. 3

                                                                                                      The BEAM was not designed to be embeddable like JS engines.

                                                                                                      If you just want self-contained apps, “releases” are that.

                                                                                                      1. 1

                                                                                                        They’re not really self contained in the way that a static binary is, they depend on libraries being installed on the host.

                                                                                              2. 2

                                                                                                What’s the appeal of shipping a completely static binary? I don’t think it’s hard to just install Erlang or include in your package.

                                                                                                1. 5

                                                                                                  A lot of people say that their favorite feature of Go is that it gives you a single static binary, which is easy to copy around. I think that’s a good argument, particularly after seeing what node_modules and pip directories look like.

                                                                                                  1. 3

                                                                                                    Hmmmm, maybe I’m from a different world here, where foopkg add libfoo or tar cvf foo.tar foo.js node_modules/npm install isn’t a hard thing to do, and shipping libraries/vendoring them if you REALLY hate that is common practice on Windows anyways.

                                                                                                    1. 6

                                                                                                      If you are to redistribute your solution (in binary form) to into various, separate, customer (or internal enterprise) environment running, different versions or patches of OSes,

                                                                                                      would > foopkg add libfoo or tar cvf foo.tar foo.js node_modules/npm install isn’t a hard thing to do, and shipping libraries/vendoring them

                                                                                                      be as convenient as a single binary distribution ?

                                                                                                      1. 2

                                                                                                        That approach is possible but you’d also need to ensure that the right C libraries are installed on the target machine too. It’s all doable but it requires additional work and a degree of technical knowledge compared to “copy this to your computer and double click on it”

                                                                                                      2. 3

                                                                                                        isn’t this what containers are for these days? Can’t you just ship a docker or flatpak (or the mac/windows equivalent) and be done with it?

                                                                                                        1. 3

                                                                                                          They do a good job for many uses cases but there are limitations. They require more technical knowledge to install and run than a file you can double click on, and there are performance + access implications of running software inside a container.

                                                                                                        2. 1

                                                                                                          after seeing what node_modules […] directories look like

                                                                                                          On a related tangent, we’re starting to use webpack to bundle files for NodeJS apps at work, which so far seems to be worth it for us. (No minification though, that would be awful.)

                                                                                                          I’ve seen a couple hundred MB node_modules result in around 10-20MB unminified bundle files. Deployment goes faster with one moderately big file than 100ks of tiny files. In the process we dropped the need for production to run npm install --production. Also in particular we see Azure app service is really slow at reading lots of small files: bundling reduced start up time for some services from ~30s to ~5s.

                                                                                                          So I think bundling things into a smaller number of files makes deployments nicer even when that smaller number isn’t as small as 1.

                                                                                                          In both the before-bundling and after-bundling states we have been doing installations using a single zip file: what changed is mainly the number of files in it.