7 ms·
Elixir for Ruby developers: the three most important differences
- tensakai 3y agoI love Elixir and I have worked with it in past 2 years. (Specially in China) But I have been free because the company was broken. I really want to keep writing Elixir, are there any remote job opportunities here? P.S. I also have some experience of React/Nextjs, Ruby and Scala.
- sreetamdas 3y agoHere's something that might interest you :) https://remote.com/openings https://remote.com/openings
- throwawaymaths 3y agothis is missing the big one: @ does not work at all the same way in ruby vs elixir, it's not even close I would probably also put in "Please for the love of God don't try to turn a genserver into an object" Because many ruby programmers will try.
- john_the_writer 3y agoMostly the dev cycle in Elixir is different. There are no "binding.pry". We're back to putting logs in the code.
- senjin 3y ago`dbg` is relatively new but [IEx.pry](https://hexdocs.pm/iex/IEx.Pry.html https://hexdocs.pm/iex/IEx.Pry.html) has been around for a long itme
- bobwaycott 3y agoUse `dbg` for prying. You can also use `break!` in an `iex` session to manually set breakpoints without modifying your source. Additionally, you can use Erlang’s `:debugger`for visual debugging, and `:observer` for understanding the entire VM when prying is not enough.
- quaunaut 3y agoThis is not nor has not ever been true. Now, you've got `dbg()` and running whatever you're running via `iex -S <whateveryouweredoinghere>`. Prior to `dbg()` you had `IEx.pry()`.
- mberning 3y agoI must have missed where they discuss the type system. They go to great length to explain that there aren’t classes, methods, etc. and showcase modules such as String, but it’s not clear to me how you know what can be passed to String.whatever.
- john_the_writer 3y agoNo classes, but there are types. When looking at the docs (which you'll do often) you'll see the doc. I say you'll be in the docs often because of things like Enum.map which returns a List not a map Enum.map_reduce takes either a List or a Map, but returns a List. Kernel.get_in takes a Map and a List
- ch4s3 3y agoThe basic data types work with modules of the same name generally. String module functions work on UTF8 but strings. If you aren’t sure you can run the h() function in an ice shell on the module and function, e.g. h Kernel.+ or whatever.
- ollysb 3y agoElixir doesn't currently have a type system built into the compiler. There is a separate package Dialyzer which does type checking but it would be fair to characterise it as a bolt-on rather than part of the core tooling. Work is now underway[1] to create a type system based on "set-theoretic types" though this is still considered experimental and may never be added to Elixir. [1] https://elixir-lang.org/blog/2022/10/05/my-future-with-elixir-set-theoretic-types/ https://elixir-lang.org/blog/2022/10/05/my-future-with-elixi...
- bobwaycott 3y agoThe type system has moved from the research phase to in development: https://elixir-lang.org/blog/2023/06/22/type-system-updates-research-dev/ https://elixir-lang.org/blog/2023/06/22/type-system-updates-...
- pavel_lishin 3y agoMy experience with Dialyzer wasn't great a few years ago. The error messages are often counter-intuitive, to the point where hating dialyzer became a meme at work.
- davidw 3y agoWhat kinds of cool things are people doing with Elixir these days, where they feel it's a really good fit for the problem domain?
- ricketycricket 3y agoJust wrapped up a live translation feature that watches an HLS live stream, live transcribes with whisper and then translates into 18 languages. Heavy use of OTP: supervision trees for each stream, ports for managing ffmpeg and receiving audio, async tasks for concurrently submitting chunks to translation API, etc. Transcription and translations provided in real-time via LiveView to about 4,000 viewers. Little over 3 weeks from `mix new` to the live event. Not sure how I could have done it so easily without OTP and LiveView.
- mjfisher 3y agoThat's really cool. Managing ports is something I've done in elixir yet, but managing ffmpeg through elixir could be very useful for a few things in my current area of focus. Can you share any details of how that works? E.g. do you operate on a single HLS chunk at a time, or can you get ffmpeg to separate a continuous audio stream, etc?
- davidw 3y agohttps://github.com/saleyn/erlexec https://github.com/saleyn/erlexec is pretty good for handling external processes. The builtins aren't quite there if you have more complex use cases.
- ricketycricket 3y agodavidw is right that ports are somewhat limited, but I haven't had much trouble doing what I need with FFmpeg in particular. I used the bash wrapper from the docs for Port [^1] and it has worked well. When a stream starts I start a supervisor that then starts a GenServer to manage the port. On init a port is started for FFmpeg (using the above bash wrapper) with args that sends 16-bit PCM audio back to the port through the `handle_info/2` callback. When a new live HLS segment is downloaded by FFmpeg the entire segment's audio is sent to the GenServer all at once (could be a few handle_info/2 calls, but it happens quickly). Since I want to work in small fixed chunks, I send the segment's audio to an AudioBuffer GenServer (started as a sibling under the same supervisor). This buffer uses binary pattern matching to segment the audio in chunks exactly 2 seconds long while keeping any remainder in the GenServer's state for the next buffer event. I then send the chunks to another ChunkBuffer GenServer that pops chunks at 2-second intervals for processing. Since everything is supervised, if (when...) FFmpeg crashes the supervisor just restarts it. Meanwhile, the audio in the buffer is still processing and nothing goes down. There might be a duplicate word or two in the transcription if the restarted port processes a segment again, but everything keeps running smoothly. For even more reliability, I have the application running clustered across four locations in the US, EMEA, and APAC using libcluster[^2]. The stream supervisor is started under a Horde.DynamicSupervisor[^3] with a custom distribution strategy. The strategy prefers the region closest to the company HQ, but if it goes down, the processes will be restarted in another region. [^1]: https://hexdocs.pm/elixir/1.13.4/Port.html#module-zombie-operating-system-processes https://hexdocs.pm/elixir/1.13.4/Port.html#module-zombie-ope... [^2}: https://github.com/bitwalker/libcluster https://github.com/bitwalker/libcluster [^3]: https://github.com/derekkraan/horde https://github.com/derekkraan/horde
- mrcwinn 3y agoI love Elixir, Phoenix and LiveView. A drawback is the size of the community, and as a function of that, availability of libraries for various things. It is not bad. It is also not great. That said, the community itself deserves high marks for their willingness to help and do so in a friendly manner.
- tagamma 3y agoIt's indeed relatively small, but what it may lack in numbers, it makes up for in quality. It's one of the most dedicated, helpful, and friendly communities I've come across. I've personally been surprised by a pro of having a more intimate community: in my experience, this leads to a higher signal-to-noise ratio in discussions and resources. It feels like what I need to get online is more "condensed".
- el_nahual 3y agoThe community is small, but that means that a reasonable question on elixirforums (not a stateless discord/slack, pun intended) has a good chance of: 1. receiving an answer from a core contributor (valim, McCord, etc) 2. Having the answer become part of the documentation for the language or library As an aside, the elixir community has a different didactic approach to many others: the documentation in elixir is genuinely instructive (vs a descriptive reference). As an example, I've been able to download the elixir, Phoenix, and ecto docs and work on an app entirely offline, on an airplane ride, and never felt like I needed to Google anything. A common elixir answer to "where are all the blog posts" is "read the docs. No, seriously."
- Mizza 3y agoI wrote a similar article for Pythonistas: https://joyyo.app/elixir-for-humans-who-know-python https://joyyo.app/elixir-for-humans-who-know-python
- eternityyyy 3y agoI'm curious, what are the chances to python you don't like?
- melx 3y agoNothing personal but I hate blog posts without a date of publication of said post.
- robinbobbin 3y agoSame here. And maybe mention the versions of the languages at the moment the article is written. Some of them add/remove features with each release.
- Mizza 3y agoOk.
- pmontra 3y agoLooking at archive.org it could be from today https://web.archive.org/web/20230000000000*/https://phoenixonrails.com/blog/elixir-for-ruby-developers-the-three-most-important-differences https://web.archive.org/web/20230000000000*/https://phoenixo...
- arrowsmith 3y agoThere's a date at the bottom of the page.
- sp332 3y agoI don’t see one?
- deleted 3y ago[deleted]
- fxn 3y agoThe article section about interpreted vs compiled is incorrect. .exs files are compiled just like .ex files are. The only difference between `elixirc` and `elixir` is that the former creates an artifact on disk, and the latter does not. See https://medium.com/@fxn/how-does-elixir-compile-execute-code-c1b36c9ec8cf https://medium.com/@fxn/how-does-elixir-compile-execute-code.... Also, Ruby is as compiled as Elixir is. Compiled vs interpreted is blurred the moment you compile to bytecode run by a VM. An artifact is not a fundamental difference.
- atonse 3y agoThis is a good point because in elixir metaprogramming you can actually have some things happen at compile time. The frameworks use this for performance in a few places. So if you had different behavior for ex and exs that would cause developer confusion.
- benatkin 3y agoYeah, if you don't want the code to run when you're compiling it, don't have it do anything until some function is called. And it would be the same as in another language if you run a program that has no side effects. For instance "python abc.py" will gladly run a abc.py that is empty or has "class ABC: pass" in it.
- josevalim 3y agoTo add to your excellent points: Elixir is compiled ahead of time while Ruby bytecode is generated as the code is loaded, which is probably the source of confusion in this case. This leads to differences such as Ruby meta-programming happening at runtime, Elixir’s at compile time. The Elixir compiler (the Erlang compiler really) can also afford to do more work at compile-time which then leads to different approaches at the JIT level too.
- larksimian 3y agoI'll add that Ruby meta-programming has 2 pseudo-phases(at least in my mind): load time and 'true' run time. They're both technically run time, but smth like a has_many method in rails ActiveRecors runs once when the code is loaded, defines some other methods and doesn't run again while the process is running, normally. You could also be defining methods pretty much whenever, for instance in response to user input, mutating the state of the process from that call onwards. The former is much, much more common than the latter. e. A blurring of the 2 is something like ActiveRecord defining field accessors dynamically once a DB connection is eatablished. You connect to the db and now your User model has email, first_name etc methods, unless you'd defined them already. I'm guessing nothing quite like this could exist for Ecto(I vaguely know this isn't a super good comparison, Ecto is quite different from AR from what I remember). That being said even that would still happen as part of a prod app's 'loading' phase so to speak rathet than during a request cycle.
- ljm 3y agoI would give seasoned Ruby engineers a lot more credit than this article expects. A lot of its examples are just…functions? A lot of the things that are ‘elixir’ are what I learned when I was writing PHP and modding forums.
- manicennui 3y agoA lot of Rails developers don't actually know Ruby.
- bingemaker 3y agoWell a lot of developers think Rails is a programming language. :shrug:
- Alifatisk 3y agoReally???
- pmontra 3y agoIMHO a more fundamental difference is that because of pattern matching and pipelines you'll write code in a very different way and any expectation that Elixir and Ruby are similar will evaporate before the end of the very first day. However many Class.method names in Ruby's standard library have a match as Module.function in Elixir, by design, to ease the migration of developers. Language developers take note, copy from the language you want to lure developers from.