Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Ruby 3.1 (ruby-lang.org)
501 points by sebiw on Dec 25, 2021 | hide | past | favorite | 70 comments


Ruby now has “punning.”

> Values in Hash literals and keyword arguments can be omitted. [Feature #14579]

> {x:, y:} is a syntax sugar of {x: x, y: y}.

> foo(x:, y:) is a syntax sugar of foo(x: x, y: y).

This is going to be controversial and take some getting used to, but I think eventually everyone will love it. It’s not an easy syntax to learn - I remember when this came to JS it took a while to get my head around all the different ways this shorthand was used in the wild.

It’s hard to come up with new syntax that can peacefully coexist with the established language. I think in hindsight it would have been helpful for Ruby if it had done something like square braces instead of brackets for hash literals, or not allowed brackets for blocks. The most ambiguous syntax all involves hash literals vs blocks… this adds to that cognitive load.

But typing out a long hash literal just to capture a bunch of local variables or methods is so common, and the duplication is quite annoying, so on the whole I’m glad this was added and am sure I’ll use it a lot :)


I'll throw myself out there to say that after being forced to read punning in JS for the past 2+ years, I've never come around to it. Sure it's quicker (and I'll admit even nicer) to write, but even after seeing it daily for so long, I still find myself doing double-takes on what I'm looking at, and I need as little as possible of that while reading code.

I'm a little disappointed that Ruby introduced it but no one is forcing me to use it so to each their own (and I'm not writing Ruby or much JS professionally anymore so it doesn't affect me too much).


This feature has such a positive effect on code quality in JS. It makes it easier to give consistent names to variables, and harder to use inconsistent names. You really notice when you write { foo: bar } instead of { foo } and it becomes somewhat of a code smell. Could variable bar be changed to foo? If yes then great, that's one less naming variation you have to remember for 'foo'. Across a whole codebase that can be a significant improvement.


I like how it prevents unnecessary repetition. “An object with foo stored in key foo” { foo: foo } vs “an object containing foo” { foo }


This is because every variable is a piece of abstraction, and this shows you unessisary abstractions! I love it.


>This is going to be controversial and take some getting used to, but I think eventually everyone will love it

It's saving a single character in your example. I can see liking it as solving a minor inconvenience. But love? I don't see that. To me it's just another thing to learn.


Maybe so, for some, but I find:

{width:, height:, x_pos:, y_pos:}

to be much more pleasant than

{width: width, height: height, x_pos: x_pos, y_pos: y_pos}

And the more items you add the more I find it useful. Yeah, it took some getting used to in Javascript after years and years without it, but I personally would not want to go back to not having it.

I'm not crazy about the colon/comma combo, but if I was writing in Ruby I suspect I'd get used to it after a while.


"everyone wants the colon" / Larry Wall. perfect example.


The curly braces in Ruby do an awful lot of work (blocks, procs, lambdas, hashes, interpolation) and I wonder if part of it is because it helped bring Smalltalk and Lisp-related concepts to people who were mostly familiar with C-style languages.

Arguably it was the right call considering where Ruby is now.


I've always wondered what this feature was called and never knew how to Google for it. TIL - thank you.


My question is whether or not rubocop can autocorrect it to whatever. If so, I really dgaf about this.


I wonder, will there be a breaking change for older syntax, where it was previously

  foo x:
    [1,2,3]
Or maybe that "punning" will work only inside of () and {}?


Of course cases where parentheses are omitted will keep working like before, changing this would silently affect huge amounts of code.

See also https://zverok.github.io/blog/2021-12-08-value-omission-debu...


"The following default gems are now bundled gems." Great to see slow removal (or carve out) of rarely used stdlib stuff.

Ruby would benefit from a trimmed down stdlib, where effort could be spent keeping a smaller footprint stdlib more polished than it is today. Turning them into opt-in gems is a good first step.

A few examples:

- `rss` to parse RSS documents/streams

- `win32ole` for Microsoft Windows OLE Automation

- `dbm` for DBM databases

- `abbrev` for finding the shortest unique abbreviation amongst many strings

This page has more details: https://stdgems.org/


Python has a similar issue, with lots of so-called "dead batteries" in the standard library.

https://discuss.python.org/t/pep-594-removing-dead-batteries...


Ruby 3.2 will having much shorter default gem list

https://github.com/ruby/ruby/blob/master/NEWS.md

Just waiting another year!



I was always under the impression that the quality of stdlib was much better than other languages (especially the documentation).


Enumerable alone is enough to outclass many stdlibs. Easily one of my fave things about Ruby, compared to dealing with different types of iterable interfaces (and conversions between them) in other languages.


Love Ruby. Personal language of choice. People keep predicting its death, but it just keeps getting better and better!


You predict something's (or someone's) death, you better kill it on the spot :).


Related: I believe there is ongoing work (not in 3.1) to modify the CRuby implementation to use shapes/hidden classes. This has significant potential to speed things up. More info: https://chrisseaton.com/truffleruby/rubykaigi21/


Thank you Matz and team! Lot of awesome stuff in this release.


No news about Ractors! The new concurrency facilities that Ruby 3.0 introduced. Anyone has an insight if there was any further development on that front?


Correct me if I am wrong but I dont think much has happened in terms of Ractors. But lots of work happening on Fiber and Async.

Edit: LOL ko1 replied [1] on Twitter "ごめんよ。来年頑張るよ " / "Sorry. I'll do my best next year".

@ko1: Thanks for all your work on Ruby.

[1] https://twitter.com/_ko1/status/1474769727109353474


Tons have happened in stabilizing them, 3.0 had lots of Ractor related bugs. But no new Ractors related features no.


IMO the most impactful improvement for Ractors right now needs to come from the community, because third-party Gems with C-extensions need to explicitly opt themselves in as Ractor-safe: https://docs.ruby-lang.org/en/master/doc/extension_rdoc.html...

"By default, all C extensions are recognized as Ractor-unsafe. If C extension becomes Ractor-safe, the extension should call `rb_ext_ractor_safe(true)` at the `Init_` function and all defined method marked as Ractor-safe. Ractor-unsafe C-methods only been called from main-ractor. If non-main ractor calls it, then `Ractor::UnsafeError` is raised."

I've submitted a few such patches for my own personal use, and it's a very trivial change for extensions which keep no state in C-land that would need to be synchronized between Ractors, e.g. https://github.com/dearblue/ruby-extattr/pull/1


I thought TypeProf is really interesting but doesn't seems to get much attention.

I am also wondering if anyone is using RBS in production. Apart from big shops like Stripe / Shopify.


I believe Stripe and Shopify only use RBI in production since Stripe develops Sorbet [0] and Shopify develops Tapioca [1]. Both tools work exclusively with RBI files instead of RBS files afaik. I haven't heard of anyone using RBS in production.

[0] - https://sorbet.org/

[1] - https://github.com/Shopify/tapioca


I'm surprised there doesn't seem to be more interest in type-checking in the Rails community at large (maybe I'm wrong). TypeScript has been make-or-break when choosing a company I apply for.


Ruby's extremely rapid iteration cycle (e.g. by embedding pry for debugging and experimentation), good test coverage, and fast search tools like ripgrep and fzf alleviate a lot of the pain you might get from the lack of static types. There are also gems for schema validation that predate Ruby's type annotations and help with runtime type checking on data coming from the wire or disk.


rails does a lot of metaprogramming, which makes static type checking much harder


What a coincidence, I just started learning a bit of Ruby with an interpreter I'm writing a couple of nights ago.

I will take the opportunity to ask; does anyone have a good introduction to creating Ruby (not Rails) projects? I'm a bit confused between rake, bundle, testing frameworks, how to debug a program or structure a project and I can't seem to find a good up to date resource on that.


I don’t know a great “how to lay out” guide off-hand, but I’ll take a stab at helping with the confusion.

Rake is a Ruby equivalent of Make. Many Ruby gems will include rake tasks (Makefile targets) that can be used to drive pieces of an application. Most of the time your test framework of choice (rspec typically) will include “rake test” as a target for running the tests.

The tests usually live in a folder named “spec”, while application code lives in “lib” and your driver code lives in “bin” or just a top-level file… without some of the Rails initialization glue, you’ll have to do a little work to require files via relative paths or set up the $LOAD_PATH variable, etc.

Bundler is the package manager, and you’ll often see commands like “bundle exec rake”, this is similar in spirit to a virtualenv. Bundler will use the libraries defined in your Gemfile to run the given program (in this case, ‘rake’). The command “bundle” will read the Gemfile and resolve dependencies to concrete versions of libraries and write out a Gemfile.lock for you with all the versions explicitly defined.

For debugging, there are a number of tools out there, but I’m partial to ‘pry’. You add pry to your Gemfile, require it, and then can add a breakpoint by putting a call to “binding.pry” in your source code wherever. This will drop you into a REPL within the context of the program at that point.

pry is useful, but there are some other gems and settings files out there that can make it a little friendlier, pry-byebug comes to mind as having saner keyboard shortcuts iirc.

If you need help with overall file system layout, etc, the best place to look is going to be existing trivial gems on rubygems.org. Granted these will have a couple of minor differences from a “plain” application because they’re packaging as a library (*.gemspec file instead of Gemfile, and usually has a version.rb file somewhere).


Thanks for the awesome reply! This has been really useful, I was mostly confused about bundle/rake now I understand most of the things to through rake but bundle just provides the env, makes sense.

Also I created a project with bundle, which gave me some structure, and downloaded Rubymine which is helping a lot as well, even if it's a tiny project, also it suggests me new cool things Ruby can do which I had not idea about.


Bundler has a nice subcommands for setting up a new gem. Setting up a test framework depends on which one you pick. The big switch from rails is that you get to decide where everything goes. I suggest looking at some recently created gems by prolific rubyists to get a feel for the structure.


I agree with @tinco. If you're doing Ruby development that is not Rails, you probably want to create a gem with Bundler. I'd check out their documentation on the subject which has some good information: https://bundler.io/guides/creating_gem.html. I'd also checkout https://www.learnenough.com/ruby. I haven't walked through the course, but Michael Hartl has been providing Ruby related learning materials for a long time and is a fairly trusted name in the community. I'm sure it's solid.


If you want to make a cli application with ruby i'd suggest thor or dry-cli as a gem(package in other languages).

rake is ruby make... aka a build utility but it can and is used for a variety of things like testing and building and distribution.

minitest is built in and is generally enough. rspec is the other big one and a lot of people like it but it's fairly complicated and it is better to stick to the basic one early on.

as for debugging puts debugging is common(though a lot of things are caught at the testing phase since testing is big with ruby). if you are familiar with debuggers that is also an option with something like vscode or the command line but vscode is more usable(or the rubymine one that is a paid app).


`bundle gem foo` will create a subdirectory `foo` and setup a decent starting skeleton for a gem named 'foo'. I'd maybe suggest 'standard' over 'rubocop' as a linter to begin with.

  foo/
    - foo.gemspec: needs to fix the TODOs to start, and this is where runtime deps will go
    - Gemfile: where your development deps will go
    - Gemfile.lock: built by 'bundle install' do not touch
    - Rakefile: the build system (build gems, push gems, run tests, etc)
    - bin/ drop binary scripts here or delete if you're making a library (generally make them tiny stubs that require "foo" or "foo/application" and call run on the app or something)
    - lib/ this is where you put all your code.  already setup with lib/foo.rb and lib/foo/version.rb which are accessible via `require "foo"` and `require "foo/version"` mostly you'll want to put code under lib/foo/ and then have `lib/foo.rb` be a pile of require statements (ish).
    - spec/ this is where tests go.  bundler will set you up with rspec installed to begin with with a spec_helper.rb already setup (this is where you tweak rspec).  i would suggest using spec/unit/whatever_spec.rb to test lib/foo/whatever.rb and keeping those directory structures roughly in sync for your unit tests.
To get started:

  bundle install  # updates all the gems in the Gemfile (plus the referenced gemspec file) and installs rspec and updated rake and stuff
  bundle exec rake spec  # runs all the spec/ tests
  bundle exec rake # runs rake + rubocop/standard both
  bundle exec rake -T # shows all the rake tasks
  bundle exec rake release # will build and push the gem to rubygems publicly


I really can't wait to use the IRB Autocomplete feature. Aside from the obvious advantage of tabbing (convenience, fewer typos etc), it's a subtle way to improve discoverability of available methods. Very cool.


PSA: Ruby 3.1 isn’t compatible with Rails 7.0.0. There’s a patch in the world that’s coming soon.


You can use the 7-0-stable branch for now - https://github.com/rails/rails/issues/43998#issuecomment-100...


How good is `debug.gem`? I'd be excited to try it if I was still using ruby ...

I'm not using ruby anymore but the debugger experience I had from vscode via the rdebug-ide library a few years ago was _mostly pretty_ nice aside from very performance limitations ... a massive performance improvement on that front must feel great!


What is best way to master Ruby for generalist engineer? I know C++ and Python, JS, Typescript well enough.

Python was easiest, since it took couple of days to master fundamentals and I was writing good code in no time.

Also anyone working on Typescript equivalent for ruby?


Sorbet[0] is probably the closest to what you're looking for. It's not something I would recommend to someone who wants to get started with Ruby, since it would be limiting to learn it as if it was a statically typed language.

[0] https://sorbet.org/


Sorbet is OK if you want to type an app, but falls apart for a lib.

RBS (descs) + Steep (type checker) is a bit younger but I found it more usable in general, especially on the corner cases.


Yeah I've tried setting it up for a library but Sorbet won't pick it up, Tapioca won't pick it up. It'll generate its own types which are exactly what I don't want.

Beyond that, it's too intrusive in the code for me. I could live with 'sig' blocks above methods, but there's an immediate readability cost when you start having to wrap stuff in T.let, T.must, T.nilable, etc.

Personally I'd rather improve my testing skills here too. Knowing how to write a good test is a valuable skill.


If you are already up to speed with many programming languages then getting into Ruby shouldn't be that hard.

Some syntax is a bit quirky (blocks in particular) but if you are solid in OOP then you soon see the beauty of the core class setup.

The primary difference to Python is that everything really is a method call on a object (even if that object is a class).

To master Ruby I would start with toy problems such as Advent of Code.


The main thing that’s different in ruby is the support for and widespread use of metaprogramming.

I’d suggest using metaprogramming (define_method, instance_variable_send, instance_eval, send) to implement a toy ruby-in-ruby DSL is the fastest way to figure out what different.


no exactly the same as js->ts but Crystal language in a typed, compiled lang. with Ruby like syntax but other nice features like Go like concurrency & speed, macros, great C interop. and they are working on an interpreter, too.


Is yjit support available now for more cpu architectures? Super excited to try this out


From the release notes, it looks like it only supports x86-64.

From the bug report [0] it sounds like they may also support ARM64 in the future.

[0] - https://bugs.ruby-lang.org/issues/18229


It's developed at Shopify, where every developer in the company was handed a new M1 this month.

I presume it will support ARM based chips pretty quickly.


>where every developer in the company was handed a new M1 this month

That's pretty interesting. They deploy, I assume to jitted ruby on X64 boxes, but will develop on M1 Macbooks. I suppose they probably have some kind of automated performance/crash/leak/etc regression tests in the pipeline?


I say it in the third person, but I actually joined Shopify in October.

Development can be done locally, or it can be done via on-demand containers in the cloud with the IDE loading the code over a remote mount of the containers filesystem. I'm new to it all, but it's a very slick setup.


Between Ruby and Python, Ruby used to be deemed the slower language. With all recent improvements from the 3x3 initiative and yjit I wonder, does Ruby officially surpassed Python on performance?


did you guys know any updates about the static typing ruby? I wish it could be more like typescript


has this released on stable with the asdf tool? can't wait to try this out!


Sigh... why couldn't they drop the : like js?

  {x:, y:} is a syntax sugar of {x: x, y: y}.


Otherwise you couldn't drop the braces like you currently can when passing hashes to functions.

    x, y = 1, 2

    puts x: x, y: y
    # ==> {:x=>1, :y=>2}

    puts x:, y:
    # ==> {:x=>1, :y=>2}

    puts x, y
    # ==> 1, 2
Which would be inconsistent and annoying.

(and knowing Ruby, I imagine there might be some syntactical ambiguities as well)


I'm ok with having

  x:, y:
but couldn't they drop the : if there are braces to indicate this is a hash?

  {x, y}


{ x }, depending on where you put it, could be a block that returns the value of x.

  5.times { x }
This could either call the given block 5 times, or pass a hash of :x => x as the first argument.


Ah thanks that answers my other question.


I guess because keyword arguments couldn't use the same shorthand if they did.


Because unlike js, ruby chose to use {x, y} as the set literal.


This isn't true; Ruby has no set literal. Sets are provided by a default gem but there is no built-in syntax for them.


Sorry I found this page on Google but did not read the note on top. Looks like it was a proposed feature but was not implemented.

https://dev.to/baweaver/ruby-3-set-literal-3fp9


Ohh since when is that? I've never seen or used that syntax and I sort of like it.


Sorry I found this page on Google but did not read the note on top. Looks like it was a proposed feature but was not implemented.

https://dev.to/baweaver/ruby-3-set-literal-3fp9

Unfortunately it looks like I can't edit or delete that comment now. :embarassed:


I definitely like the clear visible syntax




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: