[HN Gopher] Elixir and Rust is a good mix
       ___________________________________________________________________
        
       Elixir and Rust is a good mix
        
       Author : rio517
       Score  : 196 points
       Date   : 2023-04-13 18:29 UTC (4 hours ago)
        
 (HTM) web link (fly.io)
 (TXT) w3m dump (fly.io)
        
       | mrmincent wrote:
       | I made the 'risky' decision to learn Elixir & Phoenix for a 6
       | week University project that I delivered earlier this week. It
       | could have turned out to be a terrible decision but honestly once
       | I got my head around it, it's probably some of the most
       | productive coding sessions I've ever had. Deploying to Fly.io was
       | also amazing, I think it was 3-5 commands from signup to deployed
       | with a database. Very happy with it all.
        
       | alberth wrote:
       | Doesn't the use of Rust have to be extremely minimal because
       | ErlangVM has hard time limits on their preemptive scheduler and
       | if your Rust code hasn't finished when preempted, that causes
       | lots of problems.
       | 
       | EDIT: thanks for pointing out where in the article this is talked
       | about.
        
         | peregrine wrote:
         | I go into this in the article :) the rustler team has a made a
         | DirtyNif that can work around that, or you can manually yield
         | if you'd like.
        
           | clessg wrote:
           | Indeed, your (excellent) article addresses this, here's the
           | gist for those following along:
           | 
           | > Change `#[rustler::nif]` to `#[rustler::nif(schedule =
           | "DirtyCpu")]`
           | 
           | > This tells the Rustler and BEAM to automagically schedule
           | this in a way that won't block the entire world while it
           | works. Again amazing, this is called a DirtyNif and is way
           | more difficult to work with when you are manually using this
           | via C.
           | 
           | Essentially, regular NIFs have to be extremely fast (< 1ms)
           | because the VM can't preempt them - they run on the same
           | scheduler threads the BEAM itself uses. Dirty NIFs solve this
           | by running jobs in a completely separate thread pool ("dirty
           | schedulers"). Rustler's docs explain it succinctly
           | (https://docs.rs/rustler/latest/rustler/attr.nif.html):
           | 
           | > For functions that may take some time to return - let's say
           | more than 1 millisecond - it is recommended to use the
           | `schedule` flag. This tells the BEAM to allocate that NIF
           | call to a special scheduler. These special schedulers are
           | called "dirty" schedulers.
           | 
           | > We can have two types of "lengthy work" functions: those
           | that are CPU intensive and those that are IO intensive. They
           | should be flagged with "DirtyCpu" and "DirtyIo",
           | respectively.
           | 
           | (Somewhat OT, but since I'm here: excellent article @
           | peregrine! I _really_ enjoyed the read. Elixir and Rust are
           | such a perfect fit. Plus, some of the specifics will be
           | helpful for certain image-related things I 'm actively
           | working on, which is always nice. :) )
        
       | Dowwie wrote:
       | If you're extending Elixir with Rust, familiarize yourself with
       | precompiled rustler: https://dashbit.co/blog/rustler-precompiled
        
       | benatkin wrote:
       | This makes me think of DotCloud, the precursor to Docker Inc. The
       | idea that you can run anything has been around for a while. I
       | don't see how Fly.io is especially good for Elixir. It seems to
       | be about delivering reliable resources for each service, and it
       | works no matter the web framework, as long as you have a PaaS
       | that's geared towards running arbitrary OCI images. These posts
       | seem a lot like the content on the DigitalOcean site, except
       | they're written by staffers instead of freelancers.
       | https://www.digitalocean.com/community/pages/write-for-digit...
        
         | mrdoops wrote:
         | Elixir does distribution and concurrency really well, so Fly
         | making multi-region deployments easy makes it a good fit.
        
           | benatkin wrote:
           | So is Fly good for small sites or is it good for huge sites?
           | What's a big customer? For small sites my idea of a multi-
           | region deployment is a single-region deployment that works in
           | multiple regions thanks to the magic of the Internet.
           | 
           | I see this which mostly seems to be content sites.
           | https://www.wappalyzer.com/technologies/paas/fly-io/ Same on
           | the first forum result: https://community.fly.io/t/customer-
           | success-stories/4882
        
         | peregrine wrote:
         | One of the interesting bits about Fly is we have our own
         | servers distributed globally and connected via wireguard. Which
         | makes it is trivial to setup Elixir/Erlang distribution
         | globally, and most importantly, close to your customers. While
         | its not a magic bullet it is pretty amazing to type a few
         | commands have a globally deployed and directly distributed
         | application.
         | 
         | Further Fly builds its Dashboard internally with Phoenix
         | LiveView. We want the Phoenix and Ruby and Laravel and more
         | communities soon, to grow because we believe if they grow, we
         | will too.
        
           | benatkin wrote:
           | That's just internal networking isn't it? VPC on the big
           | clouds, DigitalOcean, and Vultr. Private Services on
           | render.com.
           | 
           | I remember when Fly.io used to tout Firecracker but that is
           | just a KVM engine, along with QEMU used on a zillion hosts.
           | 
           | What I'd like to see are customer success stories.
           | 
           | Edit: looks like you have to set up your own cross-region
           | links on DigitalOcean and Vultr. So that interests me
           | somewhat. :)
        
       | brightball wrote:
       | This is essentially what has gotten me into Rust. Knowing how
       | easy Elixir makes it to offload a piece of my system that would
       | benefit from it without needing to write the entire thing in
       | Rust.
        
       | bglusman wrote:
       | 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 learning curve, and from
       | what I've read, easier tighter integration into elixir, including
       | I think language server integration. Some discussion here[1]
       | though I forget if I listened to this one or not.
       | 
       | [0]https://github.com/ityonemo/zigler
       | [1]https://podcast.thinkingelixir.com/83
        
         | packetlost wrote:
         | Efficient PLs are useful for latency sensitive applications
         | too, not just CPU bound ones. Though, that doesn't widen the
         | number of cases by much...
        
         | jimbob45 wrote:
         | _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.
        
       | FpUser wrote:
       | I remember MS reps coming to our offices in the 90s and
       | "Teaching" us how to program and how it is cool to have one
       | person writing GUI and the other "guru" writing high performance
       | C++ to be used in critical parts.
       | 
       | I showed them a piece of software that was mighty fast, Internet
       | enabled and GUI intensive. They liked the software but asked
       | where did you get this particular screen control from. You've got
       | to see their faces when told that the whole software was written
       | by a single person in Delphi.
        
       | peregrine wrote:
       | Author here. The rustler team has really made a great developer
       | experience using Rust in Elixir and I just had to share.
        
       | mtremsal wrote:
       | This is amazing! The Gods have sent me the perfect excuse to
       | finally read all the rust ebooks I've been collecting! I have a
       | toy project where certain functions are CPU-bound and would make
       | for a perfect learning project. Very timely read!
        
       | maciejgryka wrote:
       | Shameless plug & also a point of support for the article: I used
       | that same stack to build https://regex.help/ (more details here
       | https://maciej.gryka.net/building-regex-help)
        
         | freedomben wrote:
         | Neat! You should definitely add a link to the github repo to
         | the main page of regex.help though, because I didn't realize it
         | was open source and I'll use it now.
         | 
         | Github link for others:
         | https://github.com/maciejgryka/regex_help
        
       | satvikpendem wrote:
       | I used to use Elixir, but the lack of static types got to me
       | (especially since I prefer the type-driven development
       | methodology). Using Rust afterwards was great, plus it was faster
       | than the BEAM. I guess, why not use Rust entirely instead of as a
       | FFI into Elixir or other backend language? I've been using Axum
       | and it works pretty well. The only time I had to do FFI with Rust
       | was with Flutter via flutter_rust_bridge, for running a CRDT
       | library (automerge) that was implemented in Rust, for offline app
       | functionality.
        
         | shiryel wrote:
         | As it usually goes in programming, "it depends on your
         | objectives", there are things that are easier accomplished with
         | the ErlangVM than Rust. Also, if you want a language that uses
         | the ErlangVM and has static types, maybe you should take a look
         | at Glean[1].
         | 
         | In my case I prefer to work with Elixir because of the
         | community, as I find easier to work professionally with Elixir
         | than some other mainstream languages, as mostly projects
         | follows the same good practices, use the same tools and have
         | good documentation.
         | 
         | [1] - https://gleam.run/
        
         | kerkeslager wrote:
         | > I used to use Elixir, but the lack of static types got to me
         | (especially since I prefer the type-driven development
         | methodology).
         | 
         | You might be interested in Gleam[1].
         | 
         | [1] https://gleam.run/
        
           | satvikpendem wrote:
           | I used to use some Gleam back before the syntax change, when
           | it looked more like Haskell. I found that rather than using a
           | language with a comparatively smaller community, I'd rather
           | just use something that's well supported, so I settled on
           | Rust instead.
        
         | whalesalad wrote:
         | There is a great talk from the creator of the language on why
         | static types are not necessary. Of course there is nothing
         | wrong with wanting them and feeling that they are, but I think
         | he (Jose) makes really great arguments for why Elixir is the
         | way it is. https://www.youtube.com/watch?v=Jf5Hsa1KOc8
        
         | hosh wrote:
         | Everyone have different needs. For us, OTP on top of pre-
         | emptive lightweight threads and a REPL in production is a huge
         | winner for troubleshooting, finding performance bottlenecks,
         | and reliability.
        
         | callamdelaney wrote:
         | Rust is faster, but that's like saying writing to memory is
         | faster than writing to a database - sure, it is - but the BEAM
         | is designed with something completely different in mind and is
         | still 'quick enough' for handling those cases. That said
         | dealing with elixir syntax is like rubbing sandpaper in your
         | eyes for 8 hours a day.
        
           | [deleted]
        
         | malkosta wrote:
         | > why not use Rust entirely instead of as a FFI into Elixir
         | 
         | Because many times you value fault-tolerance and distribution
         | more than performance.
        
           | rapnie wrote:
           | There's a couple of Rust libs and frameworks inspired on
           | Erlang/OTP in 'best of both worlds' attempts, such as
           | https://lunatic.solutions
           | 
           | I found others like Lunatic before, but cannot remember right
           | now.
        
             | malkosta wrote:
             | I guarantee your life will be simpler with Erlang.
        
         | aeturnum wrote:
         | I think the most attractive part of the Elixir / Erlang
         | ecosystem is BEAM and its ability to manage code, processes and
         | resources in an extremely parallel environment. Rust operates
         | at a lower level and it feels deceptive to just compare the
         | languages.
         | 
         | That said - if you don't benefit from what BEAM has to offer -
         | I agree Rust is a really attractive alternative.
        
         | toast0 wrote:
         | Rust doesn't have a lot of good runtime introspection tools (or
         | they're very not obvious). If you're running a system with a
         | lot of concurrency, it's nice to be able to attach a debugger
         | and find out exactly what's going on with each of your tasks.
         | 
         | I haven't seen hot loading for Rust (but a quick search shows
         | there's some out there), and I'm not sure how amenable Rust is
         | to dlopen and friends to force the issue.
         | 
         | Erlang (and Elixir) have a constrained language that allows for
         | BEAM to be effectively premptive in a way that a Rust
         | concurrent runtime can't be. At every function call, BEAM
         | checks if the process should be preempted, and because the only
         | way to loop is recursion, a process _must_ call a function in a
         | finite amount of time. A Rust runtime cannot preempt, if you
         | need preemption, you 've got to use OS threads, which limits
         | capacity, or you need to accept cooperative task switching.
         | 
         | Also, some of us are as anti-typing as you are pro-typing. :)
        
           | RhodesianHunter wrote:
           | >Also, some of us are as anti-typing as you are pro-typing.
           | 
           | Assuming ample experience with both, how does one reach this
           | conclusion?
           | 
           | I have yet to see a project of any size that needs to be
           | worked on by multiple teams and is written in an untyped
           | language not descend into dumpster fire.
        
             | ReflectedImage wrote:
             | Untyped languages work fine if you use them with
             | microservices.
             | 
             | The only thing you can't do is have both untyped and
             | monolithic at the same time.
        
             | freedomben wrote:
             | I have yet to see a project of any size that needs to be
             | worked on by multiple teams not descend into dumpster fire.
             | Typing can definitely help, but it's just a small tool.
             | Java is a pretty typed language and I'm seen some real
             | doozy code bases in Java.
        
             | toast0 wrote:
             | 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
             | the other team is using a different language than me, so it
             | needs to be a language agnostic type, and it can't include
             | unsigned numbers because Java can't cope, and it can't
             | include large integers because Javascript can't cope, etc.
             | Protobufs are popular, json is too.
             | 
             | I have a lot of unpopular opinions though, and that's fine.
             | It's just tiresome that everyone wants to come in and add
             | types to things that don't need them. Also, I agree with
             | dllthomas, most developers and teams are capable of
             | creating dumpster fires in all sorts of environments, with
             | all sorts of tooling. :)
        
               | cglong wrote:
               | IMO, TypeScript strikes a great balance here. I loved the
               | way I could cast something to `any` when hacking
               | something out, then add proper type annotations once it's
               | ready to be productized. It also a did a good job with
               | type inference.
               | 
               | Disclaimer: I work at Microsoft, but not in the Developer
               | Division
        
               | RhodesianHunter wrote:
               | You can absolutely create a dumpster fire in any
               | language.
               | 
               | Putting the fire out in an untyped language is a
               | Herculean effort.
        
               | throwawaymaths wrote:
               | have you tried doing it in elixir? It's not that bad.
        
               | freedomben wrote:
               | Test coverage is, in my experience, much more important
               | factor than typing. A codebase with great testing is much
               | easier to aggressively refactor/change whether typed or
               | not.
               | 
               | That said, a dumpster fire usually has no or little
               | tests, so maybe we're arguing non-existent hypotheticals
               | :|
        
               | di4na wrote:
               | 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.
        
               | bombela wrote:
               | Nobody code without a type system. The distinction is
               | build time vs runtime type checking. At build time you
               | catch bugs that would appear later at runtime. Which is
               | more costly to fix later.
        
               | toast0 wrote:
               | > 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 release, then do all the
               | things you can to prevent making small mistakes.
        
               | sdeframond wrote:
               | 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.
        
               | ReflectedImage wrote:
               | Well no since unit tests run faster than build time.
        
               | [deleted]
        
               | packetlost wrote:
               | 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.
        
               | [deleted]
        
               | toast0 wrote:
               | Conway's Law means you have to fix the organization
               | before you can fix the software. That's the real
               | Herculean effort.
        
             | fiddlerwoaroof wrote:
             | I tried Haskell for a while and switched to Common Lisp
             | (although I still follow Haskell from a distance). My
             | experience just doesn't match up with the claim that a
             | project of any size written in an untyped inevitably
             | descends into a dumpster fire. I've worked on largish
             | systems in several dynamically-typed languages and several
             | statically-typed and I personally haven't noticed any major
             | difference in overall productivity suggesting that static
             | types are better: they just have different friction points
             | and different ways of working work better in each paradigm.
        
               | RhodesianHunter wrote:
               | The issue isn't productivity. As far as just slamming out
               | code untyped languages are undeniably faster.
               | 
               | The issue is working on projects once they've reached a
               | certain size where you have no idea what the intent of
               | the original author was and you maybe need to refactor,
               | add-in major pieces, or change anything with the
               | expectation that it continues to work.
        
               | fiddlerwoaroof wrote:
               | I'm including maintenance costs in "productivity". I've
               | worked on large dynamically typed codebases and never
               | experienced what you're talking about.
               | 
               | I think it's a question of understanding how to work and
               | think without explicit types rather than something that
               | makes statically typed codebases easier to maintain.
        
               | ReflectedImage wrote:
               | Untyped code bases with microservices are the best code
               | bases out there by far.
               | 
               | They are exceptionally easy to refactor, add-in new
               | parts, etc.
               | 
               | The keyword is microservices, you need to know how to do
               | proper microservices if you are using untyped code.
        
             | throwawaymaths wrote:
             | >I have yet to see a project of any size that needs to be
             | worked on by multiple teams and is written in an untyped
             | language not descend into dumpster fire.
             | 
             | Github? Dropbox? I mean they both eventually went to type
             | hints in their respective languages or migrated to a typed
             | language but for a long time I'm certain it wasn't.
        
               | RhodesianHunter wrote:
               | And I can pretty much guarantee you that some form of
               | dumpster, fire or other was the driving factor behind
               | those moves.
        
               | ollien wrote:
               | It's worth noting of course that ~Github~ Dropbox was the
               | driving force behind mypy
        
               | throwawaymaths wrote:
               | yes, that is exactly what I meant by "they both
               | eventually went to type hints", but doesn't github use
               | ruby? I think you mean sorbet? Dropbox was the driving
               | force behind mypy (IIRC).
        
               | ollien wrote:
               | bleh, I meant to say Dropbox.
        
             | dllthomas wrote:
             | While I'm pretty solidly in the "pro-typing" camp, it seems
             | worth acknowledging that such projects often turn into
             | dumpster fires in typed languages as well, even
             | expressively typed languages.
        
               | jjnoakes wrote:
               | Maybe, maybe not - but in my experience, a dumpster fire
               | with static types is easier to read and understand and
               | also easier to refactor.
        
               | dllthomas wrote:
               | That matches my experience as well. I just think we need
               | to be resistant to reading too much into "I've seen bad
               | code that X", because that can easily be true of almost
               | any X.
        
               | jibe wrote:
               | You think that statically typed languages don't often
               | turn into dumpster fires? Not my experience! Even though
               | there are real advantages.
        
           | throwawaymaths wrote:
           | it's certainly possible to write a nif that cooperates with
           | the VM so that its async yield points match up with the VM's
           | expectation of yield points. Definitely tricky to do
           | correctly in C (given that C doesn't have a yield statement,
           | lol, you have to structure it as an awkward tail call where
           | you pickle/unpickle whatever state you want to keep around or
           | unmarshal it from a passed struct). I'm not sure if that's so
           | easy to do in rust.
        
             | toast0 wrote:
             | Sure, you can do that for the code you write, but you can't
             | for the code you call. Any Erlang you write or call will
             | have this property, and most of the ERTS provided C code
             | will as well; either it's trivially finite, it is designed
             | to yield during the work, or it's neither but it hasn't
             | triggered anyone to fix it, with occasional deviations of
             | things that become known issues (like -- was for some time;
             | although it got fixed twice and is now fairly ok).
        
         | dxhdr wrote:
         | > Using Rust afterwards was great, plus it was faster than the
         | BEAM. I guess, why not use Rust entirely instead of as a FFI
         | into Elixir or other backend language?
         | 
         | Sure, you just need to reimplement light-weight threading with
         | preemptive scheduling prioritizing latency over throughput,
         | extremely robust fault tolerance with a supervision hierarchy,
         | and runtime introspection with code hotloading capabilities.
         | Maybe you could add frictionless distributed system support as
         | well.
         | 
         | No big deal, why not right?
        
           | lucasyvas wrote:
           | Is any of this needed though? For some use cases yes, but for
           | many no. It's possible the parent has no practical use for
           | these capabilities.
        
             | [deleted]
        
             | pdpi wrote:
             | If you're building a project that actually benefits from
             | Elixir/Erlang's features, you can have a constructive
             | discussion about whether those features justify sacrificing
             | static typing. If you don't actually benefit from those
             | features, "I tried to use a language that's unfit for my
             | purposes and found it unfit for my purposes" is a comment
             | of very limited value.
        
             | hexo wrote:
             | "Is Rust needed at all? For some use cases yes, but for
             | many no. It's possible the parent has no practical use for
             | its capabilities."
             | 
             | You hear yourself? Yes? Good.
        
               | tines wrote:
               | You may not realize this, but your comment comes off as
               | being very snide and annoying, which I'm sure you didn't
               | intend. Try rewording things in a way that assumes good
               | faith, and besides making better relationships you'll
               | persuade people more effectively as well.
        
               | lucasyvas wrote:
               | The author gave static types and performance as examples
               | of things that matter to them that they clearly don't
               | feel Elixir does as well. It's probable they weren't the
               | target demographic for Elixir, like many aren't the
               | target demographic for Rust.
               | 
               | The initial response made an assumption that all these
               | capabilities matter either way, and that's not true.
        
               | tessierashpool wrote:
               | This is not helpful. Please consider what if might be
               | like if you were to edit your comment to improve it.
        
         | dsiegel2275 wrote:
         | I used to use Elixir. I still do, but I used to too.
        
         | eikenberry wrote:
         | Could also be nice as it means the Rust parts are smaller and
         | so its slow compiler speed isn't as much of a bother. You get
         | the safety and runtime speed of Rust with the fast iteration
         | cycle of Elixir. Best of both worlds type of thing.
        
           | satvikpendem wrote:
           | I often find FFI more annoying than it should be (ie
           | something always breaks somewhere), I try to avoid it where
           | possible.
        
         | zinclozenge wrote:
         | I pretty much agree with this. As much as I liked the core
         | language, I absolutely hated using anything else in the
         | ecosystem, and in my opinion a lot of that was due to lack of
         | static types. Using Ecto as the main way of interacting with
         | the database was a miserable experience. Part of that was due
         | to skill issue I'm sure.
        
           | kerkeslager wrote:
           | > As much as I liked the core language, I absolutely hated
           | using anything else in the ecosystem, and in my opinion a lot
           | of that was due to lack of static types.
           | 
           | You might be interested in Gleam[1].
           | 
           | [1] https://gleam.run/
        
           | malkosta wrote:
           | > Ecto as the main way of interacting with the database was a
           | miserable experience
           | 
           | That's very common when you don't know DBs. But DB savy
           | developers usually claim the opposite, because the syntax is
           | more familiar.
        
             | zinclozenge wrote:
             | > That's very common when you don't know DBs.
             | 
             | I'm not a 20 year DBA greybeard veteran, but I'm
             | comfortable enough to write schemas and queries by hand
             | without any issue, and the entire time I wished I could do
             | just that instead of using Ecto.
        
               | sph wrote:
               | No one stops you from writing raw SQL with Ecto.
               | 
               | But good luck creating composable SQL with raw string
               | interpolation, which Ecto excels at.
        
           | sergiotapia wrote:
           | On the flipside for me Ecto is the perfect balance between
           | ORM and writing raw SQL queries. I've used many different
           | ORMs like Entity Framework, ActiveRecord, Prisma, Ecto - Ecto
           | stands alone.
        
             | throwawaymaths wrote:
             | I believe... technically Ecto is not an ORM but a query
             | builder, which may be why you like it better than an ORM.
        
           | parthdesai wrote:
           | > Using Ecto as the main way of interacting with the database
           | was a miserable experience.
           | 
           | Ecto is prolly one of the best ways to interact with db.
           | Genuinely curious, what other ORMs have you used?
        
             | zinclozenge wrote:
             | 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.
        
               | freedomben wrote:
               | Interesting, I usually just write the SQL too in most
               | projects, but in Elixir I _love_ Ecto because it 's so
               | close to the SQL but has an elegant and powerful way to
               | handle interpolated values.
        
         | vlunkr wrote:
         | 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, which is good
         | but has some problems. The warning output can be really hard to
         | read, and unless you're diligent in using it across most of
         | your project, it's not very useful, because you'll end up with
         | 'any' values all over.
        
           | OkayPhysicist wrote:
           | I disagree. Any value could be nil, but any value could be 5,
           | too. In fact, nil is just like any other atom. Elixir shines
           | when you lean on pattern matching as much as possible. Your
           | functions should unpack as much as possible within the
           | function definition, frankly the "if" macro is completely
           | superfluous to case and in rare cases cond. You'll find that
           | you match the data you want, and thus reject anything else.
           | 
           | Square bracket dictionary accesses are a code smell, because
           | you should be using %{^key = val} = dict or Map.fetch(map,
           | key) or rarely Map.fetch!(map, key).
           | 
           | If you do that, managing typing in Elixir just boils down to
           | defining structs to differentiate cases where dictionary A
           | and dictionary B contain similar keys but strictly are not
           | interchangeable.
        
           | throwawaymaths wrote:
           | 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, and then I go and fix it, and that's that.
           | 
           | That access acts on nil is unfortunate, but it's necessary
           | for things like get_in.
        
       | pawelduda wrote:
       | I used this in past, but there were a lot of people saying that
       | NIFs/ports are dangerous to use. Did any of this change or are
       | there tried and tested practices that can be applied? What I used
       | this for wasn't critical app so I didn't mind it going down.
       | 
       | IIRC one threat was Rust sharing memory with BEAM which could
       | exhaust it and cause OOM crash?
        
         | peregrine wrote:
         | Nif's are _always_ a risk to deploy cause they run embedded in
         | the Beam runtime. That said we all use many nif 's to do all
         | kinds of stuff and its fine.
         | 
         | I go into this in the article a little but but the ruslter team
         | has made dirtycpu and dirtyio macro's to help reduce the risks.
        
         | toast0 wrote:
         | I wouldn't use the word dangerous. NIFs and (linked in) ports
         | are a risk, yes. You're loading native code, and you don't have
         | intrinsic protection against it doing naughty things that alter
         | the underlying shared state in unapproved ways. Things like
         | writing to improper addresses, closing improper filehandles,
         | opening filehandles and leaking them, leaking memory, other
         | improper use of syscalls, or just running for too long.
         | 
         | The only proper solution is to audit and understand the code
         | you're running, but hoping it's fine often works too; maybe
         | formal methods, but to a first approximation, nobody uses
         | those. Did you audit all of ERTS and/or OTP? I'm guessing
         | probably not, but it's there to review if you run into a
         | problem.
         | 
         | IMHO, it's not worrying about if BEAM will crash; worry about
         | it not crashing instead. If your Rust NIF ties up a scheduler
         | with an infinite loop, that has the potentially to lock up the
         | whole BEAM once another scheduler needs to do something that
         | requires full cross scheduler coordination.
         | 
         | BEAM can certainly crash on OOM; although I recommend setting a
         | ulimit to ensure it will, because when it crashes, you can
         | recover. I've also run into situations where instead of
         | crashing or being killed by the OS OOM killer (which is close
         | enough to crashing), the OS gets into some tricky to debug
         | state where your application is neither functioning nor killed.
         | Sometimes, you even get into a state where BEAM is making
         | progress, but very slowly; that's a fate worse than death.
         | 
         | If you follow the Erlang philosophy, you'll have a recovery
         | strategy from crashes or other deaths. Heart can be used to
         | turn completely blocked into death, although I never used it
         | professionally. But you've still got to worry about working but
         | not well.
        
         | OkayPhysicist wrote:
         | NIFs are dangerous, ports are not. Basically a NIF runs in the
         | same memory space as the BEAM, so misbehavior of the NIF can
         | crash the entire application. On the other hand, they have
         | wildly better performance than ports, which have to operate
         | through STDI/O.
         | 
         | The Rust / BEAM memory sharing problem does exist, but it's not
         | nearly as bad as in more traditional C NIFs, because almost all
         | C programs leak memory due to bad manual memory management.
         | Hence all the buzz about Elixir+Rust.
        
           | throwawaymaths wrote:
           | ports can be dangerous! One time my server lost performance
           | because of a lot of zombie processes.
        
           | toast0 wrote:
           | I personally include port drivers in with ports, which gives
           | you the same level of shared runtime environment as NIFs,
           | with the benefits and drawbacks. Sometimes it makes more
           | sense to interface as a port rather than as a function. Of
           | course, sometimes it makes more sense to interface as a
           | C-node rather than either; then you can be on a totally
           | isolated machine, and the C-node can even crash or otherwise
           | disable the whole OS and your Erlang node will be fine.
        
             | OkayPhysicist wrote:
             | What's the benefit of a port driver over a NIF?
        
       | waynesonfire wrote:
       | IO in erlang is slow, is Rustler a good candidate to improve IO
       | intensive applications?
        
         | throwawaymaths wrote:
         | Where did you get this idea? Depending on your task, Erlang can
         | be very fast with IO because it will aggressively use
         | writev/readv instead of write. Obviously, you can do this if
         | you "know about it" in low level langs, but it might be a pain.
         | 
         | Erlang is generally considered to be compute-slow (which is
         | generally the case without dropping to nifs).
        
         | weatherlight wrote:
         | I/O in beam languages is considered pretty fast, are you sure
         | you aren't mistaken?
        
         | toast0 wrote:
         | Is IO in Erlang slow? I never got that impression; iolists are
         | a good fit for scatter/gather I/O, which reduces copying, and
         | Erlang supports kqueue, epoll, and I believe similar on
         | Windows. I don't follow Erlang on Linux closely, so I don't
         | know if there's any movement towards io_uring, which does seem
         | promising to help with throughput.
         | 
         | Either way, I wouldn't expect doing I/O in NIFs or ports to
         | substantially improve throughput, unless you're also moving
         | significant processing into that layer as well, or you're going
         | to end up doing substantially the same level of marshaling work
         | as ERTS does, just in a different language. Setting up a
         | different set of kqueue/epoll descriptors sounds like a lot of
         | work for not much gain too, IMHO; again, maybe io_uring would
         | be useful, but I think you'd be better served to bite the
         | bullet and integrate it with ERTS.
        
         | sph wrote:
         | IO in Erlang is faster than many other managed languages,
         | thanks to stuff like IO Lists that are dealt with very
         | efficiently through iovec syscalls (readv, writev).
         | 
         | Then add efficient pattern matching for binary data, and
         | networked servers on the BEAM are the most ergonomic than any
         | other language.
         | 
         | All this stuff that the BEAM offers you out of the box can be
         | replicated in any native language with a lot of boilerplate and
         | ceremony.
         | 
         | Your "Hello, <name>" webapp in Rust will probably need two
         | allocations and a string concatenation, while on the BEAM, if
         | constructed as an iolist, it's a single writev syscall, using a
         | static "Hello, " string and a shared "<name>" reference from
         | the parsed HTTP data.
        
       ___________________________________________________________________
       (page generated 2023-04-13 23:00 UTC)