Live data from Hacker News

Elixir and Rust is a good mix

fly.io

141–150 of 165 posts

Re: Elixir and Rust is a good mix

#141
post #123

Earlier quoted context omitted.

Maybe because the language is not untyped? It has both dynamic typing and optional static typing.

sure but not in a sense that rust is. my point is that it is entirely possible to build good software with substantial code bases in dynamically typed languges and i used common lisp as an example. in fact i dont know of one common lisp code base that turned to a dumpster fire because of typing problems. instead i find the opposite true: old forgotten code can often be resurrected because the language promotes clear…

Lisp is not Python or JS.

People use Python and JS, not Lisp.

Dynamic typing in Python and JS + medium-sized project = dumpster fire.

Re: Elixir and Rust is a good mix

#142

I admit for a long time this was my primary motivation to learn Rust, but, sadly, I haven't come across problems in years that were CPU bound/where I needed something like Rust... Rustler still looks like a great fit if needed, but, depending on the use case, if I were CPU bound and needed to write my own code/not just use a Rust library, I'd be as or more likely to look at using Zig and Zigler[0], for much faster le…

I haven't come across problems in years that were CPU bound/where I needed something like Rust This is where Rust falls short of C#: scaling to the issue at hand. C# can build you a beautiful app at a high-level but also lets you dick with pointers and assembly at a low level. Rust insists on defaulting to pass-by-move and an arcane trait system that hold it back from being usable in large projects.

Composition is objectively superior to inheritance, and that's all traits are: https://en.m.wikipedia.org/wiki/Composition_over_inheritance

Re: Elixir and Rust is a good mix

#143

Earlier quoted context omitted.

Tokio seems to be a valid replacement for lightweight threading in elixir. Fault tolerance and supervision hierarchy might be unnecessary as mentioned. Hotloading capabilities are unnecessary, most shops go with blue-green deployments, so the hotcode loading is usually unused (and for a good reason, so much complexity!). Distributed computing also goes unnecessary as most applications are deployed with containers wit…

> Fault tolerance and supervision hierarchy might be unnecessary as mentioned. It's not like there is suddenly no fault tolerance though. Erlang has a certain way of handling/dealing with errors/faults and so does Rust and other languages. I would not by default assume that Erlang's errorhandling is superior. > That leaves us with runtime introspection, which is pretty cool indeed. But that has to compete with Rust p…

The reason why I haven't brought it up is because they are not the same thing, so they can't compare. Of course rust type system is great, but at the same time the memory management is not something necessary to most software.

Elixir could teach some really good practices to people writing code, which is why I'm somewhat sad that other languages can supersede it (go, rust).

Re: Elixir and Rust is a good mix

#144
post #67

Earlier quoted context omitted.

> Which is more costly to fix later. This assumption is changed, IMHO, by Erlang. Hot loading makes the cost to make small changes very low. So the question becomes, do you pay the definite cost of build time type checking (usually includes coding time type annotation), or do you accept the possible future cost to making small fixes. Of course, if you work in an organization where even a small fix requires months to…

The cost at runtime also includes loss of data, inferior user experience, direct financial loss or even loss of human life for some systems. It really depends on the domain but it definitely is more than pushing an update.

Essentially every statically typed language contains runtime errors that can be costly too.

Erlang was designed to achieve 9 nines of uptime. It achieved this without static typing across very large applications. The fact that this is a regular occurrence with Erlang disproves the idea that a lack of types is fundamentally unsafe.

Static types are most useful with monolithic application design. They counter your massive ball of code growing too complex and the complete lack of introspection at runtime. They attempt to handle the problem that any error crashes your entire system.

Erlang uses a different approach.

First, it uses safe datatypes. You aren’t going to crash because you chose a 32-bit integer and rolled it over (something a type system won’t actually help with). This is maximally likely to corrupt user data without even raising any flags. Integer rollover has actually killed people (famous in the Therac-25).

Second, it uses all immutable data, so data sharing is safe. Also something types don’t help with. This is also a maximal risk of data corruption. Incorrectly mutating data has also killed people (also in Therac-25).

Third, it is functional. Toys reduces passing around giant balls of mud. Those balls are unusable disasters unless you add some types. Functional programming with immutable records means that a program can’t accidentally change the types of incoming data. Because the pattern encourages separating data and mutable state, the most common typing accidents are simply avoided.

Erlang is designed with concurrency first. This helps to keep those balls of code even smaller and further reducing the chances of typing errors. And of course, combined with immutable data, we eliminate another set of errors typing does nothing about and that have caused massive damage and probably deaths (a deadlock causing a NYC blackout leaps to mind).

Finally (I probably missed some points), Erlang is designed expecting crashes to happen. Few runtimes are capable of anything close to the elegant Crash handling of BEAM. Instead of fearing crashes, you understand they’re inevitable and embrace them. This means that you are prepared for not just an occasional type error, but will also elegantly handle null exceptions that plague most of the most common statically typed languages.

Re: Elixir and Rust is a good mix

#145
post #132

Earlier quoted context omitted.

Come on, Rust has a good type system, but it’s nothing special - Haskell has the same guarantees since decades and it’s not like Haskell programs are suddenly without fault. There is only so much static types can catch without dependent typing, as per Rice’s theorem, types are a ‘trivial property’. Most of the interesting stuff happens at runtime and those are much harder to reason about. Just because you have a Resu…

> it’s not like Haskell programs are suddenly without fault I never said that. But would you claim that Haskell programs are generally more faulty / less stable than Erlang programs? > Just because you have a Result type doesn’t mean you actually properly/meaningfully handle the error at all Okay, but the same is true for Erlang and the BEAM. > it may just happen that “restart” is the correct solution Yeah, but is ve…

> > Also, Rust is not safe from dead/live locks and many other concurrency issues, only data race free. > How is Erlang safe from those things in a way that cannot or only with a lot of effort be replicated when using Rust?

Each BEAM process (other runtimes would call them preemptable green threads) has its own heap, communicates with other processes by messages, and only works on immutable data without the involvement of Native Interface Functions (NIFs). There’s no shared memory at all. It is natively massively concurrent without most of the risks involved. Sure, it’s possible to write code that results in mailbox deadlocks, but it also means stepping outside of normal program design for the BEAM, and it means stepping outside of OTP (which provides structured programming constructs like gen_server).

Rust makes it harder to program without memory safety. Erlang (and other BEAM languages) make it harder to program without concurrency safety.

Edited to add:

Joe Armstrong’s thesis on Erlang is available for download and is written in very accessible language[1].

If you want more, you can also read Programming Erlang (2nd Edition)[2] also by Joe. (I would love to see a 3rd edition tackled by someone to address the newest stuff added in the 9 years since the last publication. I can understand why no one would want to approach this, since it was Joe’s.)

[1] http://erlang.org/download/armstrong_thesis_2003.pdf [2] https://pragprog.com/titles/jaerlang2/programming-erlang-2nd...

Re: Elixir and Rust is a good mix

#146
post #59

Earlier quoted context omitted.

In my experience it is even harder in a typed one because now you have to deal with the type system nightmare they built. So the compiler fight your refactoring.

You never actually get away from types, they are a core requirement of using any data beyond raw bytes. The guarantees that a strong type system provide mean you can be certain about certain things before your program even runs. If that's a problem for you, you're likely just leaving bugs on the table to be discovered at runtime.

I’d modify your statement to say "strong, static type system". Strong and weak typing are orthogonal to dynamic and static typing. JavaScript has weak dynamic typing; TypeScript has strong-ish static typing sitting on weak dynamic typing. Ruby and Erlang/Elixir have strong dynamic typing. Rust and Go strong static typing (Go’s is weakened by interface{}, IMO, but it’s a valid choice).

With the way that Erlang and Elixir pattern matching can be used in function heads, I can have much the same feeling of certainty that people express from Haskell and Rust. (Erlang typespecs help here, but are not checked by the compiler itself, only by additional tools like dialyzer or gradualizer.)

Re: Elixir and Rust is a good mix

#147
post #133
post #44

Earlier quoted context omitted.

I work on a lot of 'glue' issues, often with languages like Perl, PHP, and Erlang (and a bit of Javascript here and there). Specifying types all over the place in languages like C, C++, Java, and Rust feels like it gets in the way and limits more than it helps. (feelings more than data here, of course) Sure, at boundaries between teams, you need to specify the data in some way. That could be a type, but for me, often…

I always wanted to ask someone whose “native tongue” is untyped languages — when you reason about code, what do you think of an object, is it of specific type? Nominal, or more like structural typing that you know that it has to have this and that method? I have started programming in untyped languages, but simply can’t remember back at all, and now I can’t really imagine dealing with objects in my mental medal as no…

I generally think about "types" in terms of capabilities more than shapes. When I write Ruby, I don’t generally think "this parameter must be an array". Instead, I think "this parameter must be an Enumerable". Or I think "incoming objects must behave like strings" (that is, they implement #to_str or are Strings)…although most of the time, I would really think "incoming objects must have useful string representations".

In Elixir, I do think about shapes more than capabilities (because Elixir is not OO), but with pattern matching, I can either specify "this must be a MyApp.Account struct" (which is just a fancy map) or I can specify "we will handle any map that has the keys X and Y, and Y must be a map itself".

I replicate this more formally when writing TypeScript, usually by building up type definitions and specifying those.

Re: Elixir and Rust is a good mix

#148
post #133
post #44

Earlier quoted context omitted.

I work on a lot of 'glue' issues, often with languages like Perl, PHP, and Erlang (and a bit of Javascript here and there). Specifying types all over the place in languages like C, C++, Java, and Rust feels like it gets in the way and limits more than it helps. (feelings more than data here, of course) Sure, at boundaries between teams, you need to specify the data in some way. That could be a type, but for me, often…

I always wanted to ask someone whose “native tongue” is untyped languages — when you reason about code, what do you think of an object, is it of specific type? Nominal, or more like structural typing that you know that it has to have this and that method? I have started programming in untyped languages, but simply can’t remember back at all, and now I can’t really imagine dealing with objects in my mental medal as no…

I’ll first say that my favorite languages are StandardML (very strongly typed), Common Lisp (not very typed), and JS (even less typed).

Look at Erlang. It has bigints, floats, Booleans, but-strings (sequence of bits —added because it is so common in telecom), string (not technically a primitive data type), functions, atoms, list, tuple, and map.

None of these look the same or act the same. People dream about seeing `123 == myMap`, but it simply isn’t a common thing because it doesn’t make sense.

The common rebuttal becomes: but how do I know if property X is a string or number when I’m using it?

If that’s your question, you are already messing up. What you really want to know is what X actually represents. Otherwise, you’re just shooting in the dark which is at least as dangerous as getting the type wrong and probably more so because a wrong type will become obvious quickly while mangling that number or string may not be caught until a much later time after serious damage has propagated throughout the data.

Let’s say you have something called `login`. Is it a number or string? If it’s a string, is it an ISO date, UTC date, or something else? Is it when they logged in or when their login expires? If it’s a number, it could be a Unix string. It could also be a calculated value for how long the user has been logged in and could be days, hours, minutes, seconds, milliseconds, or something less common.

How do you know which thing is correct?

In a good codebase, you read the docstring comment on the data constructor that describes what it does. If it says “milliseconds since last login” vs “token expiration using ISO datetime format” do you have any question at all about whether it’s a number or string?

If there isn’t a docstring, you’ll be digging through that code or playing around with the responses and will see the data type anyway.

The result is that you’re forced to better understand what you’re doing which isn’t a bad thing in my opinion. There may still be mistakes, but that leads to the next point.

Dynamic languages generally make it easy to dynamically check the types of incoming data and tend to be more flexible with mistyping (especially JS). I can’t count the number of major errors from common typed languages because they make introspection hard, so programmers don’t do it and crash on malformed data or when an API suddenly changes.

It’s also worth talking about null exceptions. Many dynamic languages expect type weirdness and handle it well. This usually includes null. Most statically typed code out there has LOADS of null exceptions lurking about which only trigger in obscure cases during runtime. In this regard, you could argue that the worse type issues also happen in typed languages, but are more dangerous in those languages too.

Untyped languages also tend to use safe numbers everywhere. Infinity is mostly useless, but not usually dangerous. Bigints everywhere are slightly slower in some cases, but completely eliminate overflow errors. Most typed languages use risky numeric types, so they must also force users to think about those things.

Finally, no common typed language offers good runtime introspection like smalltalk, Common Lisp, Erlang, or even JS. I feel static types are just a crutch to make up for this deficiency.

That brings us to good static languages. Typescript offers all the benefits of normal, unsound static typing combined with all the robustness of JS’s dynamic environment. The same can be said for Coalton and Common Lisp.

StandardML offers a language that feels like a dynamic language, but still offers static checks that are actually sound and completely eliminates null exceptions. Rust (an ML in spirit if not in syntax) does the same things in environments where garbage collection and other such amenities aren’t possible.

I like both kinds of languages and good examples from each word around the problems of each approach to make them (in my experience) about equal in productivity for equally skilled and experienced developers.

Re: Elixir and Rust is a good mix

#149
post #48

Earlier quoted context omitted.

I'm in the same boat with Elixir. I love many aspects of the language, but it borrows the fast-and-loose type ecosystem of ruby. nil is an especially big problem. Any value could be nil, and this will absolutely bite you over and over. nil even allows you to use square brackets for some reason (some_nil_value[:some_key]) which is a great way to disguise the actual issue. There is optional type checking with Dialyzer,…

Elixir is incredibly consistent with how it uses nil. It does take a bit of work -- you have to really pay attention to the convention of fetch! vs fetch vs get -- and often times library maintainers are not... always the best at that... but for all the problems that dynamic languages has, nil in elixir is pretty low on the list. I think I get bitten by maybe one a year, and it causes the sporadic report on sentry, a…

> That access acts on nil is unfortunate, but it's necessary for things like get_in.

Ah, that explains it at least. Other atoms don't implement the access behavior.

Re: Elixir and Rust is a good mix

#150
post #104

Earlier quoted context omitted.

I usually just write the SQL, honestly. For the last 6ish years of my career I've mainly been in the Golang world, so the closest I've gotten to an ORM is a utility to scan rows into structs.

Have you tried sqlc? Different to any other SQL library I've used and suits Go really well

Yes, I like it very much. I've run into some edge cases with it, and I wish there was a setting to change the names of some of the autogenerated code, but otherwise it works very well.
Post reply on HN