[HN Gopher] Ruby 3.1.0 Preview 1
       ___________________________________________________________________
        
       Ruby 3.1.0 Preview 1
        
       Author : riffraff
       Score  : 213 points
       Date   : 2021-11-09 10:25 UTC (12 hours ago)
        
 (HTM) web link (www.ruby-lang.org)
 (TXT) w3m dump (www.ruby-lang.org)
        
       | fourseventy wrote:
       | "foo(x:, y:) is a syntax sugar of foo(x: x, y: y)"
       | 
       | This syntax sugar is a nightmare to me. Very confusing and for
       | what? To save 2 keystrokes?
        
         | onlyrealcuzzo wrote:
         | I really wish there was a command to `un-sugar` a script -
         | especially intelligently built into editors.
         | 
         | That way - if you're new to a language and don't want to deal
         | with all the cognitive overhead of syntactic sugar (or if you
         | just find some particular feature really complicated) - you
         | could "un-see" it.
        
         | berkes wrote:
         | I highly doubt that any such feature is introduced to save
         | keystrokes.
         | 
         | If you want to save keystrokes, Ruby is probably not your
         | language. And you also really need to invest some time in your
         | editor/IDE.
         | 
         | The sugar is that it removes redundancy and adds DRY:
         | 
         | > Every piece of knowledge must have a single, unambiguous,
         | authoritative representation within a system.
         | 
         | Now, the value for DRY is minimal here:
         | `referer_acceptence_header: referrer_acceptance_header` is
         | quite easy to spot (and there too: if _these_ are your bugs,
         | you probably need to invest some time in your editor /IDE), but
         | avoiding it alltogether in the language is always nice.
        
         | mostlysimilar wrote:
         | It's only two keystrokes if your parameters are single
         | characters.                 def
         | some_method(with_longer_parameters: with_longer_parameters)
         | do_something(with_longer_parameters)       end
         | 
         | vs                 def some_method(with_longer_parameters:)
         | do_something(with_longer_parameters)       end
        
           | cpb wrote:
           | Is it to spare keystrokes in method definition, or rather, in
           | method invocation?
           | 
           | Your second definition reads that `with_longer_parameters` is
           | a keyword argument with no default.
           | 
           | Still, you've illustrated the keystroke savings with your
           | choice of parameter names :-)
        
             | kule wrote:
             | Yeah, should be invocation, there's a nice example on the
             | feature request (https://bugs.ruby-lang.org/issues/14579):
             | def login(username: ENV["USER"], password:)
             | p(username:, password:)       end
             | login(password: "xxx") #=> {:username=>"shugo",
             | :password=>"xxx"}
        
         | lamontcg wrote:
         | Keyword args are real nice for maintaining API compatibility
         | but they're commonly passed down through the call stack
         | resulting in a lot of:
         | 
         | "foo(arg, my_keyword1: my_keyword1, my_keyword2: my_keyword2,
         | my_keyword3: my_keyword3)"
         | 
         | that now becomes:
         | 
         | "foo(arg, my_keyword1:, my_keyword2:, my_keyword3:)"
         | 
         | that is just a bit less for your eyes to have to digest and
         | parse, although i can see leaving the trailing colon off as
         | being a common bug.
         | 
         | sometimes you can just double splat both the signature and the
         | wrapped invocation, but if you need to peel off kwargs in the
         | wrapper method then you're stuck passing them all back in, or
         | else you fall back to pulling kwargs out of a hash (plus you
         | lose some level of auto-documentation in the method signature
         | that way).
         | 
         | it'd be kind of nice to have a literal which could be passed
         | into the method invocation that would expand out to all the
         | kwargs that were passed, while still being explicit in the
         | definition.
        
         | nusaru wrote:
         | I don't find it that confusing. Parameter names are usually
         | longer than one character.
        
         | sodapopcan wrote:
         | While yes, parameter names are usually longer than 1 character,
         | I'm super disappointed that Ruby has introduced this. I hate
         | hate HATE this in JS. Sure, it's easier to write, but my brain
         | always has to do a small double-take as to what I'm looking at
         | while reading as it looks almost identical to destructuring.
         | 
         | Also, how is this going to work in function heads? `def
         | foo(bar:)` means that `bar` is a required keyword. Is it going
         | to have to be `def foo({bar:})`? In that case, it's going to
         | come off as a potential style error to many people.
        
           | sodapopcan wrote:
           | My bad, the example illustrates in a function head. So how
           | are require keyword args going to work now?
        
             | sodapopcan wrote:
             | Oh wait, it's function definition vs callsite (duh). This
             | is still unnecessary confusion.
        
         | dragonwriter wrote:
         | > To save 2 keystrokes?
         | 
         | A lot more keystrokes if you are using meaningful argument
         | and/or hash key names, but the big benefit is, IMO, readability
         | (at least, that's the big benefit I see with the very similar
         | syntax in JS.)
        
       | toomanybeersies wrote:
       | I'm not sure that the new "valueless" hash syntax is an
       | improvement. From my experience with Typescript, it's a common
       | source of bugs.
       | 
       | But I'm sure that people had similar complaints when compact hash
       | syntax was introduced in Ruby 1.9, and now nobody even thinks
       | about it. So I'm sure I'll survive.
        
         | maxfurman wrote:
         | I'm in the opposite camp - I love the short object syntax in JS
         | and the way it mirrors destructuring. I'm very happy to see
         | something similar come to Ruby! But, that said, I think that
         | the Ruby version is ugly compared to JS and the extra colons
         | are noisy. I assume there's some reason why the parser can't
         | read `{ x, y }`, as ruby is notoriously hard to add syntax to.
        
           | hvis wrote:
           | > I assume there's some reason why the parser can't read `{
           | x, y }`, as ruby is notoriously hard to add syntax to.
           | 
           | Something in the parser using the colon after the first
           | identifier to disambiguate between hashes and blocks,
           | probably.
        
           | pqdbr wrote:
           | Count me in as well, very happy to see this addition.
        
       | evolve2k wrote:
       | Enhanced error log messages are always welcome on the ground :)
       | 
       | Reminded me of the work done in elm to explicitly improve their
       | error reporting by deeply considering the user experience [1]
       | 
       | Repo for the newly included error_highlight gem is interesting
       | [2], anyone have more background on this ?
       | 
       | 1. Elm "the perfect big report"
       | 
       | https://elm-lang.org/news/the-perfect-bug-report
       | 
       | 2. Error_highlight gem repo:
       | https://github.com/ruby/error_highlight
        
       | Mikeb85 wrote:
       | Nice, compiling it now. Will be fun to play with YJIT and try the
       | new features.
        
       | picardo wrote:
       | Good to see IDE support for TypeProf type hints[1]. I've been
       | doing a lot of work in statically typed languages lately, and
       | spoiled by how good IDE integration is with the compiler. Ruby
       | has been moving towards static types for a while, but the lack of
       | IDE support has always been the dealbreaker for me to go back to
       | Ruby. The ecosystem needs more tooling like this.
       | 
       | [1] https://github.com/ruby/typeprof/blob/master/doc/ide.md
        
       | rememberlenny wrote:
       | Can anyone share their experiences using YJIT or RBS in Rails?
       | 
       | I'm curious how the impact affects development, deployment, etc.
        
         | angelbob wrote:
         | Disclaimer: I'm on the YJIT team.
         | 
         | In general it's not a big change. You should only turn on YJIT
         | for long-running jobs -- the prod Rails server, plus probably
         | background workers if you have them. YJIT does nothing unless
         | you turn it on with the --yjit flag.
         | 
         | YJIT's going to affect memory usage, so it'll change your
         | optimal number of processes and threads for your Rails server -
         | play with it for your app specifically, because the percent
         | speedup and mem expansion vary a lot from app to app. YJIT
         | works fine with Puma and Webrick. I don't think anybody's tried
         | it seriously with less-common servers like Falcon or Thin, but
         | I'd expect it to work -- file a bug if it doesn't, because it
         | should.
         | 
         | YJIT _does_ speed up Rails - we 're seeing about a 20%-25%
         | speedup on little "hello, world" Rails apps (see:
         | https://speed.yjit.org/), and about 11% on Discourse for a
         | single thread. We don't have good multithreaded or multiprocess
         | numbers yet, but it's in the works. YJIT scales with multiple
         | threads/processes just like existing CRuby.
         | 
         | (All speed numbers are accurate as of right now, but may change
         | over time.)
         | 
         | I would probably _not_ use it in dev mode. While YJIT has
         | pretty good warmup numbers, Rails throws away all existing
         | application code for every request in dev mode. That 's going
         | to make YJIT a _lot_ less useful. Play with it -- maybe I 'm
         | wrong for your app, especially if you use a lot of non-reloaded
         | code (e.g. methods inside gems.) But I wouldn't expect great
         | results in the development RAILS_ENV.
         | 
         | For deployment the short version is: add --yjit as a command
         | line parameter in production mode and (probably) for your
         | background workers. You can do this with "export RUBYOPT='--
         | yjit'" or use your local preferred way.
         | 
         | Where I give weaselly-sounding qualifiers like "probably,"
         | that's because it can depend on your config. If you have plenty
         | of memory but are often CPU-bound, YJIT is usually good. If you
         | have really limited memory and your server CPUs are mostly
         | idle, YJIT is usually bad. YJIT is also currently x86-only and
         | runs on Mac and Linux but not Windows.
         | 
         | There has been a lot of historical demand for a Ruby config for
         | servers: something that uses more memory to get faster
         | operations, and that is optimised for long-running processes.
         | YJIT is aimed directly at that. Non-JITted CRuby is mostly the
         | opposite: fast startup, modest memory requirements, doesn't get
         | significantly faster over time.
        
           | claudiug wrote:
           | can we expect for better numbers on the official 3.1 release,
           | or we need to wait for 3.2 version?
        
           | xfalcox wrote:
           | > YJIT works fine with Puma and Webrick. I don't think
           | anybody's tried it seriously with less-common servers like
           | Falcon or Thin, but I'd expect it to work -- file a bug if it
           | doesn't, because it should.
           | 
           | Have you tried it with Unicorn?
        
             | byroot wrote:
             | Yes, it work fine with Unicorn, YJIT is currently serving a
             | small portion of Shopify storefront traffic, and that app
             | runs with Unicorn.
             | 
             | Of course since each of the unicorn process will generate
             | its own executable code, the memory usage difference with
             | Puma is even bigger, and copy on write can't help here.
        
               | xfalcox wrote:
               | Yeah, I was trying to come up with an idea for this. We
               | try to eagerly load as much as we can before fork, so
               | most of the memory is shared between the forked unicorns,
               | but this won't work with YJIT right?
               | 
               | Ideally we would be able to eventually do the forks of a
               | "mature" unicorn child an hour or so after all is
               | JITed...
        
               | byroot wrote:
               | Beside the operational nightmare that it would be to
               | deploy with such a strategy, it wouldn't work long term.
               | 
               | JITed code can be invalidated and recompiled, so your
               | forks would still drift over time.
               | 
               | I'm a big proponent of unicorn (and forking setups in
               | general) for various operational reasons, but I think JIT
               | might be the last nail in the coffin.
        
               | joelbluminator wrote:
               | Im out of my depth here but why can't they share the
               | JITed code?
        
               | byroot wrote:
               | Because JITed code will inline things like the address of
               | some specific objects (typically constants) etc. To share
               | code between processes you'd need to ensure all these
               | references are exactly the same in each process.
        
           | pqdbr wrote:
           | How one would check if the YJIT was correctly enabled?
        
             | byroot wrote:
             | $ ruby -v         ruby 3.1.0dev (2021-11-08T09:35:22Z
             | master 7cc4e147fc) [x86_64-darwin21]         $ ruby --yjit
             | -v         ruby 3.1.0dev (2021-11-08T09:35:22Z master
             | 7cc4e147fc) +YJIT [x86_64-darwin21]         $ ruby --yjit
             | -e 'p RubyVM::YJIT.enabled?'         true         $ ruby
             | -e 'p RubyVM::YJIT.enabled?'         false
        
             | sebiw wrote:
             | You can call `RubyVM::YJIT.enabled?` to check.
        
         | byroot wrote:
         | > I'm curious how the impact affects development, deployment,
         | etc.
         | 
         | YJIT is pretty much transparent in production, if not it's
         | likely a bug.
         | 
         | When we tried MJIT in production to compare it against YJIT, it
         | causes lots of request timeouts on deploy, because the JIT
         | warmup would take 10 to 20 minutes and it's much slower during
         | that phase.
         | 
         | But YJIT warms ups extremely fast and with a much lower
         | overhead, it's seemless on deploy.
         | 
         | The only thing you may need to tweak is `--yjit-exec-mem-size`,
         | it defaults to `--yjit-exec-mem-size=256` (MB) which is not
         | quite enough for larger apps.
         | 
         | As for development, it would work, but with code reloading
         | enabled, you'd likely exhaust the executable memory allocation
         | pretty fast, because for now YJIT doesn't GC generated code
         | [0]. It will come soon, hopefully before the 3.1.0 release, but
         | that's one of the reason why it's not enabled by default.
         | 
         | [0] https://github.com/Shopify/yjit/issues/87
        
           | joelbluminator wrote:
           | Is it 256 mb for the entire app server or is it multiplied by
           | each Unicorn/Puma process?
        
             | byroot wrote:
             | Each process, a small part of it might make it into CoW
             | during boot, but that won't make a big difference.
             | 
             | If you don't have the free RAM for it and you app is small
             | enough, you can try lower values.
             | 
             | Also note that currently YJIT fully initialize that memory
             | to make it easier to debug, so it's not even virtual.
             | That's another thing that is on the roadmap to be improved
             | soon, and ultimately you'll only pay for the part that YJIT
             | really use even if 250MB is allocated.
             | 
             | But overall all JITs trade increased memory usage for
             | faster execution, you have to store that generated code and
             | metadata somewhere.
        
               | joelbluminator wrote:
               | Do u guys expect it to be on by default eventually, at
               | least for Rails apps?
        
               | byroot wrote:
               | Yes. Basically the main reason it isn't the default now
               | is the still rough executable memory management.
               | 
               | Other than that it's been rock solid and offers decent
               | speedup across a wild range of benchmarks and real world
               | applications.
               | 
               | So my personal expectation is for it to be enabled by
               | default in 3.2, but I might be wrong.
        
       | maxfurman wrote:
       | Very confused by the example of the "pin" operator given here -
       | what is it for, and what is the improvement in this release?
        
         | Lammy wrote:
         | https://docs.ruby-lang.org/en/master/doc/syntax/pattern_matc...
        
         | dangerbird2 wrote:
         | Definitely not a clear description, but I believe it stands for
         | "pattern matching in". Ruby's new pattern matching uses a sytax
         | of
         | 
         | case {{ value }} in {{ pattern }} {{ code }} ... end
         | 
         | the new feature apparently allows expressions, rather than just
         | local variables, in the pattern spec.
         | 
         | They probably should have included the link to the feature
         | ticket: https://bugs.ruby-lang.org/issues/17411
        
       | drumpkid wrote:
       | No news on Ractors improvements :'(, maybe next year
        
       | WalterGR wrote:
       | Swapping out a JIT must be an unimaginably complex operation.
        
         | byroot wrote:
         | It's not swapped, both are available for now.
        
         | aardvark179 wrote:
         | Not really. Separate out your JIT into well defined components
         | (compiling a method, installing the compiled version,
         | invalidating the compiled version, deoptimising, etc.) and make
         | sure your JITs use those common interfaces. The JVM manages to
         | support multiple JITs (including Graal which is written in
         | Java) and multiple GCs through this sort of approach.
        
       | kule wrote:
       | Was just playing around locally and found one of the undescribed
       | Irb improvements is a drop-down with autocompletion suggestions
       | nice!
        
       | sandstrom wrote:
       | I'd like to see Ruby deprecate some of the rarely used standard
       | library items.
       | 
       | For example, does Rinda and GDBM need to be in the standard lib?
       | Maybe they're better suited as stand-alone gems?
       | 
       | Similarly, I think it should stop bundling some gems.
       | 
       | I see they are moving some gems from 'default' to 'bundled',
       | which I guess is some sort of deprecation or demotion -- that's
       | great!
       | 
       | **
       | 
       | I'd also like to see them move development onto Github, that
       | should make it easier for more people to participate.
        
         | ksec wrote:
         | >I'd also like to see them move development onto Github, that
         | should make it easier for more people to participate.
         | 
         | This has been discussed a few times in the past 5 years. But
         | some member refused to use Github due to it not being open
         | source.
         | 
         | Not sure if that is still the case but you could certainly try
         | and ask again.
        
         | sdwolfz wrote:
         | Looks like dbm/gdbm were removed from the ruby repo, just not
         | documented in the release notes:
         | 
         | https://github.com/ruby/ruby/pull/4525
         | 
         | https://github.com/ruby/ruby/pull/4526
         | 
         | https://github.com/ruby/ruby/pull/4619
        
         | toomanybeersies wrote:
         | That's been slowly happening [1]. For instance, with Ruby 3.0,
         | net-telnet and xmlrpc were removed from the stdlib and now have
         | to be installed as standalone gems.
         | 
         | [1] https://stdgems.org/removed/
        
       | ericb wrote:
       | Those error log messages will save me time--super excited about
       | that!
        
       ___________________________________________________________________
       (page generated 2021-11-09 23:02 UTC)