Hacker News new | past | comments | ask | show | jobs | submit login
News for Ruby 3.2.0 (ruby-lang.org)
230 points by type0 on Dec 23, 2022 | hide | past | favorite | 60 comments



  Add support for bundle gem --ext=rust command.
Cool to see support for writing extension gems in Rust shipping with Ruby.


> "Find pattern" is no longer experimental.

This makes me so happy. Pattern matching is amazing, and I use find patterns quite extensively. And I’ll be even happier to run tests without RUBYOPT='-W0' moving forward.

Also great to see Regexp.timeout as well as the ability to initialize a Struct using kwargs without keyword_init: true.


To complement, the evolution from 2.0 to 3.1: https://rubyreferences.github.io/rubychanges/evolution.html


I have been playing around with django for the first time in almost 5 years recently, and it’s so much more productive. Wondering if I should try out rails.


I'm working with both.

Django feels like a loose set of tools. That could be bad or good. You have to take more architectural decisions, every project can end up with a very different structure. You can split it into sub applications each one with its own urls file, models, controllers and migrations. Tests lay in the same directory of code. The templating language is quite constrained and inflexible. The source of truth of the database are the models and I discorage using inheritance in models or you end up with a database that no other application will ever be able to understand, humans included. The ORM feels verbose. The admin tool is good. No tools for deployment, maybe docker? In general there is a feeling of overengineering everywhere as if it was designed to keep up with every possible use case.

Rails is more constrained, it's really on rails. Again, this can be both bad and good. Two projects will look the same except for those companies that adopt the services / commands / etc sub structure of the code and the ones that stick to the plain models directory, possibly lib. The source of truth of the db is the db and if you want to turn it into a tangle you have to do it yourself explicitly. The ORM is OK for the usual use cases. There is only one file for routing. Tests are in their own directory. The templating language is Ruby itself so you have one less thing to learn but in theory you can shoot in your foot and write your application there, but you can always find a way to shoot yourself even in Django. There is no standard admin tool, you have to pick one yourself so you usually end up without an admin tool unless the customer pays you for that. The traditional tools for deployment were Capistrano and Mina. Maybe docker now.

I made about the same amount of money from them in the past many years. I enjoyed more the weeks spent on Rails.


From a very long time rubyist: if you care a lot about code elegance, I think you could like ruby/rails more. If for you it's more important that there is only one correct way to do things, then probably sticking with python /Django makes sense.


Honestly code elegance is less important than raw productivity.


My point is that your productivity with a given tool also depends on your own preferences/cognitive style. Between Ruby/Rails and Python/Django, my assessment, even if I don't know the latter anywhere as well as the first, is that your results will depend a lot on your preferences and cognitive style.


Compared to Rails, django will feel like fastapi

Imo


What does that mean?


Django is more comprehensive than FastAPI in terms of features and use cases it tries to address, so I assume they mean Rails offers more than Django. More != better.


I’m excited to see my syntax suggest gem as a default gem


I’m actually pretty excited about that. I hate the dreaded unexpected end error.

gg


It looks great, really! My first thought is that it would make a very handy solargraph diagnostic reporter, so I think I'll whip that up in the next few days.


Quick question for the current Ruby community:

I kind of moved away from Ruby right around the time Ractors were about to land and they looked really promising.

I was just curious if they ended up delivering much in the way of change and if not what the main problems were?


ractors, due to its "no shared or immutable only memory" constraints, is fundamentally incompatible with 99% of ruby code in the wild. I don't see it getting much adoption until some of those constraints are relaxed.


If that constraint is relaxed, then they aren't really actors anymore, are they?


They would. Some of the constraints were senseless. You used to not be able to use class variables, even if they were already initialized and frozen. However, using static variables, and worse, changing them, was fine.

Ruby uses a lot of pure lazy memorization. That's an aspect I'd like to see more accepted. A system that enforces rather than recommends, is a less usable system.


This can be said of most actor systems. Using actors is a fundamentally different way of programming than non-actor-based multi-threaded systems. You do have to change your paradigm; but, when I have, I've found the experience to be really wonderful.


Celluloid was an actor library which worked well with most ruby code. This is not the case for ractor. For starters, the ruby standard library is itself incompatible with ractor. Go ahead and try using logger inside one. Beyond that, a lot of mature libraries would have to be rewritten to fit ractors, and that's quite risky. Something as simple as a connection pool has to be done completely differently. That's a big red flag, considering that the value of ruby is its ecosystem.

I actually tried making the libs I maintain ractor compatible. I recorded the constraints and suggested removing some of fhe annoying ones. Some got accepted, but it's not enough.


> This can be said of most actor systems.

True, but other languages/platforms have better built-in support for immutable data structures and don't force you to fight the standard library to implement a share-nothing approach.


You get there pretty fast in Ruby with DryStruct; and, Ruby has .freeze, which can also be helpful.


But you can't use any libraries that maintain mutable state, which, in Ruby land, is many of them.


A common actor strategy for that is to have a dedicated actor for communicating with that mutable state


Ractors is still in experimental stage but I’ve played around with it and it sure offers a huge performance benefit & true concurrency


I assume by the fact they are still experimental that there isn’t much in the way of adoption yet?


I was looking into this question a few weeks ago and couldn't find any libraries I would use in typical applications (eg. background jobs, etc) implementing Ractors.

There are occasional comments in GH issues discussing the possibility of implementing Ractors, but nothing material.


Here's one that sounds like exactly the sort of example you had in mind: https://github.com/okeeblow/DistorteD/tree/NEW%E2%80%85SENSA...

Disclaimer: mine :)


Thank you! Will check it out.


Feel free to email me @ the address in the commits if you have questions. I like Ractors a lot and want to see them succeed!


Not from what I have seen, It’s kinda risky because the fact that Ractors still is in experimental stage means that there couls be major breaking changes at any time, both how you use it and internally.


> The following deprecated methods are removed: Dir.exists? File.exists?

These names were really elegant, I wonder why they were removed. Searching the web, the only explanation I can find is they were removed because they were deprecated. So why were they deprecated?


For better or worse, the convention in Ruby is to name methods in a second-person style [0], as if addressing the object directly: “file, do you `#exist?`”; “string, do you `#start_with?` foo?”. So, for consistency, `Dir.exist?` and `File.exist?` have been preferred for a long time.

[0] https://bugs.ruby-lang.org/issues/9041#note-1


That's true for File objects responding to an :exist? message. For the File class, I think exists? makes more sense.

Anyway, no big deal. Happy to see Ruby getting nicer and nicer every update.


Link should be updated to https://docs.ruby-lang.org/en/master/NEWS/NEWS-3_2_0_md.html. The current link is now pointing to News for Ruby 3.3.0


How do MJIT and YJIT differ?


MJIT pastes together snippets of C code that implement Ruby VM bytecode instructions. It then hands off that C code to GCC which compiles it to native code while the Ruby VM is running.

YJIT compiles from Ruby VM bytecode straight to native code using a JIT technique called basic block versioning (which is slightly different from how JITs like V8 work because the unit of reuse is a basic block instead of a function).

There’s more information in these links:

https://youtube.com/watch?v=zO9_uTaELCw&feature=shares

https://shopify.engineering/yjit-just-in-time-compiler-cruby


I can't influence people at work to use Ruby correctly or to learn it.

It's a battle to ship linters amongst people who don't have CS degrees and express hostile disdain for any suggestions of software craftsmanship, much less curiosity.

They want to use their dumb patterns and bad habits, and aren't interested in changing.


Really pleased to see Enumerable.product make it!


While on the topic, I still don‘t get it why we have [].last but {}.last fails with a NoMethodError.


Are hashes guaranteed to be ordered in some way (not just incidentally implemented that way, but specified so that changing it in the future would be considered breaking)? I thought they weren't, in which case there wouldn't really be any obvious way to define `last`, but I might be mistaken


`{}.first` works, so no reason why `{}.last` shouldn't. I would argue, though, that it's best not to rely on hashes for ordering, though that's a relatively loose preference, and I've certainly use it for quick 'n' dirty scriptss


Ruby hashes have been intentionally ordered since Ruby 1.9, which is ~15 years now.


Yep, as I described in another comment I just don't like to exploit that, but it's more of a personal preference. It's cool by me if others choose to.


I agree that it's conceptually weird, but since Ruby guarantees the ordering, you might as well have features for it.


The best feature of `Hash` maintaining insertion order is that `Set` does too, since a `Set` is a `Hash` with all-`true` values: https://github.com/ruby/ruby/blob/3539da64fc42d6eb76f1d4c3cc...


Ya, it's one of things you have to make a team/org-level call on.

For me, ruby is full of a lot of little conveniences that shouldn't necessarily be used in production systems. I always cry loud that code should be quickly "scannable", and the data-structures we choose to use can help a lot in the quicker understanding an unfamiliar piece of code.

But I stress again: these types of decisions are best left up to the team or org. It's ultimately low-stakes.


key ordering is something to rely on now, in Ruby as well as in JavaScript and Python

That ship has sailed - it was partly for the convenience of debugging, but the general purpose dict is now ordered.

It's only by insertion order - it's expensive to change the order - but the order can by relied upon and is being used.

Edit: some detail on changing the order - you can either remove all the key/value pairs up to the first one you want to change and add them back, or you can create a new dict with the pairs in the desired order. With Rust you can choose whether or not to have insertion order preserved https://stackoverflow.com/questions/42723065/how-to-sort-has...


Ya, my preference still stands whether the ship is docked or not. As you point out: it's good for debugging. As I mentioned, I like it for quick things in throwaway scripts. I don't like it in production code because when I'm reading something quickly that I don't care to deeply understand: Hashes are records and arrays order ordered lists. I very much like the way Rust does it (and I like a lot of what I've seen in Rust)--if we had `OrderedHash` in Ruby, I will feel completely different.


That seems arbitrary. I would consider that "politics" and like a place that had a rule to treat hashes as unordered a bit less.


I already implied it was politics by saying that it is something that needs to be determined at the team/org level.

I don't feel it's arbitrary, though, and to get a little clever about it I feel that ordered hashes are arbitrary and that's why I don't like to rely on it in _production_ code.

"Records" (aka hashes, aks dicts, aka maps, etc) are inherently unordered. Relying on insertion order or keyed values is super brittle.

So again, the fact that they are ordered is super convenient! It shines in one-off, temporary situations like debugging or writing a quick script to group something by a specific value without having to do any further sorting. But I don't believe it should ever be replied on in a production system, just for the fact that if the order ever changes, there are possibly many places that have to change.


I get that it's deterministic, but I can't really think of when I would use that for solving real programming tasks?

If it was sorted by a criteria of my choosing, sure. But I don't know when I last cared about insertion order...


Might be some kind of linked list like implementation under the hood. Getting the first element is performant but traversing everything to find the last one would be slow.


That's very unlikely.

Even for singly linked lists, implementations for general purpose use usually keep pointers to the first and last elements so that you can use it as an O(1) FIFO queue, as well as prepend in O(1) time.

If you only keep a pointer to the head of the linked list, then it can be practically used a LIFO queue (stack), and a few other corner cases, but not much else. (A FIFO isn't very useful if adding an item is O(1) but removing an item is O(N), or vice versa.)



Ruby hashes are ordered, per the docs.


Hash#first comes from Enumerable - and Enumerable doesn't have #last.


Yeah, that's strange to me too. In Clojure (similar conceptual mode with Ruby, with sequences, hashes, etc.), the code is very similar, with predictable results:

  Clojure 1.11.1
  user=> (first [])
    nil
  user=> (first {})
    nil
  user=> (last [])
    nil
  user=> (last {})
    nil
  user=>


Well sure, but what about non-empty collections? How are hashes ordered?


    Clojure 1.11.1
    user=> (first {:one 1 :two 2})
    [:one 1]
    user=> (last {:one 1 :two 2})
    [:two 2]




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

Search: