On the one hand, it's nice to see Ruby and the Ruby tooling system getting some love.
On the other, I'm not sure if this is really needed. Most of this stuff already works fine in Ruby with Bundler. Did you know that Bundler already has a really nice syntax for inline requirements for single-file scripts?[0] Seems like a lot of people forgot. Installing Ruby hasn't generally been much of a hassle either AFAIK. Bundler also doesn't seem to have the Python venv problem - it works fine for keeping a bunch of gem versions around in the same Ruby install and only activating the specified ones. I think Gemfile and Gemfile.lock is what Python always wished they had. I guess more speed never hurt, but it never felt like bundler was painfully slow for me, even on huge codebases. So is there really a big win here?
Though I guess plenty of Python gurus probably feel the same way about the uv craze when their existing tooling works well enough for them.
It's fun to see package management improvements move full circle—lessons from Ruby package management contributed to Rust, Rust is helping improve package management for Python, and now Python package management is inspiring improvements for Ruby!
I'm sure rv is great, but am I the only one who needs one such tool not only for Ruby, but also Python, JavaScript, and Java, at least, and finds it weird to run 4+ of those?
In theory it would be nice to have one tool for all languages but I think it's never going to be practical because programming languages can be different in arbitrary ways. I can't imagine how the same tool could ever be ergonomic for managing projects written in C++, Scheme, Haskell and Bash for example. Mise (and other tools for managing development environments like Flox and asdf – I prefer Flox myself) only implement a subset of the features of languages specific tools like cargo/uv/rv. For example cargo can do all of this out of the box (and you can also extend it with more subcommands):
* manage dependencies
* format and lint code
* publish package on crates.io
* open the project documentation
* install binaries
* build/run the project
* run tests
* run benchmarks
Uv/rv don't (yet?) do all of that but they also manage Ruby/Python versions (which is done separately by rustup in Rust).
We've been using mise since it was called rtx at $DAYJOB, and it's caused many a headache (mostly around upgrades/backcompat/etc.). We use it both on dev machines and in CI. In spite of that, it’s decent at what it does, and I wouldn’t soon replace it with individual version managers, given that we have similar needs.
However…more than once we've seen language runtimes that used to be available exclusively via plug-ins be migrated to be internal to mise, which broke everyone's setups in strange and hilarious ways, and caused countless hours of debugging.
Less bad overall than using individual runtime version managers for sure. But the next time mise costs us a bunch of hours fixing multiple engineers' setups, I intend to find another solution, even if that means writing my own. It’s burned us nearly one too many times.
It looks cool but I feel this kind of tool is only useful if Ruby is the only language you use. I have to manage several runtimes for most projects. I've used asdf for years and recently switched to mise: these tools already download pre compiled binaries for Ruby, plus pretty much any other language runtime.
It's likely that you get better per language features for something specific to the language though. We end up in exactly the same kind of frustration, that for some random project you need this specific tool that does dependency management of the specific runtime. asdf and mise both respect a .tool-versions file, I'd rather see things go more in that direction with some kind of standard.
A flake.nix file plus a direnv `.envrc` file with `use flake` has solved this for me.
When I cd into a project directory I get all of the tools that project needs, at the exact versions they were tested with. When I cd out of the directory, they go away. If the dependencies are well behaved (e.g. they don't do any self-modification, which is annoyingly common in the npm world) then it's often pretty easy to track all of your deps this way, imported from your npm package-lock.json or similar.
Ask your favorite LLM to write your flake.nix file for you, they're pretty good at it. I've been able to drop all of the bespoke language-specific tool versioning stuff `nvm`, `uv`, `rvm`, etc for all my personal projects, and it makes it easy to add deps from outside the language-specific package managers, like ffmpeg and lame.
If you still want to package your stuff natively for the language ecosystem, you still need all the usual metadata and you also want to specify version constraints for your dependencies and so on.
Typically I wire up something like uv or rv (or Poetry or Bundler, which are fine but slower) to shell activation using Devenv, then autogenerate the Nix package from the language-native dependency specification files.
mise is really nice in this respect in that it manages the tools and the environment, so you don't need direnv as well. It also has hooks for running arbitrary commands when you cd in (although you can do that with direnv because it basically just runs .envrc as a script).
nix manages the environment too, all direnv is doing in my setup is automatically entering and leaving environments based on my current working directory. Looks like mise does that automatically, which is neat.
mise looks nice, uses PATH manipulation rather than asdf's slow wrappers, and it supports Windows, which is a point over nix. nix only supports unixy environments like Linux, Mac, and WSL.
What might tempt a mise user to try nix are its just truly stupendous collection of packages, so more tools are available. You can also easily add your own packages, either upstream or privately. nix is bigger, more ambitious, more principled, but more complicated. You can build an entire fully-reproducible operating system from a short nix config. It's really cool! But also a lot more to learn, more surface area, more places to get confused or to spend time fiddling with configs rather than solving the actual problem.
mise uses `uv` as a backend for some python things (like python tools via `uvx`). If `rv` develops in the same direction as `uv` then it could be the default backend for `mise` ruby things.
I've been very happy with `mise` since switching from asdf, and also very happy with uv in general. I think they play nice together.
I agree with the sentiment as I also use asdf but feel at this stage this critique of the project feels more than a little unfair.
We really don’t have the features they’ve been discussing including the npx like feature and easily just run Ruby without installer headaches that it seems they’ve gone after solving.
Reframing, id like to ask that .tool-versions be supported as a place where we can define Ruby versions. Then both tools with a little tweaking could pretty much be used side by side.
I don't think I really criticized the project. I said it was cool, I had a look at it. I just put down that I think there are pros and cons to the single language approach and, for me, the cons outweigh the pros.
Wait, how do you get precompiled Rubies with mise? I still have to compile with default settings, and the docs only mention that it uses ruby-build behind the scenes: https://mise.jdx.dev/lang/ruby.html
I don't think you can. I also don't know why people care so much about it - I work full time with ruby and compiling a new version, which maybe takes 10 minutes, a couple times a year is no big deal.
I think it comes mostly from CI environments that start entirely clean before every run. 10 minutes every time a commit is pushed is not pleasant. That's not how I'd like CI to work, but sadly it seems to be the current state of things.
One thing I love about Ruby is it never devolved into ?VM hell like Python did. Yes, there are a bunch of ruby version managers, but there's only one bundler no matter how you get get ruby installed. I like some ideas here, but I'm also afraid this could be step one toward that python nightmare.
It seems pretty different in that rv waited to take inspiration from a relatively clear winner in an entirely different ecosystem, after quite some time. I think it makes sense to be optimistic.
Static analysis through type hints brings plenty of benefits to a dynamic language, such as helping to eliminate bugs at runtime (albeit not perfectly) and making it easier to grok a codebase. It’s a trade off and Ruby is as dynamic as it gets. But there is a point to it
My beautiful experience with sorbet: Yeah, ducktyping? We don't do that here.
Depending on a library that uses ducktyping (like any sane library following the Ruby conventions)? Good luck writing a wrapper for it. Or just disable type checking.
This goes so much against the Ruby vibe that I advise you to just go and use Rust instead if you hate Ruby that much that you want to butcher it with types.
Sorbet can actually make programs crash at runtime if a variable's type doesn't match its annotation, right? It's not as busted as some other gradual typing implementations.
Many smart engineers (including Guido) disagree with you, and have added static types to Python, Javascript, Dart, Elixir, Hack and surely some I'm forgetting.
This looks like a really nice improvement to the Ruby ecosystem. Great job and thank you to those involved.
I've definitely felt the awkwardness of gems being so compartmentalized by project that using system level dev tools that I like to have available for all my projects feel out of place within my project's Bundler-centric world.
> We expect to be able to silently run equivalents of both rvm install and bundle install at the beginning of every bundle exec,
Do I understand right it doesn't use bundler code for resolving gem requirements dependency tree, but uses it's own code meant to be compatible? Hmmm.
And also producing the `Gemfile.lock`, which has had kind of a lot of churn in bundler, which bundler has had to work to keep from breaking for people even when it's assumed they're all using (different versions of) bundler.
If I understand correctly, rvm/rbenv only install Ruby versions, and you use bundler to install dependencies. rv seems to manage everything (like uv in Python) – Ruby versions and dependencies, and adds things on top of that (like `rv tool` for global tools installation).
"Not a version manager, or a dependency manager, but both of those things and more. I’m currently calling this category a “language manager”, but if you have a better name idea, let me know!"
Rust is the new C. Go had a shot but went in an applications direction. I predict that very soon, perhaps even inside of three decades, Rust will become the dominant, first-choice systems programming language.
It's important to note that Microsoft's choice of Go for tsgo was because it would be easier to port the existing TypeScript codebase due to the structural similarity of TypeScript and Go. If writing from scratch, they likely would not have chosen Go.
Which is not to say that Go can't do well in tooling. Only that Go was not necessarily their first choice.
MS uses Go for tsc because they are basically doing a line by line rewrite of tsc from typescript to Go.
It's impossible to do this kind of rewrite from a GC language to a non GC one, especially Rust where the object soup of typescript will probably cause the borrow checker to explode.
I think that if MS or someone else decided to write a typescript type checker from scratch there is a high chance Rust will be chosen.
I think Go is going away. It occupies such a weird niche. People have said it's good for app backends, but you should really have exceptions (JS, Py, Java) for that sort of thing. For systems, just use Rust or worst case C++. For CLIs, it doesn't really matter. For things where portability matters like WASM, can't use Go. Bad syntax and type system on top of it.
What if Google spent all that time and money on something from the outside instead of inventing their own language? Like, Microsoft owns npm now.
I always thought of Go as a middle ground between C and Python. From C it gets simple syntax, from Python - "batteries included" part.
Deserializing JSON and XML is a breeze from my experience. And it's available out of the box. But I guess C++ will get there with reflection having been approved in C++26.
So I don't think it will go away (in the coming years at least), since a lot of tools is written in it.
Maybe - but in this case, Ruby is written in C, it uses C extensions when performance matters, but tooling for the Ruby language itself is all in Ruby. Rust isn't replacing the use of C in the core of Ruby (yet) - it's stepping in to the area where Ruby would have been traditionally used.
Similar thing is in motion with the JS toolchains. Rewriting in Rust is easier than rewriting in C, but why didn't they previously rewrite in something like C++ or Go? I'm guessing because people were simply not interested.
As a long-time Rubyist and recent Python dabbler (due to pytorch) this is exciting! Uv and uvx certainly are great improvements in the Python ecosystem, but still have some quirks that I wonder how they will handle with rv:
- By default uv is creating isolated environments in the project directory and will download all dependencies over the network. For small stuff this isn't too bad, but re-downloading 700mb pytorch each time you clone a repo gets annoying very fast. Of course there are trade-offs with running updates less frequently (and uv has flags such as --offline and --refresh to avoid or force online access) but more sensible default behavior would be nice so that uv (and rv) keep you on the happy path during developing. Maybe updates could be run in the background by default.
- Also because the environments aren't shared in any way, each project directory consume a lot of disk space (10x checkouts = 10x pytorch on disk). More sensible caching across environments would be nice (links?).
- I am wondering if rv will support version operators such as rv install "~> 3.4.4" to get ruby ">= 3.4.4, < 3.5.0", which I think would help ensure everyone is running Ruby versions with security patches applied.
- uv includes the pip sub-command (similar to using gem install rather than bundle add) but because the environments are isolated this feels rather weird and I haven't really understood in which cases you should not just use "uv add" to update your project dependencies.
- Uv tries hard to support migration from legacy Python projects which don't have a pyproject.toml, but the Python eco-system is too fragmented for this to always work. I hope rv can avoid adding new config files, but really stick to the existing Gemfile approach.
- If a Python package includes a script with a different name than the package then the syntax is a bit annoying ('uvx --from package script' but not 'uvx script --from package' because this would get passed to the script). Uv already uses square brackets for optional project dependencies (e.g. 'uvx --from huggingface_hub[cli] hf') but since Ruby doesn't have these, maybe this would be an option for rv.
uv has been the greatest development in the python ecosystem in the last decade.
super excited about rv! PLEASE, enable sponsorship on github.com or elsewhere. I want to donate $$$!!!
He he. If this article isn't proof that people don't really want "do just one thing and do it well" (besides the million flags of ls and find), nothing is :-)
Has anyone ever actually had anything break from a Ruby version update? I know Matz basically never does breaking changes, last I remember is the 1.8.7 -> 1.9.2 update...
I've only ever just straight up downloaded the source and installed it myself, never had any issues with Ruby updates...
Depends what you mean by "break". There have been backwards-incompatible changes, but as you say, very few since the 1.8.7 to 1.9.X jump.
I can think of one meaningful breaking change going from 2.7 to 3.0, where the longtime behavior of creating an implicit "options hash" as the last argument to a method was finally removed. It was gradual though. First we got keyword arguments. Then keyword arguments got faster. Then there were two versions of warnings about the removal of the old, implicit options hash. Thus if you really wanted to kick the can down the road, you had about 5 years where you could be on a "supported" Ruby version without having fixed your code. Plus the change required was relatively simple outside of a few edge cases.
The best part was that most of the community was pretty good about upgrading gems across the years of warnings we had for this. Hats off to the maintainers and contributors for that!
This is cool! A frequent problem I've had with bundler is when the Gemfile lists a newer version of a gem (stringio) but the older version has already been activated. If you can get rid of such errors I would be so happy! Also I've had to frequently update bundler too often when updating a Rails site.
Yes, this is due to the effort to extract stdlib code into gems https://stdgems.org/
In your case, StringIO use to just be stdlib code so bundler (or rubygems) uses it. Later on it became a gem, so by requiring it before reading the Gemfile, bundler run into this problem of already having loaded the wrong version.
Everytime this happens the bundler team has to modify bundler, and as a user the fix is to upgrade bundler.
Is it really a name collision when they're effectively completely different namespaces? For example, no one thinks Rust's `cargo` might be the same thing as Ruby's obscure `cargo` library.
My lazy heuristic is to use nix-locate to search through the 100k packages in Nixpkgs, e.g.:
> nix-locate -r 'bin/uv'
Not perfect, but sort of useful for choosing names for executables for internal corporate projects, little wrapper scripts, etc. It's definitely still possible to find reasonable names!
But I've never done the analysis of such short names yet :D
On the one hand, it's nice to see Ruby and the Ruby tooling system getting some love.
On the other, I'm not sure if this is really needed. Most of this stuff already works fine in Ruby with Bundler. Did you know that Bundler already has a really nice syntax for inline requirements for single-file scripts?[0] Seems like a lot of people forgot. Installing Ruby hasn't generally been much of a hassle either AFAIK. Bundler also doesn't seem to have the Python venv problem - it works fine for keeping a bunch of gem versions around in the same Ruby install and only activating the specified ones. I think Gemfile and Gemfile.lock is what Python always wished they had. I guess more speed never hurt, but it never felt like bundler was painfully slow for me, even on huge codebases. So is there really a big win here?
Though I guess plenty of Python gurus probably feel the same way about the uv craze when their existing tooling works well enough for them.
[0] https://bundler.io/guides/bundler_in_a_single_file_ruby_scri...
It's fun to see package management improvements move full circle—lessons from Ruby package management contributed to Rust, Rust is helping improve package management for Python, and now Python package management is inspiring improvements for Ruby!
I'm sure rv is great, but am I the only one who needs one such tool not only for Ruby, but also Python, JavaScript, and Java, at least, and finds it weird to run 4+ of those?
I put my hope in mise-en-place - https://mise.jdx.dev
What do people think? One tool per language, or one to rule them all?
In theory it would be nice to have one tool for all languages but I think it's never going to be practical because programming languages can be different in arbitrary ways. I can't imagine how the same tool could ever be ergonomic for managing projects written in C++, Scheme, Haskell and Bash for example. Mise (and other tools for managing development environments like Flox and asdf – I prefer Flox myself) only implement a subset of the features of languages specific tools like cargo/uv/rv. For example cargo can do all of this out of the box (and you can also extend it with more subcommands):
* manage dependencies
* format and lint code
* publish package on crates.io
* open the project documentation
* install binaries
* build/run the project
* run tests
* run benchmarks
Uv/rv don't (yet?) do all of that but they also manage Ruby/Python versions (which is done separately by rustup in Rust).
We've been using mise since it was called rtx at $DAYJOB, and it's caused many a headache (mostly around upgrades/backcompat/etc.). We use it both on dev machines and in CI. In spite of that, it’s decent at what it does, and I wouldn’t soon replace it with individual version managers, given that we have similar needs.
However…more than once we've seen language runtimes that used to be available exclusively via plug-ins be migrated to be internal to mise, which broke everyone's setups in strange and hilarious ways, and caused countless hours of debugging.
Less bad overall than using individual runtime version managers for sure. But the next time mise costs us a bunch of hours fixing multiple engineers' setups, I intend to find another solution, even if that means writing my own. It’s burned us nearly one too many times.
It looks cool but I feel this kind of tool is only useful if Ruby is the only language you use. I have to manage several runtimes for most projects. I've used asdf for years and recently switched to mise: these tools already download pre compiled binaries for Ruby, plus pretty much any other language runtime.
It's likely that you get better per language features for something specific to the language though. We end up in exactly the same kind of frustration, that for some random project you need this specific tool that does dependency management of the specific runtime. asdf and mise both respect a .tool-versions file, I'd rather see things go more in that direction with some kind of standard.
A flake.nix file plus a direnv `.envrc` file with `use flake` has solved this for me.
When I cd into a project directory I get all of the tools that project needs, at the exact versions they were tested with. When I cd out of the directory, they go away. If the dependencies are well behaved (e.g. they don't do any self-modification, which is annoyingly common in the npm world) then it's often pretty easy to track all of your deps this way, imported from your npm package-lock.json or similar.
Ask your favorite LLM to write your flake.nix file for you, they're pretty good at it. I've been able to drop all of the bespoke language-specific tool versioning stuff `nvm`, `uv`, `rvm`, etc for all my personal projects, and it makes it easy to add deps from outside the language-specific package managers, like ffmpeg and lame.
If you still want to package your stuff natively for the language ecosystem, you still need all the usual metadata and you also want to specify version constraints for your dependencies and so on.
Typically I wire up something like uv or rv (or Poetry or Bundler, which are fine but slower) to shell activation using Devenv, then autogenerate the Nix package from the language-native dependency specification files.
mise is really nice in this respect in that it manages the tools and the environment, so you don't need direnv as well. It also has hooks for running arbitrary commands when you cd in (although you can do that with direnv because it basically just runs .envrc as a script).
Flake.nix is nix specific I would guess?
nix manages the environment too, all direnv is doing in my setup is automatically entering and leaving environments based on my current working directory. Looks like mise does that automatically, which is neat.
mise looks nice, uses PATH manipulation rather than asdf's slow wrappers, and it supports Windows, which is a point over nix. nix only supports unixy environments like Linux, Mac, and WSL.
What might tempt a mise user to try nix are its just truly stupendous collection of packages, so more tools are available. You can also easily add your own packages, either upstream or privately. nix is bigger, more ambitious, more principled, but more complicated. You can build an entire fully-reproducible operating system from a short nix config. It's really cool! But also a lot more to learn, more surface area, more places to get confused or to spend time fiddling with configs rather than solving the actual problem.
This is the way. Nix, despite all of its issues, is still the best for reproducible developer environments. I just don't write my own flakes anymore.
Or you can use a nix wrapper like jetify's devbox.
devenv.sh
Nix is too hard.
Mise is way easier.
It also brings awesome task files... With it's usage lib
mise uses `uv` as a backend for some python things (like python tools via `uvx`). If `rv` develops in the same direction as `uv` then it could be the default backend for `mise` ruby things.
I've been very happy with `mise` since switching from asdf, and also very happy with uv in general. I think they play nice together.
I sent jdx this article, so maybe it will happen sooner rather than later
I agree with the sentiment as I also use asdf but feel at this stage this critique of the project feels more than a little unfair.
We really don’t have the features they’ve been discussing including the npx like feature and easily just run Ruby without installer headaches that it seems they’ve gone after solving.
Reframing, id like to ask that .tool-versions be supported as a place where we can define Ruby versions. Then both tools with a little tweaking could pretty much be used side by side.
I don't think I really criticized the project. I said it was cool, I had a look at it. I just put down that I think there are pros and cons to the single language approach and, for me, the cons outweigh the pros.
Wait, how do you get precompiled Rubies with mise? I still have to compile with default settings, and the docs only mention that it uses ruby-build behind the scenes: https://mise.jdx.dev/lang/ruby.html
I don't think you can. I also don't know why people care so much about it - I work full time with ruby and compiling a new version, which maybe takes 10 minutes, a couple times a year is no big deal.
I think it comes mostly from CI environments that start entirely clean before every run. 10 minutes every time a commit is pushed is not pleasant. That's not how I'd like CI to work, but sadly it seems to be the current state of things.
One thing I love about Ruby is it never devolved into ?VM hell like Python did. Yes, there are a bunch of ruby version managers, but there's only one bundler no matter how you get get ruby installed. I like some ideas here, but I'm also afraid this could be step one toward that python nightmare.
It seems pretty different in that rv waited to take inspiration from a relatively clear winner in an entirely different ecosystem, after quite some time. I think it makes sense to be optimistic.
I am so excited about this!! Ruby tooling is already pretty good, but we can do better. I will try to contribute. Now we just need types
Please no types... They're worse than pointless for a dynamically typed language.
Static analysis through type hints brings plenty of benefits to a dynamic language, such as helping to eliminate bugs at runtime (albeit not perfectly) and making it easier to grok a codebase. It’s a trade off and Ruby is as dynamic as it gets. But there is a point to it
My beautiful experience with sorbet: Yeah, ducktyping? We don't do that here.
Depending on a library that uses ducktyping (like any sane library following the Ruby conventions)? Good luck writing a wrapper for it. Or just disable type checking.
This goes so much against the Ruby vibe that I advise you to just go and use Rust instead if you hate Ruby that much that you want to butcher it with types.
Pyright catches an awful lot of dumb mistakes I make in Python.
Sidenote, but you might also want to give basedpyright a try (basically FOSS Pylance reimplementation): https://docs.basedpyright.com/
Sorbet can actually make programs crash at runtime if a variable's type doesn't match its annotation, right? It's not as busted as some other gradual typing implementations.
Oh exactly what I wanted - runtime overhead, on top of its lack of ability to accomodate ducktyped external dependencies in any sane way.
It does welcome nil proliferation though! Just sprinkle some `nilable` around and you're set to continue the actual scourge of the language.
Many smart engineers (including Guido) disagree with you, and have added static types to Python, Javascript, Dart, Elixir, Hack and surely some I'm forgetting.
This looks like a really nice improvement to the Ruby ecosystem. Great job and thank you to those involved.
I've definitely felt the awkwardness of gems being so compartmentalized by project that using system level dev tools that I like to have available for all my projects feel out of place within my project's Bundler-centric world.
> We expect to be able to silently run equivalents of both rvm install and bundle install at the beginning of every bundle exec,
Do I understand right it doesn't use bundler code for resolving gem requirements dependency tree, but uses it's own code meant to be compatible? Hmmm.
And also producing the `Gemfile.lock`, which has had kind of a lot of churn in bundler, which bundler has had to work to keep from breaking for people even when it's assumed they're all using (different versions of) bundler.
The more tools the better. Thanks!
As an idea: add advantages compared to rvm, rbenv, etc. Or a comparison table
> Ruby Versions: Ruby 3.4.1 and up
It turns out that this is only for the latest ruby versions :(
But I will follow the development!
> add advantages compared to rvm, rbenv, etc
If I understand correctly, rvm/rbenv only install Ruby versions, and you use bundler to install dependencies. rv seems to manage everything (like uv in Python) – Ruby versions and dependencies, and adds things on top of that (like `rv tool` for global tools installation).
"Not a version manager, or a dependency manager, but both of those things and more. I’m currently calling this category a “language manager”, but if you have a better name idea, let me know!"
Language Orchestrator?
fast installs will be great. compiling ruby is the only slow part left in our provisioning process.
why are you compiling ruby during provisioning?
to this end I have been deploying with the fullstaq-ruby builds for some years now.
I find it interesting how Rust is gaining momentum in tooling like uv and now rv.
Rust is the new C. Go had a shot but went in an applications direction. I predict that very soon, perhaps even inside of three decades, Rust will become the dominant, first-choice systems programming language.
Go can do just as well in tooling.
Microsoft chose Go for tsc rewrite. https://devblogs.microsoft.com/typescript/typescript-native-...
And then there's esbuild, also in Go, which revolutionized web bundling speed https://esbuild.github.io
It's important to note that Microsoft's choice of Go for tsgo was because it would be easier to port the existing TypeScript codebase due to the structural similarity of TypeScript and Go. If writing from scratch, they likely would not have chosen Go.
Which is not to say that Go can't do well in tooling. Only that Go was not necessarily their first choice.
How is Go structurally similar to TypeScript?
It doesn't even have advanced generics like TypeScript, nor union types. No classes and no heritance either.
Unless you have a source, I'd say that's a very debatable speculation.
My guess is they chose Go for the same reason most users do: it's good enough, easy to grasp, has a decent std lib and is easy to grasp.
https://www.youtube.com/watch?v=10qowKUW82U
Around the 13 minute mark, Anders goes into it. IIRC, the big things were the GC and them both supporting cyclic data structures.
Makes sense. Cyclic data with Rust is not trivial, to put it mildly. And GC does make things much easier.
GC vs no GC will impact your code structure more than anything else.
MS uses Go for tsc because they are basically doing a line by line rewrite of tsc from typescript to Go.
It's impossible to do this kind of rewrite from a GC language to a non GC one, especially Rust where the object soup of typescript will probably cause the borrow checker to explode.
I think that if MS or someone else decided to write a typescript type checker from scratch there is a high chance Rust will be chosen.
I love both Go and Rust but Go is GC no? Where rust shines is on its safety at compile time and lifetime/borrow/memory model imho
both are awesome tools!
GC is ok for these use cases. In fact with such short-lived processes, GC is probably not even running before it terminates.
I think Go is going away. It occupies such a weird niche. People have said it's good for app backends, but you should really have exceptions (JS, Py, Java) for that sort of thing. For systems, just use Rust or worst case C++. For CLIs, it doesn't really matter. For things where portability matters like WASM, can't use Go. Bad syntax and type system on top of it.
What if Google spent all that time and money on something from the outside instead of inventing their own language? Like, Microsoft owns npm now.
I always thought of Go as a middle ground between C and Python. From C it gets simple syntax, from Python - "batteries included" part.
Deserializing JSON and XML is a breeze from my experience. And it's available out of the box. But I guess C++ will get there with reflection having been approved in C++26.
So I don't think it will go away (in the coming years at least), since a lot of tools is written in it.
Maybe - but in this case, Ruby is written in C, it uses C extensions when performance matters, but tooling for the Ruby language itself is all in Ruby. Rust isn't replacing the use of C in the core of Ruby (yet) - it's stepping in to the area where Ruby would have been traditionally used.
Similar thing is in motion with the JS toolchains. Rewriting in Rust is easier than rewriting in C, but why didn't they previously rewrite in something like C++ or Go? I'm guessing because people were simply not interested.
Finally Linus accepted it into Linux.
It's his birthday today btw hbd
It is not his birthday. Today is my birthday and you almost made me very excited
Torvalds was right all along to hold out against C++.
As a long-time Rubyist and recent Python dabbler (due to pytorch) this is exciting! Uv and uvx certainly are great improvements in the Python ecosystem, but still have some quirks that I wonder how they will handle with rv:
- By default uv is creating isolated environments in the project directory and will download all dependencies over the network. For small stuff this isn't too bad, but re-downloading 700mb pytorch each time you clone a repo gets annoying very fast. Of course there are trade-offs with running updates less frequently (and uv has flags such as --offline and --refresh to avoid or force online access) but more sensible default behavior would be nice so that uv (and rv) keep you on the happy path during developing. Maybe updates could be run in the background by default.
- Also because the environments aren't shared in any way, each project directory consume a lot of disk space (10x checkouts = 10x pytorch on disk). More sensible caching across environments would be nice (links?).
- Using uv to turn Python files into standalone/self-contained scripts is really great (https://peps.python.org/pep-0723/) and I hope rv can mirror this capability well. Because the lock file isn't included in the script header it requires some configuration options to make runs repeatable (e.g. https://docs.astral.sh/uv/guides/scripts/#improving-reproduc...).
- I am wondering if rv will support version operators such as rv install "~> 3.4.4" to get ruby ">= 3.4.4, < 3.5.0", which I think would help ensure everyone is running Ruby versions with security patches applied.
- uv includes the pip sub-command (similar to using gem install rather than bundle add) but because the environments are isolated this feels rather weird and I haven't really understood in which cases you should not just use "uv add" to update your project dependencies.
- Uv tries hard to support migration from legacy Python projects which don't have a pyproject.toml, but the Python eco-system is too fragmented for this to always work. I hope rv can avoid adding new config files, but really stick to the existing Gemfile approach.
- If a Python package includes a script with a different name than the package then the syntax is a bit annoying ('uvx --from package script' but not 'uvx script --from package' because this would get passed to the script). Uv already uses square brackets for optional project dependencies (e.g. 'uvx --from huggingface_hub[cli] hf') but since Ruby doesn't have these, maybe this would be an option for rv.
uv doesn't redownload every dep every time. If the dep is the same, it uses a hardlink: no additional download, no additional space taken.
Pip subcommands are here to ease the transition from the old ecosystem to the new.
uv has been the greatest development in the python ecosystem in the last decade. super excited about rv! PLEASE, enable sponsorship on github.com or elsewhere. I want to donate $$$!!!
He he. If this article isn't proof that people don't really want "do just one thing and do it well" (besides the million flags of ls and find), nothing is :-)
Has anyone ever actually had anything break from a Ruby version update? I know Matz basically never does breaking changes, last I remember is the 1.8.7 -> 1.9.2 update...
I've only ever just straight up downloaded the source and installed it myself, never had any issues with Ruby updates...
Depends what you mean by "break". There have been backwards-incompatible changes, but as you say, very few since the 1.8.7 to 1.9.X jump.
I can think of one meaningful breaking change going from 2.7 to 3.0, where the longtime behavior of creating an implicit "options hash" as the last argument to a method was finally removed. It was gradual though. First we got keyword arguments. Then keyword arguments got faster. Then there were two versions of warnings about the removal of the old, implicit options hash. Thus if you really wanted to kick the can down the road, you had about 5 years where you could be on a "supported" Ruby version without having fixed your code. Plus the change required was relatively simple outside of a few edge cases.
The best part was that most of the community was pretty good about upgrading gems across the years of warnings we had for this. Hats off to the maintainers and contributors for that!
They moved quite some things out of the standard library so you need require/gems for some things which used to be batteries included.
Also small changes like File.exists? being deprecated and then removed.
This is cool! A frequent problem I've had with bundler is when the Gemfile lists a newer version of a gem (stringio) but the older version has already been activated. If you can get rid of such errors I would be so happy! Also I've had to frequently update bundler too often when updating a Rails site.
Just using `bundle exec` should handle that - that's what bundler is for.
Yep, didn't work.
Yes, this is due to the effort to extract stdlib code into gems https://stdgems.org/
In your case, StringIO use to just be stdlib code so bundler (or rubygems) uses it. Later on it became a gem, so by requiring it before reading the Gemfile, bundler run into this problem of already having loaded the wrong version.
Everytime this happens the bundler team has to modify bundler, and as a user the fix is to upgrade bundler.
You can see they had to vendor a lot of code from default gems to avoid this problem: https://github.com/rubygems/rubygems/tree/c230844f2eab31478f...
Nice André!
Very unfortunate name collision with rv for R (https://github.com/A2-ai/rv).
Is it really a name collision when they're effectively completely different namespaces? For example, no one thinks Rust's `cargo` might be the same thing as Ruby's obscure `cargo` library.
It's not a library. It's an executable that needs to be on the PATH to use it. And the executable has the exact same name.
At this point, I think the namespace for 2-3 character CLI binaries has probably been clobbered several times over.
My lazy heuristic is to use nix-locate to search through the 100k packages in Nixpkgs, e.g.:
> nix-locate -r 'bin/uv'
Not perfect, but sort of useful for choosing names for executables for internal corporate projects, little wrapper scripts, etc. It's definitely still possible to find reasonable names!
But I've never done the analysis of such short names yet :D
You might use R and Ruby. Wouldn't be unheard of. Alias ftw.
No need because there's chruby and/or asdf that do it elegantly. Looks like NIH reventing rvm.