I've seen various posts about Elixir's gradual type system pop up on HN, but haven't been following too closely. Does anyone know whether this particular gradual type system can change the asymptotics of programs vs untyped code? As far as I'm aware, most gradual type systems (e.g. Racket) can make programs run asymptotically slower, although there are some exceptions [1].
Elixir's gradual type system cannot change the asymptotic complexity of your programs. The design explicitly rules out mechanism that causes slowdowns in other gradual type systems (runtime casts at static/dynamic boundaries)
Most gradual type systems insert coercions when values cross the types/untyped boundary (checking every element of a list, wrapping values in typed proxies, etc) but Elixir's team published a "strong arrows" result specifically to achieve soundness without those runtime checks. The bytecode the compiler emits is semantically identical to untyped code.
Your last sentence is basically where I'm at, writing my backends in Rust these days. I'm interested in the BEAM promise of letting things crash but not sure how good that is in Gleam due to its OTP still being somewhat immature as the devs are rewriting GenServer as a typed library.
I wrote both Elixir and Erlang code. Erlang is just useless to me as a
programming language; it has many great ideas though. I love the idea
of being able to think in terms of immortal, re-usable, safe objects
(Erlang does not call these objects, but to me this is OOP by Alan
Kay's definition. I don't use e. g. the java definition for OOP.)
Elixir built on that and made Erlang code optional, meaning people
could write more pleasent code. And here it succeeded. I am not sure
why Elixir succumbed to type madness now, but the comment that
"writing Elixir is like writing Erlang", is just simply not true.
Elixir is significantly better than Erlang with regard to writing
code. José Valim got inspiration for Elixir from ruby, to some
extent.
You're taking my comment way too literally. I'm basically just making a syntax comparison. Obviously Rust is not at all like Gleam in many ways either. It's just statically typed and has a similar syntax.
I agree that actor languages are the purest form of OOP as Alan Kay has expressed it. And unlike Smalltalk, Erlang just accepts that some things are naturally functions, not messages.
Gleam doesn't have macros, which many Elixir libraries (such as Phoenix and Ecto) uses to great effect.
Gleam for example has issues with verbosity of decoding/encoding json whereas in Rust you derive serde and in Elixir it's just a function call away.
Elixir has a more mature ecosystem. While you can for example use Phoenix with Gleam (or some other Gleam framework) the experience just isn't the same.
The big draw with Gleam over Elixir is the typing (where Elixir is now closing the gap) and being able to compile to JavaScript (which is also what Hologram is doing for Elixir).
I prefer Gleam's typing system and the Rust-like syntax, but for now I feel Elixir is the better choice for all my web dev projects.
Oh shit here I go (and learn Elixir for a whole year (again)) again.
I love everything about Elixir, but Elixir constantly makes me doubt myself like no other language. My brain isnt made for functional stuff, but this makes me want to try again.
Sucks that it's not really a beginner friendly ecosystem and usually, when having questions answered, people assume you already know a lot about the language.
don't let the title fool you - the first half of the book is just elixir
over the past 8 years this is the book i've used to ramp back up on elixir and it works like a charm every time - i've never finished it
for me, a mark of a good programming book in this tutorial-project style is that I have started it half a dozen times and never finished it because at some point before the end I've been equipped w/ the tools to go off and do my own thing
Yea I've worked through Elixir in Action and appreciate all book recommendations. My issue is, tutorial style books rarely cover security related concerns.
How to properly build a liveview thats safe against hijacking the websocket phoenix uses for liveviews. You can just do it from the devtools on client side. With regular HTTP requests at least I know what to look out for, with liveview there are almost no resources on how to build a view securely. Like I was able to just call the functions in my module by just addressing them from my browsers console. Just to name an example.
Yea I've posted there twice as far as I remember. You will absolutely get help, whether you understand the answers is a whole different story.
Elixirs community is great. Its just hard to learn because it's not yet widely adopted, there are no (non senior) roles for it and it's a lot of work understanding all the BEAM concepts. A thing just being interesting isn't enough motivation for me to learn, I need a bigger goal but with Elixir there do not seem to be any.
My last experience with it was building something with Phoenix Liveview until I noticed how easily you can hijack the websocket and just spam random commands to your server or temper with payloads (with regular webapps ive built i never had this issue). Which made me quit that project.
Fair. If you have this friction then it's not worth pursuing.
One thing that really helped me pick it up was saying YOLO and rewriting one part of the business stack from Ruby on Rails to Elixir. It taught me quickly and well.
The official guides are also great and IMO you can get through them all without a rush in two weekends. But again, if you don't want to then don't.
You can also try asking right here in this HN thread. Maybe I or others would be willing to give you a more detailed response.
When building I couldn't get "what if I have ghost processes", "what if I spawn too many processes", "what if this architecture is bad compared to...", "when to kill processes", "whats the correct restart strategy for this" out of my head... It's so confusing to build for the BEAM that I ultimately gave up on it.
Do you maybe know some Rust? I'm also not that experienced with FP languages, but Gleam felt familiar enough, due to some Rust-isms, to allow me to focus more on the concepts rather than the syntax. Granted, I spent a few afternoons with it, but if I were to pick a FP language again to wrestle my brain into submission, I'd probably go with Gleam due to familiarity.
I gave up on Rust even quicker than on Elixir haha.
But yea I know about Gleam and I did build some fourier transform stuff with Rust a while back. I like Gleam generally. I am just much much slower with FP and think its extremely unintuituve compared to, say, Go for example.
The confusing state riddling here happens in the background as your whole app basically is a state. The thing that really throws me off with Elixir is having to handle (possibly) hundreds of thousands of processes. Doing this correctly seemed impossible to learn for me.
It's not like you're dealing with hundreds of thousands of ad-hoc processes. If you're writing a web server, for example, each of these processes might simply be a client connection and they all operate the same. The fact that there are 2 or 100,000 is only a problem for the BEAM scheduler.
Sounds like there is some foundational knowledge of Elixir that you miss and everything seems more confusing than it should be. To me writing a 'server' in Elixir is orders of magnitude easier than doing it in Python, Rust or C++.
As someone else suggested, bring your concerns to the Elixir Forum and surely someone will clarify them for you
I'm working on a game engine right now (written in object oriented language, of course) and I keep itching to design a compiled functional language for games, because state spread in thousand of objects, eldritch class hierarchies, are complete hell.
Once you taste Elixir/Erlang, there is no going back to the madness.
Do https://htdp.org and follow all the exercises carefully (yes, it will feel like baby work at first) - you will retrain your brain for functional stuff. :-)
With Elixir specifically it was the learning experience I had with Phoenix. I didn't understand how a Phoenix app booted, didn't know where to edit my config.
Syntax like:
I love Elixir and Phoenix, but Phoenix especially uses a lot of compile-time macros and it can be a steep learning curve when you need to pull apart the skeleton framework to figure out how things are actually wired.
I pretty frequently find myself needing to open up the source to understand what's actually going on, the docs aren't bad but it often feels like they assume a lot of existing familiarity with phoenix.
In this example, `socket` is a compile time macro and it's being called with
and what is does is register that data with the `phoenix_sockets` attribute inside the module you called `socket` from. At compile time that gets turned into a lookup inside your module, and presumable then the UserSocket module is invoked when a websocket request hits the specified path.
Would you find it more clear if socket was called like this?
I find the optional parentheses, and the way that keyword lists are defined to be the two biggest stumbling blocks when I come back to Elixir after a while way.
example "with", 3, extra: "arguments", as: "a", keyword: "list"
always takes some extra mental effort to get through, especially when there's no parenthesis. But I appreciate not having to write all the extra brackets and parens when I get going, so I think it's a fair tradeoff.
Socket is a behavior, which is like a trait or interface. MyAppWeb.UserSocket implements the behavior. It's basically a convenience over having to write a bunch of repetitive WS or long poll handling every time you want a socket like thing. Its pretty well documented https://phoenix.hexdocs.pm/Phoenix.Socket.html.
I think this also shows that merely copy/pasting
ruby's syntax, isn't an automatic win. I noticed
this before with crystal, though naturally crystal
had types from the get go.
Fundamentally:
def foo()
end
should stay simple. And this is no longer the case now.
(Ruby also went in error, e. g. "endless methods". I don't
understand why programming languages tend to go over the
edge in the last 5 years or so.)
The syntax you are commenting on has always existed in Elixir, before v1.0, as part of patterns and guards.
You are commenting as if we added this now but we have made no changes to the language surface. The difference is that we now leverage these same language constructs to extract precise type information.
You need Beam and the Elixir. I find that really weird, because I'm used to just the language like in Python, Java, C, Rust. Not something underneath it, too.
There is no debugger. The way to debug Elixir is to print stuff to the console, like 40 years ago. No thanks.
> You need Beam and the Elixir. I find that really weird, because I'm used to just the language like in Python, Java, C, Rust. Not something underneath it, too
The beam is a VM. You get that Java requires a VM too right? It’s called JVM for a reason. And Python requires an interpreter.
> There is no debugger. The way to debug Elixir is to print stuff to the console, like 40 years ago.
That is false. https://www.erlang.org/doc/apps/debugger/debugger_chapter.ht... and you have observer. And you have a lot of other debugging tools. I hear Java has a good one and maybe it’s better (I never used it) but it’s not true there exist no debuggers for the beam.
If you're used to Java, Elixir is like `javac`, Beam is like `java`. Mix is like a (way better) version of Gradle. You need elixir to compile your app, you only need the Beam to run it. Once you've built your project, you don't need Elixir anymore exactly like java/javac. C and rust compile to machine code so don't have a runtime dep, but otherwise they still require you to have a compiler at build time, just like elixir.
If you're going to try and use this analogy, you need to compare Elixir to Kotlin or Scala or Clojure rather than Java. Elixir is a language written for the BEAM which was created for Erlang. The BEAM happened to be useful VM for these other languages such as Elixir, Gleam, LFE, & Luerl.
For Java you need a JRE and JDK depending on whether you're just running or also building. That they are bundled (for Windows) is slightly convenient, but they're not bundled on Linux so what you're saying is OS dependent
To be fair, there is more than just print debugging. You have access to tools like red(x)bug https://github.com/nietaki/rexbug, the Elixir-LS project has Debug Adapter Protocol support. And in my opinion, the REPL (and decent software architecture) makes it easy to investigate your code by just running the functions as needed (even if your live production system if you want).
[1] https://doi.org/10.1145/3314221.3314627
Most gradual type systems insert coercions when values cross the types/untyped boundary (checking every element of a list, wrapping values in typed proxies, etc) but Elixir's team published a "strong arrows" result specifically to achieve soundness without those runtime checks. The bytecode the compiler emits is semantically identical to untyped code.
that said, I'm a fan
I don't know the current state of Gleam OTP, but last I checked it wasn't great.
If you don't care about either of those things and only about types, use Gleam. But then why not just use Rust?
I wrote both Elixir and Erlang code. Erlang is just useless to me as a programming language; it has many great ideas though. I love the idea of being able to think in terms of immortal, re-usable, safe objects (Erlang does not call these objects, but to me this is OOP by Alan Kay's definition. I don't use e. g. the java definition for OOP.)
Elixir built on that and made Erlang code optional, meaning people could write more pleasent code. And here it succeeded. I am not sure why Elixir succumbed to type madness now, but the comment that "writing Elixir is like writing Erlang", is just simply not true.
Elixir is significantly better than Erlang with regard to writing code. José Valim got inspiration for Elixir from ruby, to some extent.
Gleam for example has issues with verbosity of decoding/encoding json whereas in Rust you derive serde and in Elixir it's just a function call away.
Elixir has a more mature ecosystem. While you can for example use Phoenix with Gleam (or some other Gleam framework) the experience just isn't the same.
The big draw with Gleam over Elixir is the typing (where Elixir is now closing the gap) and being able to compile to JavaScript (which is also what Hologram is doing for Elixir).
I prefer Gleam's typing system and the Rust-like syntax, but for now I feel Elixir is the better choice for all my web dev projects.
I love everything about Elixir, but Elixir constantly makes me doubt myself like no other language. My brain isnt made for functional stuff, but this makes me want to try again.
Sucks that it's not really a beginner friendly ecosystem and usually, when having questions answered, people assume you already know a lot about the language.
don't let the title fool you - the first half of the book is just elixir
over the past 8 years this is the book i've used to ramp back up on elixir and it works like a charm every time - i've never finished it
for me, a mark of a good programming book in this tutorial-project style is that I have started it half a dozen times and never finished it because at some point before the end I've been equipped w/ the tools to go off and do my own thing
Sometimes posts don't get traction due to ambiguity, and some smelled like "do my homework" so people ignored them.
But every post with a genuine curiosity in it gets answered, as far as I can tell.
Elixirs community is great. Its just hard to learn because it's not yet widely adopted, there are no (non senior) roles for it and it's a lot of work understanding all the BEAM concepts. A thing just being interesting isn't enough motivation for me to learn, I need a bigger goal but with Elixir there do not seem to be any.
My last experience with it was building something with Phoenix Liveview until I noticed how easily you can hijack the websocket and just spam random commands to your server or temper with payloads (with regular webapps ive built i never had this issue). Which made me quit that project.
One thing that really helped me pick it up was saying YOLO and rewriting one part of the business stack from Ruby on Rails to Elixir. It taught me quickly and well.
The official guides are also great and IMO you can get through them all without a rush in two weekends. But again, if you don't want to then don't.
You can also try asking right here in this HN thread. Maybe I or others would be willing to give you a more detailed response.
Check this out: https://www.theerlangelist.com/article/spawn_or_not
Written by one of the very best Elixir mentors. I believe it will dispel most (hopefully all) of your doubts and clear things up.
You can always ask follow up questions for clarification, people there are generally really friendly.
But yea I know about Gleam and I did build some fourier transform stuff with Rust a while back. I like Gleam generally. I am just much much slower with FP and think its extremely unintuituve compared to, say, Go for example.
Sounds like there is some foundational knowledge of Elixir that you miss and everything seems more confusing than it should be. To me writing a 'server' in Elixir is orders of magnitude easier than doing it in Python, Rust or C++.
As someone else suggested, bring your concerns to the Elixir Forum and surely someone will clarify them for you
Once you taste Elixir/Erlang, there is no going back to the madness.
``` socket "/ws/:user_id", MyApp.UserSocket, websocket: [path: "/project/:project_id"]
```
Elixir gives you too much freedom on how to write something on a syntax level which really annoyed me.
I pretty frequently find myself needing to open up the source to understand what's actually going on, the docs aren't bad but it often feels like they assume a lot of existing familiarity with phoenix.
In this example, `socket` is a compile time macro and it's being called with
and what is does is register that data with the `phoenix_sockets` attribute inside the module you called `socket` from. At compile time that gets turned into a lookup inside your module, and presumable then the UserSocket module is invoked when a websocket request hits the specified path.Would you find it more clear if socket was called like this?
Or, alternatively, would it help if the endpoint was more specifically defined likeComing from other languages, I find that
being equivalent to and always takes some extra mental effort to get through, especially when there's no parenthesis. But I appreciate not having to write all the extra brackets and parens when I get going, so I think it's a fair tradeoff.This is true perhaps compared to python or go, but not compared to Java, JS/TS, or some others.
> socket "/ws/:user_id", MyApp.UserSocket, websocket: [path: "/project/:project_id"]
Socket is a behavior, which is like a trait or interface. MyAppWeb.UserSocket implements the behavior. It's basically a convenience over having to write a bunch of repetitive WS or long poll handling every time you want a socket like thing. Its pretty well documented https://phoenix.hexdocs.pm/Phoenix.Socket.html.
I am sorry for your loss here.
I think this also shows that merely copy/pasting ruby's syntax, isn't an automatic win. I noticed this before with crystal, though naturally crystal had types from the get go.Fundamentally:
should stay simple. And this is no longer the case now.(Ruby also went in error, e. g. "endless methods". I don't understand why programming languages tend to go over the edge in the last 5 years or so.)
You are commenting as if we added this now but we have made no changes to the language surface. The difference is that we now leverage these same language constructs to extract precise type information.
Two reasons I put it aside again are:
You need Beam and the Elixir. I find that really weird, because I'm used to just the language like in Python, Java, C, Rust. Not something underneath it, too.
There is no debugger. The way to debug Elixir is to print stuff to the console, like 40 years ago. No thanks.
> You need Beam and the Elixir. I find that really weird, because I'm used to just the language like in Python, Java, C, Rust. Not something underneath it, too
The beam is a VM. You get that Java requires a VM too right? It’s called JVM for a reason. And Python requires an interpreter.
> There is no debugger. The way to debug Elixir is to print stuff to the console, like 40 years ago.
That is false. https://www.erlang.org/doc/apps/debugger/debugger_chapter.ht... and you have observer. And you have a lot of other debugging tools. I hear Java has a good one and maybe it’s better (I never used it) but it’s not true there exist no debuggers for the beam.
I'd like to do step by step but I cannot plug the debugger to VScode from inside a docker container.
I am not sure what GP is objecting to.
Here's what you need to do for elixir:
Download and run the Erlang installer Download and run the Elixir installer
Here for Java: Download and run the Java SDK
And for Python: Download and run the Python installer
I guess we know how he feels about TypeScript.
Download SDKMan/Jenv
Install the version(s) of Java you need for your projects
Make sure your JAVA_HOME environment variable is set
Ensure your IDEs locate the correct Java home
Compared to all that, Elixir's two installers are trivial.
And if you have a competent package manager, you can just tell it to get Elixir and it'll handle Erlang for free.