return to table of content

Switching to Elixir

byhemechi
106 replies
1d12h

I often see people say static typing slows them down and I'd really like to know why that is because for me it's the exact opposite, I really don't like not knowing what format data is in. I'd much rather have to write slightly more verbose code and have a vast number of possible errors caught at compile time instead of having things go wrong in production when someone inputs something a bit weird with nothing so much as an error.

wofo
30 replies
1d8h

Lack of proper types is what killed the joy of programming in Elixir for me (I lasted 6 months, hoping I would somehow adapt, but the experience was so miserable that I decided to move on). I simply can't understand how anyone can be productive in a big codebase without the rigor of static typing, but those people exist, so I guess there must be something about our brains that divides us in the dynamic vs static typing camps.

d3ckard
9 replies
1d5h

I believe this as well. I like dynamic typing, because it often feels to me that rigour of static typing is slowing the prototyping phase. Plus overusing types createsa lotof boilerplate. In one of the frontends I've seen adding a boolean field to a form required changing over 10 files - thank you Typescript.

On the other hand, sometimes I feel like it has a lot to do with test writing. I feel people enjoy static typing, because you can get a feedback loop catching certain things without writing any tests. If you do write tests, all the type errors get caught pretty immediately anyway, so I just don't see the benefit.

Personally, the biggest advantage of dynamic typing for me is the ability to skip formalities for a time. If I want a function that can modify any struct with field "val" in (by, let's say, setting it to zero), I can - and I don't have to do multiple definitions, I don't have to define an interface. Just a function and I am done. If I want to skip error handling for now and only code the happy path, I can - and my program will work (and crash on error, but in some cases it's ok).

As the projects get more complex and require higher safety guarantees, static typing helps in ensuring nothing got broken - but nothing beats dynamic typing for prototyping.

mejutoco
3 replies
1d5h

I mostly agree with you. Just wanted to add that in some languages, for example in Typescript, there are ways to say that you do not care about the type for prototyping. For example using :unknown or :any.

IggleSniggle
2 replies
1d2h

:unknown is great, but the problems come in the middle area; when you have lots of very tight types and are prototyping something that makes use of those things, :unknown doesn't work, and :any can betooexpressive, even for your prototype.

mejutoco
0 replies
22h13m

Sorry, but that is moving the goalposts. Quick prototyping was mentioned, but now we seem to be talking about some undefined balance between typing and no typing for prototyping. It seems :any solves the problem.

cloverich
0 replies
1d1h

when you have lots of very tight types

This is true. But also I've noticed many less experienced TS devs end up writing types that are too specific and not utilizing structural typing enough. So e.g. writing some type and demanding a function accept it, when that function only actually needs one or two properties from it. Instead that function can inline or localize the part of the type it needs, and the original type can be unaware its ever being used by some other function.

And the other thing is trying to leverage the type system too much. For my style, if the types aren't making things easier to read, write, and maintain, they should be loosened and / or duplicated. I blame a lot of libraries here, it should never be puzzling to figure out how to type something so a function accepts it, yet that comes up quite often; I end up diving through these nested and overly DRY types trying to find what the heck even is this thing? That's crazy. If you need to cmd+click more than once or twice to understand what a type is, its way too abstracted.

j1elo
2 replies
1d4h

If you do write tests, all the type errors get caught pretty immediately anyway, so I just don't see the benefit.

That's a pretty bigif, though. You will never catch me in my typed backyard, writing tests that say: if typeof(arg) =! string then return error("Not a string!")

An additional problem of course is that solutions that assume extra work from people, tend to be brittle ones (also thinking about "manual backups" here) aka. those tests will end not being written at all.

sodapopcan
0 replies
1d

You shouldn’t be writing that in dynamic languages anyway.

d3ckard
0 replies
1d1h

You will never find me in my dynamic backyard writing such tests neither - I will write normal tests and they still expose type errors.

And, if you do not write tests, there is a bunch of other problems that will surface, which will not be caught by the compiler itself. What I'm saying is static types give you feedback loop:

write code -> make the project compile -> fix bugs

while the dynamic ones give you:

write code -> fix bugs (including type ones).

Obviously, YMMV. For me it works. And to be honest, from my experience nothing is more brittle than a type hierarchy designed early in project lifetime and then fixed repeatedly until it "works", but again - to each their own.

spion
0 replies
1d5h

The example is, interestingly possible in TypeScript, at a very cheap cost

  function modifiesValField(struct: {val: number}) {
    struct.val = 0;
  }
Structural types and inline interfaces (or as I like to call them inyourfaces) are pretty cool.

But I do get your point - although type systems have gotten much less annoying, its not like they're perfect.

IggleSniggle
0 replies
1d2h

I do think types and tests have a lot of overlap. In an ideal system, you would have tests that result in progressively more narrow types as each test case is added, providing the benefit of both.

This is basically the entire reason I am so excited about Zig.

Edit: it's also the reason I have a love/hate relationship with typescript. Typescriptalmostlets you do this if youtry really hard, but at the end of the day it's not designed to truly test your code and requires you to "cheat" in order to make the types properly describe the situation; every time you "cheat" in order to get a more expressive type (whether that's looser or narrower), you would have been better off writing a test instead.

toolz
8 replies
1d5h

I'm firmly in the camp that it's all perception. The studies I've seen aren't what I would consider conclusive, but they certainly suggest there is very little difference in the output and bugs of dynamic vs static languages.

In my experience, static typing seemed to lend itself to poor testing, maybe some sort of belief that static types were good enough to not need tests that can prevent regressions. So from my point of view the static typing is negative value. It prevents such a low value class of bugs while seemingly incentivizing people to be lax with the most important classes of bugs.

aerhardt
7 replies
1d4h

I literally struggle to read and work with dynamic code. My head explodes when trying to hold return types or the shape of semi-complex data structures in my head, versus having it spelled out. I wouldn't call it an issue of "perception", I really think in my case it's "capability", pure and simple. I've programmed for thousands of hours in both styles, so we're well past the possibility of this being an adaptation problem.

I am totally convinced that the advocates of dynamic programming are right, too, just possibly built differently. For example, if I had an order of magnitude more working memory than I have as an individual (I'm assuming that's neurologically plausible), maybe I'd view dynamic programming differently, too.

MatthiasPortzel
4 replies
1d3h

I’m a proponent of dynamic typing. I’d say the same thing. I don’t have enough working memory in my head to store the compile-time type information about every relevant variable, in addition to the actually important information about what the runtime data could be.

The way that I write static-typed code is by imagining how I would write dynamic code to solve the problem, and then additionally imagining what types and type constraints I need to add.

I honestly think it’s a kind of an instance of Paul Graham’s Blub Paradox. I know JavaScript and I spent years writing JavaScript. So if you ask me to write TypeScript, well, I write the JavaScript that I want to write and then go back and add types to make the typescript compiler happy.

There are a bunch of other things I could talk about. I should write a post.

leoedin
1 replies
1d2h

The way that I write static-typed code is by imagining how I would write dynamic code to solve the problem, and then additionally imagining what types and type constraints I need to add.

Is that not how everyone writes static typed code? You have a need for a variable holding some data, you think about the bounds of that data, you pick a type. What other way would you do it?

The problem with dynamic typing isn't in the first-write. It's all in your head then. It's in the 2 year later bugfix, when you're looking at a function and wondering what kind of data is being passed into it. And then you find all the places that call that function and still can't work out what fields that object will have, or whether they're numbers or strings.

cloverich
0 replies
1d2h

The problem with dynamic typing isn't in the first-write. It's all in your head then. It's in the 2 year later bugfix

The 2 year later bugfix is often easier I agree. But for me by far the biggest difference is speed and effectiveness in writing new code. I'm not just much faster, but also much better with typed code probably because it fits the way my brain works better.

Is that not how everyone writes static typed code?

For me the process is a bit opposite. I tend to write the interfaces first, usually until the entire routine of whatever I am writing is complete. So e.g. only the types accepted and returned by functions, but not the actual function itself. Then I go back and add the code itself usually at the very end.

kaashif
1 replies
1d3h

I don’t have enough working memory in my head to store the compile-time type information about every relevant variable

Neither do I, but I know the compiler will check that for me so I don't need to hold all of that in working memory. I know my IDE will always be able to tell me the types too, and flag if anything is wrong immediately.

The different points of view on this are really interesting.

pmontra
0 replies
1d1h

In the end both approaches work well enough to keep companies in business. Companies fail not because of static or dynamic typing but because of marketing, internal fights, etc. The technical details are something that impacts very rarely.

Personally I worked in C for the first years of my career. Then the web happened and the two languages for it were Perl and Java. No more mallocs and frees, it was so great that I kind of forgot C. Then I was assigned to higher level tasks than programming and when I came back to it almost 10 years later I refreshed my Java (I kept doing Perl for my own stuff - CLI scripts and CGIs) and discovered Ruby on Rails. I realized that I could do the same web apps I was writing in Java with much less code and without having to lose my time after obvious but nearly useless details such as specifying that a given variable is a string, or number and how big, or an array of that class of objects indexed by strings (I intentionally use generic terms), etc. It's almost always clear what it is, especially if one picks good names for identifiers. There are some hiccups but not every year.

By the way, a great feature of Elixir is pattern matching in function definitions. In a pythonish pseudocode

  def fib(0): 0
  def fib(1): 1
  def fib(n): fib(n-1) + fib(n-2)
Of course n is an integer. It works with floats too and probably fails with anything else. But who would run fib on some complicated not numerical class that happens to implement the - operator?

I accept the argument that providing type information to a compiler lets it generate faster code. However none of my customers from the last 10 years care about that argument and they selected their technological stacks. Like everybody else they care about getting features done as quickly as possible. They all run their services on a single server, make enough money to pay themselves, their employees and a bunch of consultants like me.

weatherlight
0 replies
1d2h

My working memory is garbage and I do prefer working with dynamic langs, however. (I also have ADHD)

I do agree though if I have to work with spaghetti code, I'd much rather work with a language that has a proper type system (I mean a proper one, like OCaml, Standard ML, Rust, Gleam, Etc.) I think static typing in these languages doesn't get in the way, they all have varying degrees of type inference, the type system is sound and uncomplicated. Whereas a Language like Typescript's type system (of Facebook's Flow for JS) had my head spinning, It often felt like playing a mean spirited scavenger hunt with Simon from Simon says.

As far as dynamic langs go, some languages are terrible to work in, (Perl). and other languages because of strong conventions (Ruby and Elixir,) I find very very easy to work in, write tests, create libraries that use DSLs, etc.

So I guess I'm in the middle? leaning in the dynamic langs direction though.

cloverich
0 replies
1d2h

For me personally, my new theory is its an ADD thing. I'm older but recently came to fully appreciate how ADD my mind is, and how I've basically built many habits around coping with it. More recently I learned types is one of those things. I realized with types I can off load a ton of my working memory into the type system. I can bounce between ideas the way my brain wants me to without losing any state, because I'm always setting up the interfaces to the various thoughts I had. And the IDE knows how to take advantage of course, linking everything, popping up docs and hints and etc for every little idea. And so the result is it just matches my brain's natural patterns.

I still remember being quite shocked many years ago when I took a job using Java of all things, I was so fearful coding would take forever. It was my first typed language. But within months, I was faster, by a lot. I would write a lot more code before I had to test it, and once I began testing it there were few if any surprises. Now I'm working in Ruby, and without a debugger and constant tests, I feel I can't hardly get anything complex done in a reasonable amount of time. Like you I thought this was a hurdle that would pass, but while I'm far more effective than when I started, I find that its overall just mentally taxing to write code in this language.

Yet at the same time, when I pair with people who do not dislike Ruby, and watch them work, they are constantly asking "What is this" and "how does this work" and navigating parts of the codebase by grepping. They are effective, and I know its been studied a bit. But to my eyes, they would so obviously be far more effective with types, even when they state they dislike them, I just can't accept its a generally better approach in the absolute sense. I won't judge people for preferring a non-typed language. But I'll likely not accept another job where I can't use a typed language.

spion
2 replies
1d5h

I've been on both camps, so I'm hoping I can give some insight.

Lots of statically typed languages are very strict about their types and have too many of them. You have to admit, when you're trying to build something difficult and focus on getting the business logic part of your program right, the last thing you want to be thinking about is e.g. whether you need a String, ByteString, LazyByteString or any of the other types of strings, and which library decided to accept which one. At some level its definitely useful to distinguish between those, and I'm sure a lot of libraries make sensible choices. But initially in the development of the program its just unnecessary busywork that distracts you from the important bits.

In the past, typed languages also made it a bit harder than necessary to create new types, especially in situations where you have serialization and deserialization. And finally, we had to do all this work, and for what? To be unable to prevent the most basic of errors i.e. NullPointerException? You have to admit, it was a hard sell.

A lot of things have changed, however. TypeScript makes it really easy to define types, anywhere - inline on the function in the argument, or right above it. You can pretend the type is correct at deserialization time, or you can use libraries like `zod` to both define a validator and a type in the same syntax - its up to you. Rust similarly has powerful and easy to use tools like serde - structs and enums are easy to define, and easy to attach metadata to them quickly to (de)serialize them accurately. Huge differences from the old world of getters and setters and NPEs.

When using dynamic languages, there are techniques to make things easier. There is the often mentioned testing, which does help verify a large subset of code paths. Lesser known and more subtle technique is coming up with and following a strict naming convention for properties, for example, and to keep things as consistent as you can in general. This is why you often see so much focus in code reviews about conventions, linting and so on.

Nowadays I guess it mostly depends on how good your dynamic language techniques (at the team level) are, as well as what your treshold for type system annoyances is. There are still some annoyances even in the best type systems, but its gotten way, way better.

akkad33
1 replies
1d5h

you need a String, ByteString, LazyByteString or any of the other types of strings,

Out of curiosity, which language do you use where this kind of decision has to be made for daily programming problems?

spion
0 replies
1d5h

This particular example with the string types was Haskell, but Rust often makes you think about performance decisions at all times as well. I'm fully aware that that's the point of Rust, however (and yes there are ways to stop worrying and just `clone`)

solidninja
2 replies
1d5h

Nice to see that I'm not the only one - lasted 9 months trying to adapt to Elixir and couldn't. My background is Scala/Rust with heavy use of effect systems and reliance on writing the types out and then solving the puzzle of how to make everything fit. The tooling is pretty poor due to lack of investment compared to some of the other languages, and the debugging story is not great either. But hey, it works for some.

minton
0 replies
1d2h

I found the tooling to be quite nice. In my opinion, it’s better or equivalent to most popular languages (python, ruby). It’s definitely not full-on bumper rails/training wheels like a Microsoft IDE, but it’s obvious they’ve invested heavily in tooling early on.

lemper
0 replies
1d

same here, mate. though mine is haskell. I'd rather waiting for gleam to mature enough to mess around with it than to be miserable with the dynamics of the data. I just don't like to guess stuff down the line.

josephg
1 replies
1d6h

I’ve swapped back and forth between static and dynamic types a few times in my career. Java and C/C++ to JavaScript (and coffeescript) to typescript and rust. The entire time (30 years at this point) I’ve felt like whatever I was doing at the time was obviously the one true way to program. I feel that now - that what I’ve been doing lately (static typing) is clearly superior. Even for throwaway JavaScript based projects at the moment the first thing I do is install typescript.

I’m spitballing on the reason - I don’t know why it’s like this. But maybe it’s because static typing encourages you to write & plan your types first. When you know the data types, all the functions kind of flow around your types and everything feels like it obviously flows from that. With dynamic typing, it’s the reverse. I find myself writing my functions first (top down or bottom up) and then backfilling what arguments and data everything needs to pass around. I run my code a lot more as I develop it to stop bugs creeping in. And because I can run my code at any time. There’s no type checker stopping me from trying things out.

IggleSniggle
0 replies
1d2h

I've recently found a great middle ground for this, using esbuild to drive code as I'm writing it, while my IDE may meanwhile be complaining that all my types are broken. Getting comfortable having "broken" types while something is still in development is a nice middle ground, helping you come back to the hot spots whenever you're ready, and acting as a forcing function prior to commit or push.

swader999
0 replies
1d2h

The only way I've seen it work (rarely) long term is with extensive unit tests and that takes incredible discipline.

ra
0 replies
1d6h

I guess there must be something about our brains that divides us in the dynamic vs static typing camps.

I've wondered if that's a thing. It seems to be.

aerhardt
0 replies
1d4h

My best programming experience ever has been in OCaml and I love the idea of Elixir, but I can't even bring myself to try it because I know I'm not going to enjoy not having types. Even something as allegedly shitty as Python's type system would do it for me. I'm aware that there are ongoing projects to add typing to Elixir and I'll keep watching out how they evolve.

mstipetic
11 replies
1d4h

Every time an elixir discussion starts a vocal segment of people just starts complaining about types. Ok we get it you like types, can you leave the rest of us in peace

sph
8 replies
1d4h

It's just a hype phase. Types are cool, but in the past few years they seem to be the panacea for all problems, by inexperienced engineers that have got their first taste of Rust and Typescript. As if writing in Typescript would produce less buggy, more stable or more maintainable applications than using Elixir.

I'll saytypes are coolagain before I get routed by angry static typing zealots.

pjerem
3 replies
1d2h

I’ve worked in a lot of languages, from PHP 3 to Rust, F# and Typescript and a lot of others. So I’m relatively educated about their differences and pretty open minded about languages but I still don’t understand why there is still a debate about this.

I mean, I can understand that some language don’t implement types and that they have other advantages (Elixir is a nice example) but I still don’t understand why no typing is still seen by some people as an advantage.

What sort of code can you write in a non-typed langage that you couldn’t write with a typed one ? Newest type systems are mostly invisible and working by inference.

The greatest example is TypeScript : you can throw any untyped Javascript at the compiler and it will still infer the types allowing you to get great auto completion and to avoid logical bugs. Why would you prefer to not have this feature ?

For me, compile time checks aren’t even the real feature, I’d even say that they are useless because they come after the real features of typed languages which is your IDE proposing auto completion that is guaranteed to work. It’s an incredible way to discover the APIs when you know that something must exist but you don’t know how it’s named.

But I’m open to be proven wrong if someone can give me practical examples in which types are counterproductive.

mstipetic
2 replies
1d2h

If elixir had types, I'd use them. Right now I'm using it for functional programming aspects, coherent design across libraries, liveview, and the amazing OTP library. Those to me are much more important.

With proper discipline you can get a lot of type-like behavior if you use structs to represent your data and ensure they're being passed in function args through pattern matching.

keep_reading
1 replies
1d1h

it's waiting for you

{:type_check, "~> 0.13.3"}

mstipetic
0 replies
1d

Feels like it's still in flux/research phase

kelipso
1 replies
1d3h

Frankly, we really need to instill the "types are cool" concept into inexperienced engineers. That insanely long phase in software engineering where people said dynamic types are cool was a huge mistake and ruined a lot of newbie minds.

sph
0 replies
1d3h

"Think of the chil^H^H^H^Hinexperienced engineers! We must save them from PHP and Python!"

Enough pearl clutching. No one's mind was "ruined".

kaashif
1 replies
1d3h

As if writing in Typescript would produce less buggy, more stable or more maintainable applications than using Elixir.

I have news for you. A lot of people, including me, do know that catching an entire class of bugs at compile time makes your code less buggy.

The trade-off as usually stated is that more things are possible with more dynamic code, and statically typed code is slower to develop with.

Elixir has much more interesting features that have nothing to do with the types/no types discussion and I 100% agree it would be more interesting to discuss those instead.

sph
0 replies
23h41m

Elixir has much more interesting features that have nothing to do with the types/no types discussion

My point exactly. Sidetracking every Elixir discussion with complaints about type (especially when they are actually working on it!) gets tiring quick, when Elixir is much more than "just" a dynamic typed language. It's literally missing the forest for the trees.

lucasyvas
1 replies
1d3h

To be fair, it's the author's fault this time. They brought it up at the very beginning in the third paragraph.

The author's joy will also be short-lived because static typing is coming and will likely win out if the implementation is solid.

bo0tzz
0 replies
1d3h

The upcoming typesystem for Elixir will be a gradual type system, so you will not be required to write any types even after it lands (and you will still benefit from the typechecker either way).

weatherlight
10 replies
1d12h

because of unification/pattern-matching you have a pretty good idea, just looking at function name + args what the shape of the data is going to be.

artdigital
7 replies
1d12h

As someone who worked with Elixir for the past couple years, and maintains multiple libraries in Elixir - nah not really. Static typing isthething I'm missing with Elixir.

No matter how much pattern matching you do, and how many typespecs you add to get a better understanding of what's behind a variable, you'll still run into issues at runtime frequently that could have been avoided if it was statically typed.

Dialyzer is great but typespecs and pattern matching only get you so far. You'll always run into situations where the shape of data is not clear, and you have to open a REPL to do an IO.inspect somewhere

h0l0cube
3 replies
1d11h

You'll always run into situations where the shape of data is not clear

If you're using typespecs, then I think the deficiency is with tooling. I think the language servers (like ElixirLS) were quite buggy for a while, but it's getting better at code completion and inspection. But if the type has no spec then you're in the same situation as any gradually typed language.

59nadir
2 replies
1d6h

If by "defiency is with tooling" you mean that `dialyzer` is bad, then yes. The current type checking facilities that it provides are too lax and also sometimes demonstrably actually incorrect even in the face of the simplest examples.

h0l0cube
1 replies
19h25m

incorrect even in the face of the simplest examples

I haven't found this in my experience. Most issues arise from a lack of typespeccing. If one were to rely on type inference, then, yes, it's not going to catch much. Specifying types is arequirementof a strictly-typed language, so to make a claim of deficiency with Dialyzer's type checking, you'd be comparing code that's fully specced with that of a strictly typed language.

The unavoidable problem is when using libraries that aren't properly typespecced, but that the same story as any gradually typed language (e.g., Typescript). The only solution here is to make a PR or a feature request to the product owners.

59nadir
0 replies
6h29m

I've used dialyzer since 2015, it's not a question of "holding it wrong". I have an example of this that I literally demonstrated live in a talk online. It's very likely you haven't used dialyzer enough if you think it's actually correct 100% of the time even with type specs. Dialyzer is an exceedingly poor implementation of static type checking and not sufficient with any level of use.

weatherlight
0 replies
1d3h

That’s okay. I’d rather do that once in a while to keep all of elixir’s dynamic traits. The fact that you can open a REPL, and open one in prod, do language introspection, inspect data, query DBs with ecto, do hot code swapping is amazing.

Until we have something like Set Theoretical Types, I think this is the best of both worlds.

kimi
0 replies
1d10h

I miss static typing for two separate and quite opposite cases:

* trivial errors, that still cause a crash and waste my time ("foo(:yo, 7)" but was "foo(7, :yo)") - sometimes spotted by Dyalizer

* complex nested structures. In Java I never have surprises as to what foo.bar.baz is and I can use autocomplete reliably. Expressing the same invariant in Elixir is something less straightforward

hosh
0 replies
1d10h

The fact that you _can_ open a REPL in production and inspect the data at runtime is huge.

Although few people use hotloading in code before, shapes of data can change from deployment to deployment.

ryanjshaw
1 replies
1d11h

I'm building a static analyzer for Solidity in F# and the data shape of Solidity AST nodes overlaps frequently enough that explicitly specifying types is necessary just to get things to compile.

I can't imagine building something like this in a dynamically typed language. The way I see it, static typing is like writing inline unit tests to save yourself many, many headaches later.

weatherlight
0 replies
1d1h

types aren't a substitute for tests.

    let add : int -> int -> int = fun a b ->
      Random.self_init ();
      Random.int 100

rishav_sharan
8 replies
1d11h

I just moved from typescript to javascript and for me it was just that I own the database, i own the api surfaces and as such I don't need to enforce any kind of type checking as the api schemas are sufficient for my case.

I would definitely use type safety if I had a lot of external data sources. or if there are lots of people working with me. Otherwise, I am beginning to go back to dynamic languages at least for web dev.

hosh
3 replies
1d10h

I'm currently working on a data engineering team, unborking some things on a team where all the original developers of the codebase had left. Up until then, I wrote Ruby for over 10 years, and Elixir for 3. I didn't have an opinion about JS or Typescript before this project.

Typescript does not solve the fundamental problems of JS. I'm not convinced it really solved the issues related to ingesting data from many different data sources. The data quality issues were still there.

If I were rewriting the whole thing, I'd rewrite it with Elixir (of course), if only to have a sane way of handling errors.

aerhardt
2 replies
1d4h

I'm not convinced it really solved the issues related to ingesting data from many different data sources

That sounds like external data validation and I don't think a type system can really solve that. Even if you're using C#, Java, Scala, or what-have-you, you're going to have that issue. If that's what you expected from TypeScript, then yea, I can see how you'd be sorely disappointed...

Like many others, the advantage of type systems for me is in how they reduce cognitive load thanks to their explicitness, even in solo projects. I literally have a hard time remembering the types returned by a function I wrote a mere few hours ago... I have come to believe that there are two broad types of dynamic typing programmers: those who don't know better, and those who have a superior working memory, or cognitive ability, such that types hinder them rather than help them.

hosh
1 replies
1d3h

It is not as if I expected Typescript to be promising for external data validation. I was watching what peoplesayabout Typescript, and how people actuallyuseTypescript.

I wrote Ruby with duck-typing for 10 years and it never seemed to be a cognitive load for me. My working memory has been degrading as I age. My Ruby code became increasingly written in a functional style. Maybe it's in how I write? Small functions, minimal (or no) side effects, composed together with names that describe how data is transformed.

Explicating types hinder me. Where it had really started becoming more useful was explicit types in functional programming, such as defining monoids or lattices, or whatever, on those data types. My experience with Typescript and even Crystal is that the static typing only yields a fragment of the benefits without being able to define operators that go with those data types. Even the Just/Maybe monad would have helped with messy external data, since that would explicitly define ambiguous data that can be progressively refined into clean data types.

I'm excited to see the new static typing effort in Elixir. It's theoretical base is a set, which, I think, will work better with how people use Elixir in production. It'll be interesting if the Witchcraft (ML ideas in Elixir) will work with those.

aerhardt
0 replies
1d3h

I am not an Elixir user but I too am watching the type story develop with a lot of interest. Even something half-decent in the vein of Python types would do it for me.

sensanaty
1 replies
1d6h

I don't really write huge complex types in TS, I basically stick to just the native data objects like string, number, boolean etc., but even then I find it so useful just for the autocomplete that you get out of it.

I jumped into some code I haven't touched in half a year the other day so had 0 recollection of any of it, thankfully cause of the types I knew exactly what to pass where and what to expect back without even having to read any of the code other than the type definitions.

I love me some dynamic languages, but damn if it isn't nice to have that kinda power available to you.

conradfr
0 replies
1d6h

You can have strict/strong typing with a dynamic language.

And after all your Typescript code is compiled to Javascript.

MrJohz
0 replies
1d11h

That's an interesting decision, because it's the reverse of one of the big complaints about Typescript: that it only works up to the API boundary, and doesn't include external data sources (unless you use libraries like Zod to combine runtime and static type checking).

For me, Typescript is more useful, the more of the codebase I "own", because it means I can be more confident that all the types reflect the true types of the runtime data, which means I can change things more confidently and quickly. Do you find that you're refactoring and changing things less with dynamic languages? For me, I think that's the number one magic feature that I miss when I use languages without explicit type systems.

Kiro
0 replies
1d8h

That only works for people with super memory. I already forgot what the code I wrote yesterday does. If you showed me code I wrote a month ago I wouldn't even know it was me who wrote it. I could never rely on just remembering API surfaces.

mijamo
8 replies
1d10h

I think it vastly depends what you're writing. Any kind of function that does not have a fixed input and output gets a lot more complex with static types. And by extension any code that depends on that also gets more complex.

I tried at some point to use Rust for an API but then I depended on making calls to a very complex API. In JavaScript I would have just gotten back a complex object where I can then pick whatever I want progressively through object access methods. In Rust I ended up with more than 500 lines of type definition for the API and it still wasn't enough so I gave up. It is a bit extreme but when you work with an API from an ERP for instance you can get very very complex and extensive types that are not in your control and not very well specified.

Another good example is how complex all ORM internal code get once they try to add static typing. The typing in the ORMs code feels like black magic because they would really really need types as code but don't have it so have to rely on a bunch of crazy generic combinators.

olivermuty
2 replies
1d9h

Elixir dev here, just to put the context in place first hehe.

Couldn’t that thing be typed as the web format? A nested set of string props with either string or number types in the leaves.

Then use those types to traverse and pull into «real» types?

I like to put structured data into structs in elixir too and the above is essentially what I would do in Elixir.

I don’t know rust well enough to see if I am missing some nuance

miroljub
1 replies
1d8h

You can do that in every language, even in Java 1.0, by just using a hash maps of objects, and cast those objects to whatever you like at runtime before accessing them.

But then, you are basically throwing out your static type checks and just using it as a dynamic language, but with much more verbosity, cruft and additional ways to should yourself in the foot.

josephg
0 replies
1d6h

Yep. It’s awkward. The language fights you every step of the way and it becomes hard to read and write your code. x.foo = 6 becomes x.set(String(“foo”), Num(6));. When you read that value back you’ll need to unwrap the type you expect before you can do anything with it. It would be utterly miserable. You’d be much better off just using Python, JavaScript or Ruby.

You also lose all of the performance benefits typing brings, and gain nothing in return. In JavaScript land, V8 moves heaven and earth to guess what your types are and optimistically compile your code behind the scenes assuming its type annotations are correct. Then it dynamically deoptimises and reoptimises at runtime with that new information, while your program runs. As well as being ugly, the equivalent “dynamically typed” rust program would have none of V8’s smarts. It would run dog slow compared to normal rust and still way slower than the (much cleaner) JavaScript equivalent.

Like wood, programming languages all have a grain. If you program in harmony with the language’s design, everything will seem easy. Compiler errors make sense. The standard library will seem useful and well designed. Program against the language’s design and you’ll hate every minute of it.

knallfrosch
2 replies
1d8h

Any kind of function that does not have a fixed input and output gets a lot more complex with static types.

If you don't know what kind of data people give your function and you don't know what's supposed to happen, how can you write that function? I think many people use too strict of a type system. If your function works with any object that has a toString()->string function, then just write an in-line interface that defines it.

I actually love TypeScript here. It allows for `any` if you're prototyping, lazy or simply don't care. It allows mapped types, where the next dev can see how a type came into being - for example, Mutable<T>, Readonly<T>, Required<T>, Partial<T>. The names actually speak for themselves! And it eliminates the Java-style verbosity of creating classes and files all just for a type.

mhitza
0 replies
1d8h

I prefer dynamic types when I prototype and hack on code.

I'd prefer if dynamic languages would converge to gradual typing support, and static languages to gradual dynamic support. TypeScript is an example of the later, and PHP of the former.

_flux
0 replies
1d6h

You perhaps know, but I believe one should prefer the "unknown" type in TypeScript in such scenarios. Of course, then you need to check what its type actually is to make use of it, but this time TS checks that you do.

Btw, the equivalent in Python (and MyPy/pyright) is object.

rTX5CMRXIfFG
0 replies
1d8h

The perceived difficulty of static typing depends on the type system itself. For example, there was a version of Swift where it became extremely painful to work with String and Substring, or Array and ArraySlice, which you’d intuitively just pass around whenever you’re making smaller pieces of collections but which the compiler complained about during type-checking when you are substituting one type for another. They solved the problem by just defining a protocol such as StringProtocol (and just reusing Sequence for arrays I think) and using that protocol wherever parameters are passed around, so it became possible again to swap those types for each other.

So then there’s more code for the language devs to write of course, but that’s just the cost of safety, which is highly desirable if you want the technology that you are building to be attractive for use in systems where correctness is critical, which also tend to be highly valuable. As a working professional it’s in my best economic interests to have such valuable tools in my skillset.

mdx97
0 replies
1d9h

I tried at some point to use Rust for an API but then I depended on making calls to a very complex API. In JavaScript I would have just gotten back a complex object where I can then pick whatever I want progressively through object access methods. In Rust I ended up with more than 500 lines of type definition for the API and it still wasn't enough so I gave up.

You can always deserialize things as `serde_json::Value` instead of making types for everything to get similar behavior out of Rust.

prophesi
4 replies
1d3h

Does José need to write up an elixir-lang.org blog post every other week on the status of their type system project for HN's collective memory to know it's in the works?

keep_reading
3 replies
1d2h

While you're waiting for official support in the language, just properly document functions with @spec and change them to @spec! after adding TypeCheck to your project and viola, you get powerful type checking at runtime with almost no performance impact. The error messages it produces are so beautiful.

https://github.com/Qqwy/elixir-type_check

conradfr
1 replies
1d1h

In a functional language where you're writing a lot of functions it's a bore and feel very dated.

Especially as you have to write the function name so copy/paste from other @spec doesn't really at least speed it up.

It is what it is I guess.

keep_reading
0 replies
1d

well, you can avoid this if you try to limit the number of public functions so you don't have to do this as often. make as many defp functions as possible, really.

satvikpendem
0 replies
1d1h

and viola

Nice to see you are a musical aficionado too. More seriously, how does this compare to other type checking alternatives for Elixir/BEAM were I to start a new project, including Gleam and Witchcraft (which at least seems to be unmaintained for now)?

pleoxy
3 replies
1d2h

It does slow some of us down. It's not really about terseness. I can write code that works on all primitives that might be sent down pretty easily. That code, sometimes is longer than limiting the inputs by types would be. I can also write code such that it only runs if the structure of the data is as required for that code to run, allowing for nulls or missing nested objects.

These two patterns allow you to write most code, type free, that gracefully handles anything you throw at it while always doing the right thing.

Making changes to such a system is easy and friction free.

Not many type advocates speak of the downsides of type systems, always pitching the net win and ignoring the actual cons.

When you refactor, make a change, or try to add new functionality, and end up fighting the type checker. That's friction to change you are experiencing and that experience is optional.

I get that having discipline in code patterns and the required robustness is a difficult ask at some organizations and some devs. In that circumstance it's better to have a minder in a type system that enforces base the conventions for everyone.

lolinder
0 replies
1d2h

When you refactor, make a change, or try to add new functionality, and end up fighting the type checker. That's friction to change you are experiencing and that experience is optional.

I don't really see that as "fighting the type checker", I see it as the type checker doing its job and warning me of the places where my refactor broke things. The alternative isn't usually that my refactored code magically works, it's that I have to manually grep through the codebase looking for all the places where I might have broken something, and get runtime errors if I don't catch them all.

In that sense the experience of struggling to make a refactor work isn't optional—the choice you get is whether you want the compiler to assist you with it or not.

I realize there are exceptions forcertaintypes of refactors to certain types of functions, but the vast majority of patterns I've ever seen in any codebase—static or dynamic—are patterns that are difficult to refactor without a type checker and trivial to do with one.

To be clear, there are other reasons to prefer dynamic typing, and I'm not trying to say you're wrong to prefer it, but you're not going to get very far trying to persuade a static types fan thatrefactoringof all things is better in the dynamic world.

cglan
0 replies
1d2h

Making code that works on all primitives and accounting for nulls/empty each time is way more difficult than using a type system.

That’s the same argument people always use. “If you account for every case and also have 30 billion unit tests you can avoid all the problems”. The reality is, people don’t. They cut corners, they forget, or they simply make mistakes.

Not only that, debugging a system without types is a terrible experience, and IDEs don’t offer nearly the same level of refactoring support for untyped languages bc it gets very hard or impossible to infer what’s going on.

If it’s a personal project or a small script, untyped languages are fine. Any other scenario you should be using types

Munksgaard
0 replies
1d2h

When you refactor, make a change, or try to add new functionality, and end up fighting the type checker. That's friction to change you are experiencing and that experience is optional.

I'm not sure exactly what you're saying. If your language is strongly typed, you'll get type errors no matter what. The only difference is whether the type errors happen at compile time or run time. Let's take a hypothetical example:

Let's say I have a programming language called Foo. There are two ways to run programs written in Foo, using the interpreters A and B. A and B are identical, except for that fact that on startup, A will check that the given program is well-typed (static type checking), while B defers such checks to runtime (dynamic type checking).

Given a well-typed program X, I can run X with A or B without ever encountering a type error. Now, I make some changes, like you suggest, and I attempt to run it again. If the resulting code is not well-typed, I will immediately know when trying to run it with A, but with B I have to be lucky enough to hit the specific case that isn't well-typed.

If I understand you correctly, you're saying that you can easily make changes in a dynamic language without _ever_ causing run-time type errors. If that's the case, you would have _exactly_ the same experience whether you ran your code using A or B.

Dowwie
3 replies
1d6h

The lack of types is hard to defend. Yet, the failed pattern match triggered at runtime becomes immediately obvious from the stack trace. You fix the pattern and move on.

The cost of this mild inconvenience is still far less than the cost of satisfying types.

This aside, I want typed elixir.

bradrn
1 replies
1d6h

This aside, I want typed elixir.

It’s happening:https://elixir-lang.org/blog/2023/06/22/type-system-updates-...

Dowwie
0 replies
23h57m

They're taking baby steps with the roll-out. It's not going mainstream any time soon.

epiccoleman
0 replies
1d3h

I love elixir, but I would also love it more with a sort of laissez-faire type system akin to TS. Glad to see they're working in that direction.

One of the best features of type systems is they make editor completions and navigation work better. Elixir's LS is pretty good, but editor support just isn't nearly as good as what you can have in a good (read: Jetbrains) IDE with a strongly typed lang like C# or Java.

liampulles
2 replies
1d2h

I think loose typing helps to prototype faster, while static typing helps you write the correct/safe version faster.

But part of doing the correct version is clarifying spec, and prototyping can help with that - so it is a weakly held opinion.

mrcwinn
1 replies
1d1h

I could not disagree with this more. You are aided in prototyping by forming an early opinion on your data models. I would argue there's nothing more important in conceiving of something new than understanding the shape and relationships in your data. Typing does that.

And nothing slows a developer down more than accruing technical debt as they build. It's like having tar stuck to your shoes. You will work the fastest when you have nothing to pay back because your mental model of the application is aligned with the intention of your program.

(That said, I don't think you necessarily need a strong static type system to achieve these aims.)

EarthLaunch
0 replies
1d

Maybe it depends on what you're prototyping. In web dev I see what you mean.

But in game dev I'm often prototyping something to see if it works at all, or to check its performance. Ignoring types is faster when spending 1-2 hours/days quickly hammering out something that just barely works. On version 2 or 3, add typings.

Maybe it also depends on the timeframe of the prototyping project. After a few days it can become tech debt. (Though I still suspect there are some long term advantages to untyped.)

whalesalad
1 replies
1d12h

static typing is a means to an end. if you can achieve the same end without static typing, good right? that is the goal of spec.

the creator of the language has a fantastic talk on thishttps://youtu.be/giYbq4HmfGA?si=LgSHZupSuR-kMXmj

magicalhippo
0 replies
1d10h

For me, a huge part of it is that I find static typing to make the code a lot more self-documenting.

I can easily see what is passes or returned, and if I'm unsure about the details of the type the answer is a click away, or a short web search away at worst.

Significantly reduces my mental load, allowing me to be vastly more productive.

threatofrain
1 replies
1d9h

I think static typing (without escape hatches) slow you down when you're a library or framework author, or you're doing something high performance. The reason being that there are many trivial and non-trivial propositions which the field has ironed over but the core language/compiler team hasn't caught up yet.

I've seen a lot of authors do crazy type things to get around the type system (like typing out recursion to the n-th level by hand), and I think many open source projects are slowed down by the lack of a type wizard on their team.

curtisblaine
0 replies
1d9h

In my experience, static typing greatly slows you down when you're prototyping, at least for a short time, then it moderately speeds you up when you're productionizing and maintaining.

peoplefromibiza
1 replies
1d7h

I really don't like not knowing what format data is in.

Which is orthogonal to what the type is

The shape of the data is much simpler to handle in Elixir than in, to name one, Java.

a vast number of possible errors caught at compile time

if it's a vast number, usually it's because either:

- you're not familiar with the code base (and you'll make a vast number of other kinds of errors)

- you're making a huge refactory and you're used to rely on a compile-driven workflow, but there are so many alternative ways to handle them

things go wrong in production

the usual wisdom applies here: static typing does not replace input validation, be it user provided data or function parameters

solidninja
0 replies
1d5h

Static typing can replace input validation though - if you make illegal states unrepresentable. That way you bake validation into your types e.g. using refined types:https://blog.rockthejvm.com/refined-types/in Scala

passion__desire
1 replies
1d12h

Does the code really need to be verbose? Scala does a pretty good job. Infer once at first declaration and enforce throughout.

jb1991
0 replies
1d11h

As does swift.

hahn-kev
1 replies
1d5h

I actually think it's pretty similar to different automated testing camps. Some people say they build faster with TDD, and others say it slows them down.

jacquesm
0 replies
1d4h

Usually it is because people have a short term view of software, but in practice software lives for much longer than most people can imagine at the time of writing and that initial burst of productivity when working on a new system is even more present in a type-free and test-free environment.

But once that honeymoon phase is over you usually realize that types and tests were invented for a reason and beyond a certain level of complexity they are absolute must-haves if you want to have high confidence it all works as advertised and to be able to effectively refactor your code.

realusername
0 replies
1d9h

Elixir is a bit in the middle, with the massive amount of very specific pattern matching for each function and the fact that modules are just plain collection of functions and not objects I would say it's the most static of dynamic languages.

They are working on typing it now from the blog posts I've seen and they will probably be successful because the language is well suited for that in my opinion

jwells89
0 replies
1d10h

In my experience, static typing takes a different way of thinking that can take a while to get the hang of, and during that adjustment period a lot of people are going to significantly slower. I definitely felt it coming into Swift, being used to Objective-C and to a lesser extent Ruby.

Having grown accustomed to static typing, not encountering errors until runtime, or worse having errors manifest as type-related misbehavior and potentially not be immediately apparent is much more frustrating than it used to be.

jddj
0 replies
1d8h

Better type inference is faster than more ceremony, but more ceremony is faster than nothing at all, in moderately complex projects.

gampleman
0 replies
1d6h

An important thing to realise is that "static typing" isn't just one thing. The details matter. For instance, type inference is a huge deal in making static typing not painful. Local type inference is something that pretty much all modern languages have adopted, since it makes writing out function bodies much less painful. But I think a lot of static typings bad rep comes from older languages that required lengthy annotations everywhere.

Then you of course have global inference, where you can write code as tersely as in a dynamic language, but still benefit from type checking and add annotations later as a form of documentation for readers.

It also changes the way you code. The best experiences from static typing come IMO from doing type-driven development, where you sketch out your problem first at the type level, then fill out the implementation at the value level. In dynamic languages, you can't program like that. So if you use the same mindset you will find the language limiting.

dartos
0 replies
1d3h

Static vs dynamic types are whatever.

Weak typing is what causes all sorts of issues.

With dynamic strong types, you can still have a tool like dialyzer figure out potential type issues before shipping, but weak typing means anything goes.

csan_gonzo
0 replies
1d9h

I've been using Elixir for over a year now and the only thing that's missing for me is a static type system, really looking forward to this:https://elixir-lang.org/blog/2023/09/20/strong-arrows-gradua...Also keeping an eye on Gleam:https://gleam.run/.

camgunz
0 replies
1d

It's really hard to prototype w/ static typing. It's not really about mechanics; annotating parameters or return types, that stuff's easy. The problem is that in prototyping you're changing a lot of stuff because you don't necessarily know what the structure or types will look like, and every time you change something or rethink your taxonomy you have tons of type updates to do.

andrewstuart
0 replies
1d6h

It slowed me down until I had enough experience then it sped me up.

zoogeny
34 replies
1d11h

I have been watching Elixir YouTube videos pretty much every day for the last few weeks. I guess there was an Elixir conference recently and after I watched a couple, YouTube has been sending me a consistent stream of Elixir content.

I really want to try out this language. I love the idea of Erlang but the few times I've had to deal with it (an ejabberd chat server was one) I found it to be a bit too quirky. Every video I've seen with Joe Armstrong leads me to believe he was an under-appreciated genius. Isolated processes and message passing (Actors) seem a good candidate for the future of distributed programming (see this recent video from Crockford on his new Misty programming language [1] - notice how the questions were about Elixir/Erlang). I love pattern matching and elixir uses this to a high degree.

However, I am not 100% sold. Clearly this community punches above its weight, and the BEAM is obviously no slouch and is a brilliant choice for a platform to build upon. But I get concerned looking at the magic of LiveView (and LiveBook). My experience is that if something sounds too good to be true, it often is. A lot of the jargon is also totally unfamiliar to me - things like GenServers and other esoteric kinds of platform specific knowledge. It feels like stepping into a one-way portal, I'm not sure any knowledge in that universe is transferable.

There is a huge risk in niche languages and platforms. Hard to hire for, hard to find libraries for, hard to find blogs/tutorials/etc. With alternatives like Go having a pretty respectable concurrency story ... it is pretty hard to justify taking the risk on such a small community.

But kudos to that community. It is honestly impressive to me what they have achieved. I'm also very excited to see what happens with their type system implementation.

1.https://www.youtube.com/watch?v=R2idkNdKqpQ

jb3689
8 replies
1d10h

You are overthinking some of it at least when it comes to concurrency. Look at what a process is and how send works. GenServer is a natural generalization of a pattern you’d write a thousand times. Knowledge of actors is transferable. Go has libraries which implement actor abstractions for example. Process mailboxes are just message queues like Go’s channels are. There are differences with respect to how the interpreters work and how processor yields work.

Stuff like LiveView though looks like magic because it is magic. There are a lot of moving parts involved in getting it working. It’s the result of work that has been going on for the past decade across multiple communities though. The ideas are mature even if there is a lot of abstraction.

Stuff like Riak was well ahead of its time. They basically had the idea of being able to create robust distributed systems much the same way you would a GenServer.

brandensilva
3 replies
1d

I was gonna say the actor model stems from state machines I believe. It's a nice way to manage state and communication. It reminds me of supervisors and processes in general but not program language specific.

hosh
2 replies
21h59m

Erlang developed the way it did before people started calling it an Actor model.

The key characteristic is not a state machine, but that:

- first class processes send messages to each other

- messages are queued

- each process is single execution flow. If you want to reenter code, start another process and send messages to it

- process execution can be preempted

- values passed in messages are for the most part, immutable.

- first class support for “links”, where one process gets notified when another process crashes (basis for supervision trees)

The consequences of this design are:

- for the most part, you don’t need mutexs

- spin locks are cheap

- every process can be suspended indefinitely when nothing is in the message queue. This is better than an async reactor.

- processes don’t get “lost” (I am looking at you, Nodejs)

- processes can receive control messages to suspend or shutdown, restart, etc. Most other platforms have to externalize that to say, K8S and such controls are crude.

- errors don’t get “lost” (Nodejs again …)

- repl in production, can inspect the whole system live, under load

- overloaded systems degrades gracefully instead of locking up

az09mugen
1 replies
11h41m

Erlang did appear after the creation of the actor model. The actor model is from 1973 :https://en.m.wikipedia.org/wiki/Actor_modelAnd Erlang is from 1987 :https://fr.m.wikipedia.org/wiki/Erlang_%28langage%29

hosh
0 replies
42m

https://softwareengineering.stackexchange.com/a/277469

Looks like I misread it. While the Actor model was conceived before Erlang, the Erlang actor model was developed in parallel. It isn’t a pure implementation of Actors (everything is an Actor, making it closer fo Smalltalk). Only processes are Actors. It also implies that Akka is not a true Actor model as conceived in the originao ‘73 paper.

This goes into greater detail on the history:https://www.labouseur.com/courses/erlang/history-of-erlang-a...

In any case, there are not many contemporary systems that uses these ideas.

riffraff
1 replies
1d10h

Why do you think riak was well ahead of its time? (actual question, I'm not arguing)

IIRC it was a few years after the dynamo paper came out, and at a time when a bunch of other nosql+high scalability solutions did (e.g. Cassandra)

macintux
0 replies
1d2h

I suspect the parent comment is primarily referring to Riak Core, which was another layer of abstraction above Erlang’s OTP for distributed processing.

Riak the database used Riak Core, but it could be used independently of the database.

I hadn’t thought about Core in a long time, I should take another look.

Looks like someone is carrying the idea forward:https://riak-core-lite.github.io/

baq
1 replies
1d9h

Riak was pretty bad at ops. Leaving and joining nodes took ages and god forbid you tried to use any of the added features like solr search. If you settled on a very small subset of all features it worked nicely... it just wasn't very useful if anything went wrong due to app or user error.

hosh
0 replies
19h29m

I think that was before things like raft or paxos

I had some similar issues with rabbitmq

On the other hand, Phoenix channels were much more flexible about membership

throwawaymaths
6 replies
1d11h

looking at the magic of LiveView (and LiveBook)

What's the magic? I think it's pretty easy to get a correct mental model of everything in livebook maybe excepting exact details of how the diff calculation/data compression works. Even so, you can spy on the websocket messages and get a reasonable picture of what's going on in a pinch.

Liveview is incredibly straightforward.

zoogeny
4 replies
1d10h

Liveview is incredibly straightforward.

I don't agree. One of the keynotes from the 2023 ElixirConf was Chris McCord (one of the principle developers of LiveView) describing how it isalmost1.0 [1]. One thing that made me laugh a bit was him emphasizing how much Javascript he's had to write (he was referencing the fact that there is an internal community meme that you can achieve such incredible behaviorswithout writing Javascript). His quip was "because I wrote it all". I wonder if you asked him "was it straightforward?" what do you thinkhisanswer would be?

There are a lot of videos of people talking about how they managed to write something in LiveView. Here is one from 2022 "How I built a block based editor in LiveView" [2]. That is a good one to see how non-trivial tasks can be difficult in LiveView, describing a few times how he had to fight with it to get it to kinda-sorta do what he wanted. Certainly this man will achieve his goal since he is smart and motivated, but his description of his journey does not lead me to a conclusion of "this is incredibly straightforward".

This is impressive tech no doubt, but it is far from clear it is currently reliable enough to stake a startup on. Another tangential issue I have with LiveView is the obvious requirement for a persistent socket connection ... which leads me to wonder how one would approach local-first type developments. Again, certainly possible but definitely not straightforward.

1.https://www.youtube.com/watch?v=FADQAnq0RpA&ab_channel=CodeS...

2.https://www.youtube.com/watch?v=7yZwxsG7tVs

toolz
0 replies
1d5h

This isn't really contextualizing the problem space well imo. How many companies exclusively used react pre-1.0? How many people using the "straight forward" vueJS had ever read the source code to understand the internals?

When someone says that liveview is straightforward, they aren't comparing it to stable backend languages that almost exclusively run on one operating system and one architecture and they certainly aren't referring to the many hacks every JS library incorporates to make the library more useful.

throwawaymaths
0 replies
23h14m

I think we have different definitions of straightforward. Liveview is straightforwardto usebecause of Chris mccords effortandhis good taste in software designandhow a genserver is a good framework for state management.

rkangel
0 replies
1d5h

I suspect that you might be right about using LiveView for things that are traditionally full, rich client side JS apps.

However, it is absolutely awesome for the "slightly javascript" case of a lot of UIs. Two examples, from my work:

Forms with "live" display of validation errors, using one single set of validation on the backend, rather than the duplicated frontend and backend having to match. It's completely trivial to implement with LiveView.

Status displays - We built some development hardware based on a Xilinx Zynq FPGA (FPGA + ARM running Linux) and used LiveView to report a lot of the hardware state - primarily the status of all of the registers. A little fiddling with HTML+CSS for the register widget, but then everything else could not have been easier - render your widget once per register, and rerun that whole thing any time pubsub provides an updated register value.

porker
0 replies
1d10h

LiveView is optional though and IMO is still overused for tasks that would be better accomplished with client side JS.

Where this gets messy is mixing LiveView and client side JS, and I need to experiment further with this (or find people who have).

thibaut_barrere
0 replies
1d10h

I find LiveView either straightforward or a bit complicated, compared to other solutions, depending on the exact use cases. It's not necessarily easy initially to grow you own way to properly handle some scenarios, and some people can find the mental switch not that easy (but in general, it has been very useful to me!).

hosh
5 replies
1d10h

I went from Ruby to Elixir to Nodejs.

I am writing Nodejs because I have to, not because I want to. Having used it now, I will never ever start a new project with it.

Nodejs's concurrency controls, ability to scale, tools for reliability and observability are so far behind from the BEAM ecosystem. I sometimes think people think Elixir is too good to be true because they're too used to platforms not designed to be resilient.

conradfr
3 replies
1d9h

Elixir is definitely a better Nodejs... that JS developers don't know about.

hosh
2 replies
1d4h

It took me months before it sank in that Nodejs async wasn't really async as I knew it from Elixir -- there's an implicit queue, and no true suspension of the execution flow.

One justification for this was that it is supposed to make it easier to reason. It made it more difficult for me to reason -- maybe single-threaded async reactor is a poor substitute for immutability.

Unhandled promise rejection is an example of a consequence of this design. That's not really a thing in Elixirby design. But in the Nodejs world, people don't even see it as a design flaw. It makes reasoning about reliability much more difficult.

skrebbel
1 replies
21h13m

One justification for this was that it is supposed to make it easier to reason.

It’s a valid justification because it makes it substantially easier to reason compared to mutable multithreaded languages/runtimes such as C(++), Java and C#.

Eg a semaphore in JS doesn’t exist. It’s just a boolean. Interlocked Increment doesn’t exist. It’s just someVar++. And so on, it’s very nice.

That doesn’t mean that there aren’t other setups (such as immutable data with message passing) that are even easier to reason about. Every new tech compares itself to the current mainstream.

hosh
0 replies
18m

You and I may know this, yet I have encountered smart people who defend a local maxima.

jacquesm
0 replies
1d4h

The whole reason Nodejs exists is because programmers eternally re-invent the wheel instead of accepting that there are already some pretty good wheels that they probably have no chance of matching.

thibaut_barrere
3 replies
1d10h

There is a huge risk in niche languages and platforms. Hard to hire for, hard to find libraries for, hard to find blogs/tutorials/etc.

There is a real need to push Elixir outside its initial circles and it's being done a bit at the moment (I feel).

Both Chris & José are doing a lot of work for exposure outside the initial Elixir circles, and some people in the community are doing the same at their own levels.

Hiring is not that complicated actually, because a fair bit of people want to work in the language (I experience that first-hand), and a good developer will be up-to-speed quite quickly too.

But the "niche" aspect must be tamed in my opinion, and is both a risk (for the language itself) and a short-term reward (being proficient in a niche something is usually quite good).

Champagn3Papi
2 replies
1d8h

I switched jobs and working as an elixir dev now. I love elixir don't get me wrong, but some of the documentation especially some of the more advanced features in ecto are very confusing.

It doesn't help you can define your ecto instructions in multiple flavors too (inline vs piping)

You can't mix inline with pipe operators without creating an additiona variable too hold the original query.

If we want to make it less niche, there's definitely good working points there. Once people understand how to hit a database from elixir it magically clicks and the other stuff is more trivial.

thibaut_barrere
0 replies
1d8h

Ecto is a specific area and I must say I share your view on the "flavours" aspect (keywords vs not). I would personally love if there was only "one way".

And agree that there are both excellent documentation, _and_ things that are kind of "assumed" and would need better "beginner" stuff (in my opinion).

di4na
0 replies
1d8h

Ecto documentation is definitely i think one of our weakest point.

Which is great on one hand, because it means we are quite above the average stack in term of onboarding and doc.

But also really makes ecto documentation and onboarding a visible sore point in the middle of the rest.

Sadly i do not have solutions rn but if people have ideas please come offer them.

victorbjorklund
2 replies
1d10h

I actually find the opposite to be true. Elixir is less "magic" once you learn it. I can see and understand what most things are doing and read the code. With javascript? Not so much.

On the point of hard to hire and hard to find tutorials. It is true. It is way harder to find for example someone that done what you wanna do in elixir vs javascript. When it comes to libaries it isnt so big problem. There are lots of libraries and so far I havent really encountered any problems. Only thing would be if you interact with an API they might provide a client library for javascript and python (but less common for Go) but not elixir. But honestly it is usually not so hard to use an API with just a http-client.

devoutsalsa
0 replies
1d8h

Elixir is actually the easiest language to read (for me), once I knew it. You can make it difficult to follow if you want to, but when people are using it to pass around plain old data structures, it's very legible. Speaking only for myself. YMMV.

agumonkey
0 replies
1h13m

an instance of simple vs easy

timwis
0 replies
1d5h

I have found the book _Programming Phoenix LiveView_ to be a great explainer as to what’s going on in liveview. It’s written for people new to Phoenix as well. I’m only halfway through and already building quite a lot with it, and, critically, I reckon I could explain pretty well what’s going on under the hood.

https://pragprog.com/titles/liveview/programming-phoenix-liv...

querulous
0 replies
15h53m

the big risk with elixir imo is that it's runtime/vm is still owned by ericsson and there's no alternative. i know things like firefly exist but they aren't mature replacements (to my knowledge)

jacquesm
0 replies
1d4h

The basic idea that infuses all of Armstrong's writings and work isreliability, not concurrency, that's just a means to an end to achieve higher reliability (and lower latency, which in the context of (soft) real time can be a failure condition if certain guarantees are not met.

hmmokidk
0 replies
19h22m

Live view has immensely less magic than react or nextjs.

In fact it's kind of crazy how much of it I understand given I haven't tried. The community is just all about simple tools and understanding them.

dorian-graph
0 replies
1d6h

There is a huge risk in niche languages and platforms. Hard to hire for, hard to find libraries for, hard to find blogs/tutorials/etc. With alternatives like Go having a pretty respectable concurrency story ... it is pretty hard to justify taking the risk on such a small community.

People say this every time Elixir comes up, but, I would like to hear evidence of this being true.

I worked at a startup for a couple of years and had never used Elixir. The majority of the engineers who worked there, whilst I did, also hadn't. We had a few who were experts in the language and a couple who had well-known open source packages.

Genuinely from my experience, each of the things in your list are simply not true.

But I get concerned looking at the magic of LiveView (and LiveBook).

What magic? Again, genuinely questioning this.

superdisk
15 replies
1d12h

For me the big sell of Elixir/Erlang is that it makes running "background jobs" a complete breeze with no concern for blocking IO bringing the entire server to a halt, especially in a web server context.

At my last job I had to do a bunch of HTTP requests in a webhook handler and if enough happened at once, the entire site would just crash due to all the OS processes being busy. I found myself desperately wishing I was just using Elixir instead because it would have been trivial to just spin up a Task to do it and move on.

jbmsf
13 replies
1d12h

Meh. I don't want background jobs to be a breeze in quite this way. I want background work to live on different compute capacity than http requests, both because they have very different resources usage and because I want to have state or queues in front of background work so there's a well-defined process for retry, error handling, and back-pressure.

I get it, of course, it'd be lovely if these complications didn't exist and the same framework handled everything... but I don't think a programming language or even a runtime gets you there. You also need monitoring and ops processes to be part of the solution.

throwawaymaths
4 replies
1d12h

You're creating a really difficult distributed systems problem then. What happens if the async request gets swallowed? Are you coordinating telemetry and tracing across these compute units?

Not all of us can afford elaborate ops teams

yuppiepuppie
3 replies
1d8h

Its really not that difficult to trace this stuff with modern APM tools. Datadog and Elastic APM support this out of the box for most languages/frameworks. And id be suprised if other big players in space didnt also.

throwawaymaths
1 replies
1d

Yeah that's fine but expensive for the tracing problem. You've completely ignored the harder bit which if you have any experience you know is a motherfucker of a problem: what happens if your async request fails, and notifies you, or, fails and forgets to notify you, or succeeds but takes way too long.

What sort of state management schemes do you have to put into place yo make sure your database isn't full of corrupted data that is going to crash you later (or, worse, silently violate an assumed invariant - and maybe black hole your money or your customers money)

The nice thing is that elixir gives you this either automatically or with a line or two of code.

yuppiepuppie
0 replies
23h48m

Not sure what the condescending tone is for...

I do have quite extensive experience with it. And it is a difficult problem.

Lots of frameworks/languages deal with them differently (dlqs, auto-retry, etc.), and each has its pros and cons. In addition, one should have to weigh how important each task is and determine if a 1 in million loss justifies having an extensive resiliency built in.

If Elixir has done that out of the box with a few lines of code like you say, great to hear. And Id love to try it out on day.

davidw
0 replies
1d2h

"Just use Datadog" is fine for a bigger more established company.

But it's a lot of expense and overhead for someone closer to starting out.

I do not think it's a "home run" kind of win, but it's definitely a "nice to have" that you can just run everything in one place, and worry about splitting it up when (if) you get bigger.

cultofmetatron
4 replies
1d11h

there's nothing stopping you from doing this but its a real game changer for an early stage startup to need a new service and the steps to getting that out is one file and an extra line in your config.

sph
2 replies
1d4h

Don't choose Elixir if you justlovesetting up autoscaled k8s on AWS with redis, RabbitMQ and half a dozen shenanigans for a webapp that serves 10 users a day.

keep_reading
1 replies
1d1h

Elixir is my excuse for refusing to entertain the idea of an k8s cluster at work. Completely unnecessary.

deviprsd
0 replies
13h8m

k8s solve a different layer of problems, to me they are a complemental tool to elixir when there is a need for that layer, otherwise yes it is completely unnecessary.

bcrosby95
0 replies
1d1h

I've only used Elixir at small companies, and it definitely feels like a superpower. I don't doubt that the Googlers of the world have no need for the language and runtime, but IMHO it really helps a small company punch above its weight.

thibaut_barrere
0 replies
1d10h

You can actually have "background jobs" in very different ways in Elixir.

I want background work to live on different compute capacity than http requests, both because they have very different resources usage

In Elixir, because of the way the BEAM works (the unit of parallelism is much cheaper and consume a low amount of memory), "incoming http requests" and related "workers" are not as expensive (a lot less actually) compared to other stacks (for instance Ruby and Python), where it is quite critical to release "http workers" and not hold the connection (which is what lead to the creation of background job tools like Resque, DelayedJob, Sidekiq, Celery...).

This means that you can actually hold incoming HTTP connections a lot longer without troubles.

A consequence of this is that implementing "reverse proxies", or anything calling third party servers _right in the middle_ of your own HTTP call, is usually perfectly acceptable (something I've done more than a couple of times, the latest one powering the reverse proxy behindhttps://transport.data.gouv.fr- code available athttps://github.com/etalab/transport-site/tree/master/apps/un...).

As a consequence, what would be a bad pattern in Python or Ruby (holding the incoming HTTP connection) is not a problem with Elixir.

because I want to have state or queues in front of background work so there's a well-defined process for retry, error handling, and back-pressure.

Unless you deal with immediate stuff like reverse proxying or cheap "one off async tasks" (like recording a metric), there also are solutions to have more "stateful" background works in Elixir, too.

A popular background job queue ishttps://github.com/sorentwo/oban(roughly similar to Sidekiq at al), which uses Postgres.

It handles retries, errors etc.

But it's not the only solution, as you have other tools dedicated to processing, such as Broadway (https://github.com/dashbitco/broadway), which handles back-pressure, fault-tolerance, batching etc natively.

You also have more simple options, such as flow (https://github.com/dashbitco/flow), gen_stage (https://github.com/elixir-lang/gen_stage), Task.async_stream (https://hexdocs.pm/elixir/1.12/Task.html#async_stream/5) etc.

It allows to use the "right tool for the job" quite easily.

It is also interesting to note there is no need to "go evented" if you need to fetch data from multiple HTTP servers: it can happen in the exact same process (even: in a background task attached to your HTTP server), as done herehttps://transport.data.gouv.fr/explore(if you zoom you will see vehicle moving in realtime, and ~80 data sources are being polled every 10 seconds & broadcasted to the visitors via pubsub & websockets).

olivermuty
0 replies
1d9h

If you want a language and VM that makes it easy to run jobs on different compute then boy do I have great news for you ;)

Running heterogenous loads on an elixir cluster is almost trivial. Certainly trivial compared to other languages. No external deps required.

keep_reading
0 replies
1d1h

I want background work to live on different compute capacity than http requests

The magic of Elixir/Erlang is that all of this logic can live in one codebase and you can choose when deploying your distributed cluster of Elixir/Erlang nodes which nodes run which tasks. The nodes are all aware of each other and when something happens that requires execution of that task it happens on the correct nodes because they're the only ones running those processes. Automagically.

ghayes
0 replies
1d12h

We recently switched from Rust to Elixir on a new service in no small part to this. The idea of sharing objects through Tokio async processes felt difficult compared to this being a first class feature of Elixir. It’s not that it’s hard, per se, but it felt harder to get right.

hartator
10 replies
1d12h

And still 0 successful startup has been built on top of elixir.

Supermancho
2 replies
1d11h

Real talk. HN posts on anything OTP continue to be the same echo chamber of responses, with most readers just leaving them to it. Many people have been trying to nicely point out that "uses Elixir in some places" is not the same as "built on Elixir". ie It's exceedingly rare for any system to have a secret sauce called Elixir and none of them have sparked a race to use it. How many decades before someone points out it's a dead horse?

From my few years off-and-on, Elixir is a nice syntax on top of Erlang. Erlang is intrinsically a flow-based system. Just because you can prove something is turing complete, doesn't make Elixir/Erlang a good general language choice. The no-side effect philosophy is a dead end. You just store state somewhere else anyway, so what have you gained? The current type system is problematic, at best, and everyone knows that. Decades have passed and the same tired phrasing appears in every paper and every talk. "dynamic, scalable language built on Erlang VM, designed for building maintainable, high-concurrency apps". It's clear that this isn't special anymore and it reads as desperate for relevancy, or left to rot. Either way, Elixir/Erlang is a specialty tool like Apache Nifi or CockroachDB. Niche, at best, a sub-optimal choice at worst, for most projects.

It's oft repeated that Elixir/Erlange tooling is "established". Whenever I have used the tooling or a framework (looking at you Phoenix), it's been primitive (Observer has gotten better), poorly implemented (IDEA, VScode), or requires a large amount of memorization to "learn" it. Not the language, the tooling. It's not enough to know Elixir or Erlang. You better understand BEAM (to some extent), shell scripting (just run it in a docker on windows), some glue technologies (something to build the UI, maintain state, etc), and then you can get down to building your backend application.

url00
0 replies
20h33m

Thank you for posting this, it also sums up some of my feelings. I would also stress that the Windows story with Elixir/Erlang last I checked was quite miserable coming from .NET. It's not the easiest thing to just fire up and try out unless you are in the *nix world.

Sorry you are getting downvoted by the hive-mind.

ashton314
0 replies
1d11h

The no-side effect philosophy is a dead end.

??? Erlang and Elixir have of tons of side effects. You must not either know the languages well—or maybe you mean immutability?

If you mean immutability, have fun building highly concurrent systems without it. The local reasoning and safety guarantees that immutability gives you makes building large scale applications sane—that’s the only way I’d want to program.

SamFold
1 replies
1d11h
hartator
0 replies
20h28m

SumUp backend is built on Go. They use Elixir only for some hardware things. It seems more like a toy thing for them.

Ref:https://www.sumup.com/careers/positions/

victorbjorklund
0 replies
1d10h

Yea, like that failure called discord. Is anyone even using discord?! What a failure!

lord-squirrel
0 replies
1d8h

Even one developer startups have had huge success using elxirhttps://plausible.io/

keep_reading
0 replies
1d1h

Why does a "startup" need to use it when giant companies already do? Nintendo, Apple, Toyota, PepsiCo...

dbbk
0 replies
1d2h

DICE is all built on Elixir and one of the biggest ticketing companies in the world but okay

ashton314
0 replies
1d12h

Hogwash. I used to work for one. Left to go back to school. They’re still going strong. Maybe I’ll go back some day.

cheema33
10 replies
1d13h

How do people switch programming languages? Established languages have massive ecosystems. Large set of libraries. For example, I cannot give up MS Entity Framework Core or Hot Chocolate graphql server for C#. Sure, there are alternatives, but nothing as feature complete.

Perhaps it is possible for applications that have small set of requirements.

h0l0cube
2 replies
1d12h

MS Entity Framework Core

Having worked with both EF Core and Ecto, I would gladly see the back of EF Core. Ecto is flexible enough to basically do everything you would with a raw SQL statement, but still use a relation mapper with it's validations. And if you have freeform output because you're doing a bunch of JOINs or querying a MATERIALIZED VIEW or whatever, you can just pipe that straight into a struct inline without having to declare a definition somewhere.

CharlieDigital
1 replies
1d12h

EF Core these days is insanely good.

It definitely has an initial learning curve, but once you've built a small sample app, it's quite easy to move ridiculous fast.

It still provides access to raw SQL and can always add in Dapper if you want/need more complicated queries. But productivity is really, really good with very little sacrifice in terms of performance.

h0l0cube
0 replies
1d12h

Iamusing it these days and I've found it wanting compared to Ecto. The only thing I think is great about EF Core is automated migrations, but in practice that's not where the complexity lies. It's in all the odd queries you need to make to satisfy the business logic as it evolves.

Edit: Probably the other good thing about EF Core is the designer, which as you mentioned is great for Rapid Application Development. Not really a time saver vs coding as the application scales, or if you prefer reasoning in code vs visually. Would like to see Ecto feature more user friendly tooling like a designer and automated migrations in the future though.

dimgl
1 replies
1d12h

For example, I cannot give up MS Entity Framework Core or Hot Chocolate graphql server for C#.

What? Why? Also, what do you mean nothing is as feature complete as Entity Framework? What about ActiveRecord, Ecto, Django ORM, Knex, even Dapper in C# itself......

cheema33
0 replies
23h3m

Do these replacements for Entity Framework Core offer first class support for Migrations, or temporal tables...

Many of EF Core replacements do a handful of things well. And after that, it is a cliff.

And now point me to a graphql server that is as feature rich and performant as Hot Chocolate.

Simpler applications will not have complex needs that require feature rich libraries. But, beyond a certain level of complexity, you are on your own. And large orgs do create their own tooling and libraries. But, smaller orgs probably should stick to languages that offer large number of libraries to handle a vast number of problems. Anything else would be putting yourself at a competitive disadvantage.

whalesalad
0 replies
1d13h

Elixir and Erlang are very well established ecosystems.

qaq
0 replies
1d12h

Erlang is fairly established 37 years young language and Elixir got to build on top of Erlang ecosystem.

lawn
0 replies
1d8h

You just have to learn to let go of your favorite frameworks and libraries.

If you do that then you'll often find loads of other amazing things that are better on the other side.

For example; maybe there's nothing like the MS Entity Framework Core, but instead you'll get to use OTP that everyone's always gushing about which may solve many issues you're having with your current tech stack.

Switching languages (and frameworks and libraries) is amazingly useful because you'll get exposed to solutions you didn't even knew you wanted.

john-radio
0 replies
1d12h

Perhaps it is possible for applications that have small set of requirements.

Well, for existingapplicationsit is extremely difficult, not because Elixir lacks many important features that C# delivers (although I'm sure it does lack some, and vice versa in a big way), but more just because rebuilding any project that's had hundreds or thousands of person-hours poured into it, that's currently satisfying hundreds or thousands of business requirements which may or may not be documented, is a huge project with few rewards; the investment is huge and the return on investment is... I mean, being on {sexy new language} is nice, but nobody's paying you for that.

But that's not what the OP's job is talking about. They just got a different job using Elixir, and are learning the technologies the same way anyone else does, and they're excited about this instance of it enough to write about it.

bradteamworks
0 replies
1d12h

I used C# before using Elixir. I also thought Entity was awesome. But Ecto and Absinthe are even better from my perspective.

gigatexal
8 replies
1d12h

“In fact, I might go as far as saying that Elixir gives you a fun language (like Ruby) while leaving out the stateful footguns OOP languages give you. There are no classes, no instances, no inheritance…it's immutable and functional and you're not bogged down by a static type system.”

I want this but with types. I’m convinced strongly typed is the way to go for larger code bases as it hides the magic of a lot of things and is easier to reason about.

kimi
3 replies
1d10h

I'm a contrarian here. I really wished we had inheritance in Elixir for GenServers - because thoseareobjects, interacting out of messages and not just glorified structs with associated functions.

So I wish I could have a generic template for a project's GenServer (for basic common registration, memory configuration, logging), that is specialized for a specific task, of which there are three flavours.

Speaking of footguns, Elixir patches this problem with macro code generation, but it is not so good. Any my GenServers are full of trivial repetitions.

POiNTx
2 replies
1d10h

Behaviours might be what you're looking for, they're the closest thing to inheritance in Elixir.

And you're absolutely right about genservers being objects :)

kimi
1 replies
1d10h

They are, but it's not as natural as A specializes B that specializes C.

toast0
0 replies
1d

It's maybe not quite as formalized inheritance, but (at least in Erlang) you can make behavior B that is a behavior A, and in module C (which implements behavior B), do B:start(C, ...) B;start/? Most likely does A:start(B, ...) and when the callbacks come in, B may call functions from C or not depending on things (such as if there is an optional callback defined).

If your boilerplate turns out to not really be that samey though, it's easier IMHO to have a template and customize it where applied.

weatherlight
1 replies
1d12h

It's less of an issue with elixir than it is with ruby or python or any other dynamic lang (or static lang) with mutability. Because of pattern matching/unification in functions, you have a good idea what shape your data is as it's being passed around. if you still don't feel comfortable, there's always Dialyzer.

Dialyzer is a static analysis tool for erlang/elixir. It's part of the standard Erlang Release and stands for DIscrepancy AnaLYZer for ERlang programs. It identifies software discrepancies such as type errors, dead code, unnecessary tests, etc., in single Erlang modules or entire (sets of) applications. Dialyzer starts from a base of correct programs and infers types; it doesn't require type annotations but uses them if they are available to provide better warnings.

https://fly.io/phoenix-files/adding-dialyzer-without-the-pai...

japhib
0 replies
23h37m

Big time this ^, I really need static typing in hobby projects (I like C#/Typescript) but at work we use Elixir and it doesn't end up being a problem because of pattern matching. It's partially because it ends up being run-time type checking, and partially because it makes the code _read_ like a statically typed language.

creakingstairs
0 replies
1d12h

Types are coming! Hopefully not too far away.

https://elixir-lang.org/blog/2023/06/22/type-system-updates-...

GavinMcG
0 replies
1d11h

You might like Gleam, then. Seems to have a similar feel.

sinuhe69
6 replies
1d12h

Coming from F# and only dabbled in Elixir, I find the language unfortunately a bit confusing. For instance, the signature of a function only reveals the name and number of the parameters but not type, so in a big library, it’s quite hard to recognize (mentally) what goes into what and one can only see one plugged the wrong parameters after one had ran and debugged the code. In strict-type language like F#, such issues would be detected right away during coding, thus it helps to reduce the time and effort immensely.

So my question is what are the main selling points of Elixir besides the Erlang environment?

jswny
1 replies
1d12h

Static typing for Elixir is in active development:https://elixir-lang.org/blog/2023/09/20/strong-arrows-gradua...

Yes, it is currently dynamic and yes, that means you won't get much int he way of type information from the language itself, it's not currently a statically typed language.

deviprsd
0 replies
13h2m

dynamic but still strongly typed

thibaut_barrere
0 replies
1d10h

I've used .Net quite a bit (but F# only occasionally), I would say some selling points are:

- the native integration of Machine Learning (including compiled to GPU) with e.g.https://www.youtube.com/watch?v=HK38-HIK6NA, Axon, Nx, BumbleBee etc (there is a real push for that in the community)

- the way LiveView works (although there is Blazor in .Net)

- the fact that Elixir can be used in a large number of contexts (including embedded, see Nerves, or scripting but F# is usable for scripting too afaik)

- overall, the BEAM and associated structures

- package manager (Hex) is really nice (but .Net has nice tooling too)

Just a couple of points from my own experience

shirvan
0 replies
1d12h

There is a lot to like about Elixir itself including the nice syntax, which as mentioned in the article is inspired by Ruby and very easy to pickup. The BEAM/OTP is what really give Elixir the edge over other languages that I've used.

In my experience they include many batteries that would be libraries in other languages, and most times those libraries add a ton of complexity, and sometimes a big learning curve; Async anything is a good example.

I think once one works with Elixir for some time, and gets to learn these builtin tools and abstractions they understand the power of the ecosystem as a whole.

rapind
0 replies
1d12h

As a language, I wouldn't call it an upgrade over F# (subjective). The main selling point is probably running on BEAM w/ ruby-ish syntax. BEAM is kind of a big deal IMO.

I don't think it compares very well to F# types, but you can use typespecs:https://hexdocs.pm/elixir/1.15.7/typespecs.html

conradfr
0 replies
1d9h

The lack of typehinting for function parameters is definitely the biggest productivity hit for me in Elixir.

You can go by with typespecs, pattern matching and guards but that's kind of exhaustive and not really IDE / Intellisense friendly (at least with the community-led Jetbrains plugin).

colesantiago
6 replies
1d12h

Which companies have used Elixir in production, I know Brex used to use Elixir but now used Kotlin and also the Bleacher Report.

Are there any more?

voxadam
0 replies
1d8h

Some case studies of Elixir's use at various companies can be found on the main Elixir site.[0]

[0]https://elixir-lang.org/cases.html

tionis
0 replies
1d5h

Discord uses it for their backend I think. Interestingly WhatsApp's backend is also built on Beam, but using Erlang directly instead.

sho
0 replies
1d11h

There are tons, I can name at least 4 in my city alone, all fintech. Elixir really excels, and is heavily used, at payment processing workflows, where genservers and the concurrency model is amazingly useful at handling complex, multi-step transactions involving multiple, often external, actors.

None of the companies appear on that list, I think those kinds of things should always be taken with a grain of salt.

schainks
0 replies
1d12h

Adobe and Apple.

romanhn
0 replies
1d12h

There's a pretty large list here:https://elixir-companies.com

keep_reading
0 replies
1d1h

Based on the customer list of Oban.pro and knowledge from previous conferences there's also Nintendo (one of their online game stores uses it?), PepsiCo, Apple, Toyota...

sBqQu3U0wH
5 replies
1d5h

A few months ago I started a new job at a company that uses Elixir as its main language

I've never written a line of Elixir or Erlang before in my life

How is this possible?

jacquesm
1 replies
1d4h

It's possible because the number of programmers that have been exposed to Erlang and Elixir is a very small fraction of the total. Besides, many programmers go through their whole career in a single eco-system (.NET, Java, C, C++, COBOL, PHP etc).

sBqQu3U0wH
0 replies
1d3h

Hmm, I was dabbling with Elixir for quite some time now, but never considered myself proficient enough for applying to Elixir jobs. May be worth a try.

toast0
0 replies
1d

Some companies have sanity in hiring?

I've been hired to work in Erlang without experience (although I got typecast into php stuff because I did have experience) and although the company was dependent on Erlang, we almost never hired anyone with Erlang experience. Hire smart people that are comfortable learning new things, have a project where the strength of BEAM is compelling, buy a bunch of Erlang books.

My current job is mostly Rust and I didn't know that before I started either. And seems like the team is similar. Smaller team, so I don't know have confidence in my likely to know Rust estimate.

The pool of people who are looking for a new job, and are experienced in Erlang/Elixir, and have exposure to the business specialization, and want to work for a company is very small and hard to find. Hiring companies can ask for it, but they'll have to compromise. It almost certainly doesn't hurt to apply to a job where you don't meet the stated requirements; there's likely no real penalty for having your resume tossed out, and that happens with qualified resumes too. At worst, maybe they blacklist you and won't look at your resume again ever; that's probably ok.

Same thing goes the other way, I'd have preferred an opportunity to use more Erlang, but I didn't find one that met my other needs, so I compromised and write Rust in a cloudy environment and dream about using BEAM and dist and hotloading and all that. Maybe one day.

dbbk
0 replies
1d2h

My company hires non-Elixir developers for Elixir roles too. The candidates with experience are just far too hard to find.

ch4s3
0 replies
1d2h

I've hired a number of people to write Elixr who were skilled and eager but hadn't used it before.

block_dagger
4 replies
1d12h

Longtime Rubyist here that has worked with Elixir. It is only loosely based on Ruby's syntax - there is a _lot_ more punctuation in Elixir. Also much more explicit passing of parameters, including database connections and error handlers in the case of a Phoenix application. It's also a challenge to deploy OTP along other non-hypervised runtimes. BEAM and Elixir are very cool, don't get me wrong, but after some programming web services in Elixir I was ready to head back to Ruby. If I need a highly fault tolerant near realtime comms system, I'll look at Elixir, otherwise I avoid.

whalesalad
2 replies
1d12h

It's also a challenge to deploy OTP along other non-hypervised runtimes.

Pardon?

ungamedplayer
1 replies
1d12h

This part stumped me too. Maybe op had some deployment issues on VM systems.

whalesalad
0 replies
1d12h

ngl I get a sense the op and most people commenting in this thread don’t understand elixir at all. the fact that the syntax somewhat resembles ruby is really just 5% of what makes elixir interesting. It’s a distraction from the real value of the beam, OTP, and immutable data.

rozap
0 replies
1d12h

It's also a challenge to deploy OTP along other non-hypervised runtimes.

What in tarnation. Please expand on this one.

BMorearty
4 replies
1d12h

In Ruby it's common to use exceptions for control flow.

I think this is just plain incorrect. The example given later in this paragraph is the Rails `update` method--but the approach used in all canonical Rails examples and generators is the non-exception version of `update`.

whalesalad
1 replies
1d11h

Ruby != Rails. There are a lot of bang! methods that will raise on error in Rails. But in general Ruby is just like Python in that it is indeed common to use exceptions for control flow.

BMorearty
0 replies
1d10h

I know Ruby != Rails but the example wasn’t mine. It was from the paragraph I quoted from the post, which conflates the two.

It may be true in Python--I don’t use it much--but I know Ruby well. It was my primary language for 13 years, at multiple companies. I taught it to over a thousand engineers at Airbnb over the course of five years. I still disagree that it is common to use exceptions for control flow.

Maybe it’s a matter of the interpretation of the word “common.” ¯\_(ツ)_/¯

thibaut_barrere
1 replies
1d10h

I do not find it incorrect at all, as a Ruby user since 2004. A lot of gems use exceptions for control flow and it is also common in apps or libraries I've written or maintained (just a data point).

lcnPylGDnU4H9OF
0 replies
23h34m

A lot of gems use exceptions for control flow

Do you happen to have an example of such control flow to link to? Not that I don't believe you but I wonder if there's a difference in what is meant by "control flow" between commenters.

  begin
    do_stuff!
  rescue MyFirstLibraryError => error
    # handle first
  rescue MySecondLibraryError => error
    # handle second
  end
That could be "control flow" to one person and "error handling" to another. Or even both to a third person.

danjac
3 replies
1d11h

It would be nice to work with Elixir, having played around with it.

However every Elixir job I've seen requires Elixir experience, so I don't really see much opportunity for working with it professionally.

fastball
2 replies
1d7h

Yeah, I'm in the same boat. Have tried to find a side project that would justify Elixir/Erlang and nothing has jumped out at me that would cut it. I still generally want to pick the best tool for the job (even on side projects), and Erlang frequently feels like overkill for the use cases I have in mind.

danjac
1 replies
1d4h

Sure but for these companies "did some Elixir in a weekend project" doesn't count as experience.

fastball
0 replies
1d2h

Yes, that is my point. In order to demonstrate experience you really need to show work on something thatjustifiedErlang, not just that you understand the syntax of Elixir and the basics of working with the Erlang VM. And usually a "weekend project" does not qualify (though that really depends on the project).

But I do think most companies that are looking for Elixir experience would be happy with your weekend project if was actually used by people in a way where Elixir could shine.

da39a3ee
2 replies
1d10h

There are no classes, no instances, no inheritance

I don't know anything about Elixir, but it bothers me when people claim that languages like Rust and Go are "not object oriented". If you create structs and have special syntax for defining functions that operate on instances of those structs, then those are called objects and you are doing OOP. Just because some Java people came up with a definition of OOP that says it has to have inheritance, doesn't mean you actually have to pay attention to their definition.

lawn
1 replies
1d8h

And Erlang (and Elixir) is also closer to the original definition of OOP, with it's focus on message passing between processes ("objects").

da39a3ee
0 replies
1d7h

Right exactly. The author implies that Elixir isn't an "OOP language" but I agree with you that (AIUI) it's almost the opposite -- it's descended from Erlang whose, AIUI, entire raison d'etre is programming in a style that is strongly oriented around objects (i.e. instances that usually represent entities in the application domain, and communicate by message passing). Immutability is orthogonal.

whalesalad
1 replies
1d13h

The true power of Elixir comes from processes and OTP.

davidw
0 replies
1d2h

Yep. A lot of these intro things aren't really selling me on how they're using the big features of the BEAM system as an advantage.

runegustavsson
1 replies
1d3h

I've been programming in Erlang since 1991, every day; and that has been my intention all the time. I've done things in Haskell, Rust, Elixir, etc.. over the years. Strong typing is extremely valuable but what it all boils down to is where I have the most fun. Erlang is the prog.lang that gives me most joy and I plan to continue hacking Erlang, at least, until I retire in a few years.

news_to_me
0 replies
1d

What kinds of projects have been the most fun for you to work on?

jononomo
1 replies
1d3h

Elixir may not be statically typed, but at least it isn’t object-oriented.

ch4s3
0 replies
1d2h

IMHO, structural typing and pattern matching get a lot of the value of static types without all of the extra effort. But your mileage may vary.

isodev
1 replies
1d13h

I only learned about Elixir a little more than a year ago and it’s been a lot of fun to learn and incorporate in different components.

My biggest joy comes from how much one can do out of the box with beam/otp. Someone in a team I worked with once said “BEAM/OTP is like k8s only without the complicated parts”.

bananadonkey
0 replies
1d12h

When all else fails that's how I explain it to my team.

I spent years learning Elixir but unfortunately the benefits were somewhat undermined by the recent migration to OpenShift (k8s) I had just architected.

It would have been a much more tantalizing proposition if k8s was not in the picture; instead we kept our existing dev stack and utilized k8s concepts to achieve what we would have been doing in OTP, with different trade-offs of course.

fyokdrigd
1 replies
1d3h

elixir is awful, mid-long term.

you write mix new something. it generates tons of code which will NEVER be update when the template gets update for new people running mix new something.

then all the liveview magic happens with JavaScript code writen by someone who will not be there when major browser security model changes happen (and google make sure these happens every 3mo). then who will keep updating the magic js?

ch4s3
0 replies
1d2h

LiveView just uses websockets to push diffs to Morphdom. It's not really much more complicated than that.

aryehof
1 replies
1d12h

Write after you’ve been there for 2 years, instead of at the start. That new thing always looks like a flawless shiny new silver bullet when starting out.

ashton314
0 replies
1d11h

I work professionally as an elixir developer for longer than that before starting a PhD program; Elixir was and still is a gem. It’s not perfect. It holds up incredibly well though.

andsbf
1 replies
1d13h

`...If you call model.update(params) in Ruby, then it returns false if it fails and updates model.errors with what went wrong. Mutable state.`

This is Rails stuff, not Ruby

krainboltgreene
0 replies
1d12h

True, you could implement Ecto exactly in Ruby, except you'd be writing effectively Elixir and every library released that got close to this in the 15 years I've been doing Ruby has been either disliked or disregarded. Each with less contributor activity in their lifespan than a month of ActiveRecord attention.

alskdj21
1 replies
1d13h

Sasa Juric'sThe Soul of Erlang and Elixirtalk[1] showcases how powerful the language can be.

[1]https://www.youtube.com/watch?v=JvBT4XBdoUE&t=4

ZeroMcMuffin
0 replies
1d3h

As someone curious about Elixir, I watched this talk earlier this week. I highly recommend it to anyone who has heard all of the "let it fail" and "BEAM does concurrency right" talk, but still doesn't grasp it. It is an incredible talk.

xonetons018
0 replies
1d1h

Cone tond

readline_prompt
0 replies
1d5h

understandably types are great, but the projects I've worked in got along just fine using specs and dialyzer's success typing. of course sometimes it can get messy like in macros etc.

pmarreck
0 replies
23h49m

FYI it's spelled "cinch", not "synch"

michaelcampbell
0 replies
1d4h

Exceptions, then! In Ruby it's common to use exceptions for control flow.

"common"? Not IME. Certainly possible, but I don't see it a WHOLE lot. Maybe it's just $CURRENTJOB's style not to, I'll grant.

linkdd
0 replies
1d3h

Self promotion moment:

If you enjoy the Result/Either type and API in Rust, I made this project just for this:https://github.com/linkdd/rustic_result

I also madehttps://github.com/linkdd/rustic_maybe/tree/mainfor an Option/Maybe type.

NB: Those are not types, but I'm waiting for set theoretic types to update those libs :)

jononomo
0 replies
1d13h

I love Elixir.

hbcondo714
0 replies
1d13h

Elixir's |>, and it inserts the result of the previous expression into the first argument of the next function

I found this convenient while writing my first Elixir app with Phoenix Liveview:

https://github.com/hbcondo/last10k_liveview

gv83
0 replies
1d1h

while bracing myself for the downvotes storm: why is this frontpage? it's very bland content harping the same old story about immutable data and pipes, without any real insights other than "3 months of a new thing and it seems cool".

are we really at the point where rust or elixir in the title = instant karma shower?

ctrlmeta
0 replies
1d6h

A few months ago I started a new job at a company that uses Elixir

In fact, I might go as far as saying that Elixir gives you a fun language (like Ruby) while leaving out the stateful footguns OOP languages give you.

I don't mean to discount the author's experiences and opinion in this post. It's a nice post with a lot of good food for thought. Likewise I want to share only my own experience here. Two months into any new programming language, it feels like a fun language. Eventually the novelty factor wears off. And then it becomes a boring language. And I say "boring" in a positive sense.

The daily driver languages should be boring. Should present no surprises. Get the job done and get out of my way. When we transistion from the fun phase to that boring phase, what matters more is how good the language is fundamentally designed. As an example in Elixir the pattern matching abilities are great but I don't know if I could justify choosing a language without compile-time type safety in this day and age!

bdavid21wnec
0 replies
1d3h

I used Elixir briefly, what sticks out to me was how easy it was to learn. Really like the pattern matching and immutable data. What it excelled at most and I still haven’t found the full equivalent in any other language is building a full CQRS system. The Commanded library combined with graphql was so powerful and well thought out. With the BEAM if a developer writes some bad code, instead of screwing up all your events, the GenServer will just error out on the same event until new code it pushes to fix it. Events will starting queueing, but the whole system is unaffected. It was brilliant

ThinkBeat
0 replies
1d5h

I love BEAM since I was first introduced to Erlang. I think it should be adopted a lot more for codebases and that it solves a lot of problems in a good way that are currently solved in bad ways in modern trends.

Clearly there are strong preferences among folks for static or dynamic typing, almost like vi vs emacs.

My opinion is on typing is:

Stating typing does not slow you down.

With dynamic typing while you are writing code you have to plan and remember what type a variable of some sort represents before You can act on it.

With static languages most type of variables will be known at compile time and can offer good feedback if a type is used in the wrong manner. It also makes it much easier to know what a variable is and what it might be doing if it has an official type.

Reading dynamic code I often have to search around a bit to figure out what a variable is.

I think if the only reason it is "problematic" to have static typing is because writing "int", "string" etc. is too much work then your priorities are mixed up.

Sometimes people resort to Hungarian notation to help out. (Less and less) sName,iAge,etc. That is helpful but you might as well have static typing at that point.

There has been a lot of work done to find a good way to add (optional) static typing to Elixir and I think it is on going but represents a hard problem.

I am glad Gleam is out (https://gleam.run/), it is my favorite BEAM language now.

EMM_386
0 replies
1d7h

you're not bogged down by a static type system

Maybe it's just me, and I'm not even specifically referring to this particular post ... but why is there so much "debate and discussion" (flamewars?) over static typing recently?

I am guessing this is due to a large influx of people into IT, many of whom got hired because they knew some JavaScript, "React a plus" a lot out of bootcamps and similar programs. As that sizable group ran headlong into static typing, usually via TypeScript, then the debates began.

All over Reddit, Twitter, even HN. People insisting that the verbose and confusing syntax was a "bridge-too-far" and one they would not cross, even if the reasons came down to "it looks weird" or "don't have to 'compile' JavaScript".

Maybe, spending too much heads-down time over the last ... whatever decades at this point ... I simply don't get it.

Don't get it similar to what I quoted here ... "bogged down by a static type system". "Bogged down", in what way?

I spend my days mixed between everything from C# to JavaScript, almost polar opposites. And the rest of it usually in TypeScript.

I do not get this feeling of being "bogged down" by static typing .... ever? I don't recall it being an issue, even though I spent hours in statically typed lanagues yesterday alone. Maybe if you are the author of a complex JS library that has to be shoe-horned into TypeScript ... yes, maybe.

What Ididexperience recently was being able to remove a parameter from a function, actually compile with the intent it will fail, see it fail, double click on some things and fix the 17 callers to that method I just changed the signature of, and then a minute or so later after fixing those call sites, I was back to work.

Yet, over on the social sites, the debate rages on. Open source projects removing TypeScript practically overnight for "reasons". Questions such as "how many type issues did you run into before switching to TypeScript", leaving me to wonder if that is even a rational question.

And then on the flipside, "TypeScript is the greatest language ever", heart emojis being sent to it, "If you are a JS dev you need to be using TS".

It's all strange to me, having used JavaScript for the first time back in 1996.

I'm convinced it was this wave of JavaScript devs crashing into new requirements to use TypeScript that started it.

It will sort itself out here at some point.

99miles
0 replies
1d11h

I've been using Ruby since about 2007. Every time I attempt to switch to the next "cool" thing, I ended up switching back, because Ruby is what I love and am the fastest with, and that's all that matters.

However, I've been starting to see a lot more Elixir buzz, and I love the looks and sounds of it. Looks like I'll need to start a new side project soon to give it a try.