News for Ruby 3.2.0
docs.ruby-lang.org
docs.ruby-lang.org
Add support for bundle gem --ext=rust command.
Cool to see support for writing extension gems in Rust shipping with Ruby.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.
Imo
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.
gg
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?
There are occasional comments in GH issues discussing the possibility of implementing Ractors, but nothing material.
Disclaimer: mine :)
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.
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.
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.
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?
Anyway, no big deal. Happy to see Ruby getting nicer and nicer every update.
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
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.
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.
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...
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.
If it was sorted by a criteria of my choosing, sure. But I don't know when I last cared about insertion order...
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.)
Clojure 1.11.1
user=> (first [])
nil
user=> (first {})
nil
user=> (last [])
nil
user=> (last {})
nil
user=> Clojure 1.11.1
user=> (first {:one 1 :two 2})
[:one 1]
user=> (last {:one 1 :two 2})
[:two 2]