Threads for lpil

  1. 2

    Gleam looks like a very nice language: I hope to find time to give it a try this summer.

    Is there a showcase of “stuff built with Gleam” out there ? I’m curious :)

    1. 2

      There’s a list of libraries and projects here: https://github.com/gleam-lang/awesome-gleam

      Could be useful. More to come in future!

    1. 1

      You ought to add a play button to the videos. Firefox disables autoplay by default, I didn’t even realize they were videos at first.

      1. 1

        It should do that I think? I use firefox and it does for me.

        1. 1

          Ah, I suppose “block audio” is the default. It would autoplay cause your videos don’t have sound. I have set autoplay to “block audio and video”.

          Either ways, you can add the “controls” attribute in the video tag.

      1. 7

        This all sounds really great, except this bit:

        And on a related node, recently publish packages can be replaced with gleam publish –replace. This is useful for correcting any mistakes made during the process of releasing a package.

        Does that mean the content of a particular version of a package can change? (Also I think there’s a typo “recent published packages”?)

        1. 12

          This is a feature of Hex (a package manager for all BEAM modules (erlang, elixir, gleam, etc)). The time limits are quite short so there should be very little danger:

          There are exceptions to the immutability rule, a package can be changed or unpublished within 60 minutes of the package version release or within 24 hours of initial release of the package.

          https://hex.pm/docs/faq#can-packages-be-removed-from-the-repository

          1. 4

            That’s neat !

            I wish PyPI had this: these kind of small release mistakes can happen very easily.

            1. 3

              Ahh ok. The time limits make it a bit less concerning.

              1. 6

                Packages also come with checksums so the tooling will identify a change compared to what is expected in the lockfile.

            2. 1

              While we’re pointing out typos: s/related node/related note

            1. 3

              With this a .ts.d file will be generated for each Gleam module compiled. … Will produce this .ts.d file. … gleam.ts.d

              Isn’t a TypeScript declaration file supposed to be .d.ts, not .ts.d? For example.

              1. 3

                Oops, typo. Thanks for catching that.

                1. 1

                  There’s a few more of the same one.

                2. 1

                  haha I was so confused by this and was thinking “what kind of workaround is this???” 😅 glad to know it was just a typo

                1. 3

                  It sounds like golang is not good for whatever it’s being used for, but even in the guy’s 4 blog posts there isn’t a ton of detail.

                  Golang is good (perhaps not great) for things where you’re mostly doing io on unixoid platforms and there are no really complicated algorithms. It also discourages cleverness by verbosity (unlike Java encouraging both cleverness and enforcing verbosity). Concurrency is less painful than most other languages.

                  Not every programming language is great for every use case.

                  1. 2

                    He said on Twitter he was professionally using it for networked services on *Nix.

                  1. 3

                    Congrats! Gleam is super cool and I’m glad to see it keep getting better.

                    Nitpick: under “Compilation” you want “emitted” rather than “omitted”.

                    1. 2

                      Thank you. I use voice dictation for the stuff and it adds plenty of fun typos.

                    1. 11

                      There’s no overhead compared to calling regular Erlang code, and the generated APIs are idiomatic Erlang.

                      Any Gleam packages published to Hex (the BEAM ecosystem package manager) now includes the project code compiled to Erlang. Once the various build tools of the other languages have been updated they will be able to depend on packages written in Gleam without having the Gleam compiler installed.

                      We want to fit into the wider ecosystem so smoothly that Erlang and Elixir programmers might not even know they’re using Gleam at all! All they need to know is that the library they are using is rock-solid and doesn’t fail on them.

                      This is awesome! It’s really a shame that Elixir never did this. All the Elixir libraries are really painful to use in Erlang projects. I intentionally use Erlang for the open source libraries I’ve created so they are usable from all languages built on the VM.

                      1. 5

                        You feel exactly the same way I do! There’s so much good stuff in Elixir I wish the other languages could use.

                        1. 1

                          What are some other notable languages on the BEAM runtime? I’m only aware of Elixir, Erlang, and Gleam.

                          1. 2

                            Elixir and Erlang are the big ones but the other ones that get used in production that I’m aware of are LFE, Purerl, Hamler, and Luerl

                            1. 1

                              I’ll have to look into those languages. Thanks!

                        2. 2

                          It’s really a shame that Elixir never did this. All the Elixir libraries are really painful to use in Erlang projects.

                          Aside from needing an Elixir compiler in all cases, and not being able to use Elixir macros (not Elixir’s fault!), where is the pain point? I am on the Elixir side 99.9% of the time so I don’t see it.

                          1. 6

                            There’s a few things:

                            • The Elixir compiler and standard library need to be installed, but they’re not on Hex unlike everything else, you don’t get declarative version resolution when installing them, and they increase the bytecode size quite a lot.
                            • The Elixir compilation process has a final step that needs to run last in order to optimise protocols, so you’ll need to wrap or modify your build tool in some way to do this.
                            • The Elixir module names and some function names use characters that require quoting in atoms so the function calls look rather strange 'Elixir.Project.Module':'active?'(X).
                            • Many APIs use macros when they could be functional, making them unsable from other languages.

                            These are not huge barriers, but if you use a library written in Erlang (or in future Gleam) you don’t have to worry about any of this. You add it to your list of deps and that’s it.

                            1. 4

                              I think you missed my point. It’s troublesome when you want to use Elixir libraries from Erlang, or from any other language on the Erlang VM. The overhead and hassle of retrofitting an existing project with support for Elixir compilation makes it not worth the effort. Thus I stick with Erlang because I need to write code that can be used from any language on the VM.

                              1. 3

                                It could be (and probably is) pretty easy to use one of the existing rebar3 plugins for using Elixir from a Erlang project. Take https://github.com/barrel-db/rebar3_elixir_compile as an example integration. I haven’t used it, but it looks pretty straight forward. I still wonder how any configuration would be wired together, but that should be pretty reasonable to write if needed.

                                Beyond the build system, I imagine Elixir code doesn’t feel ergonomic in other languages. It’s function argument ordering differs from a lot of functional languages, the pervasive use of structs in library APIs, the use of capitalization for modules doesn’t read well, and the constant prefix of 'Elixir.AppModue':some_function(). all make it less appealing.

                                All together it’s just enough hassle to use outside of Elixir, and often that bit of work + usability issues isn’t worth it.

                            1. 3

                              Question. What’s more to dependency resolution than constraint solving? Why not just use a solver like Z3?

                              1. 11

                                There’s not huge amounts of difference. Pubgrub is based on the same field of research and is effectively a specialised constraint solver optimised for speed and clear error messages with this one particular problem.

                                The main difference is that with pubgrub we include an extra 2000 lines of Rust, while Z3 would mean distributing and linking to 600,000 lines of C++.

                                1. 1

                                  One aspect that I am not sure off the shelf constraint solvers handle automatically is the fact that after, say, upgrading a package some of its previous dependencies may no longer be necessary and could be dropped. But this in turn can change the set of constraints that the initial solution was based on meaning that it now has to be re-evaluated. Which in turn can lead to other packages being no longer necessary (or even previously thought to be unnecessary become necessary again). So there is this iterative refinement process to arrive at the optimum solution.

                                1. 5

                                  Why do you say Nomad is not free?

                                  1. 4

                                    That paragraph seems like the author is justifying to themselves why they want to play with k8s. I think they’re super weak reasons, could delete the entire paragraph and improve the post.

                                    eg, not sure I’d claim Mesos hasn’t gained critical mass given it underpins Netflix’s entire stack (Titus depends on Mesos & Zookeeper.) Nomad has equivalent large deployments, Cloudflare, Roblox and as you point out, is free (with paid-for extra features.)

                                    1. 4

                                      Author here, thanks for the feedback. I meant Nomad is not free because some features are behind an “Enterprise” paywall.

                                      1. 1

                                        Isn’t that also technically true of k8s? In the sense that cloud providers (google, amazon) have a special sauce that they don’t share with mere mortals?

                                        1. 3

                                          You don’t bump into “Error - Enterprise only feature” messages when working with K8s. I’m sure Amazon and Google have their own tools for working with it, but their use case is very specific.

                                          1. 1

                                            Thankfully no, that is not the case.

                                        2. 2

                                          Mesos was a contender for a hot minute but it’s definitely donezo at this point, isn’t it?

                                          1. 2
                                            1. 2

                                              Goodnight, sweet prince.

                                              edit: I actually had no idea it had gone to Apache, hah.

                                              1. 2

                                                Apparently it was originally an Apache jam? Wow. I know nothing.

                                      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!