- RBS: meh... might get more useful in the future (in 2-5 years maybe).
- Ractor: Wohooo! I'm writing a DAG library where I was thinking of implementing something like this, good to know I can use it and get real parallelism on top.
- Scheduler: :shrug: don't know about this one, might be relevant with future concurrent ruby code, any ideas?
- Rightward assignment: it's a bit awkward but I see the use case, just wish we had the pipe operator too like in Elixir.
- Endless method: this one is cute, I love it!
- Find pattern: oh boy, code reviews are going to be interesting now!
- Hash#except: yes, definitely a welcome one.
- Memory view: if this helps with numpy style gems it will be great!
- `send(:"do_#{ meth }", ...)`: don't do meth kids! (it's a joke!)... seems like a reasonable feature.
- `order of backtrace had been reversed`: good! it was confusing...
- Promote default gems to bundled gems (rexml): I like this one, if only nokogiri was a stdlib gem or part of core, imagine how much time would be saved instead of having to compile it every time in a `bundle install`.
- `Promote stdlib to default gems`: what does this mean? Do I now have to add `gem "securerandom"` to Gemfiles instead of having it by default and just needing to require it?
- Mjit improvements: can't wait to try it!
Overall, I'm delighted!
"Bundled gems" means the same thing, but you do have to include them in your Gemfile.
https://github.com/janlelis/stdgems#about-the-gemified-stand...
Recent summary of scheduler, a little bit out of date (changes to interface): https://www.codeotaku.com/journal/2020-04/ruby-concurrency-f...
- A Ruby "Preview 1" release? Oh crap, I have to start Christmas shopping soon.
Never noticed it's always released on December 25th.
Now they just need to make it defless too.
It's a weird name for it. It should probably be called something like 'equational method definitions'
Yeah, that's not weird
This is exactly the kind of stuff I hated when I had to work with ruby in my last gig and why I will never accept a job using it again - soo many pointless and inconsistent ways to do the same thing ... they have method aliases for collection operations like map/filter in standard library ! .NET went with non-standard SQL-like names (select/where) and I'm not a fan but at least they made their choice and stuck with it. And it's inconsistent all over the place - like '!' postfix means "operation mutates the object" in std lib BUT in rails it means the operation will raise an exception and not return an error code.
Now they add a pointless operator that means completely different thing in other languages to throw off even more people.
It's just a hell of a language to maintain someone else's code in.
I've done Ruby since 2014 or so at a few shops. My general anecdotal experience:
- Lone Ruby coders often use a lot of that cutesy/obscure/dense stuff.
- Teams of people writing Ruby, with healthy code review practices, tend to value simple, easy-to-read Ruby.
- A lot of Popular Ruby gems (and projects at aforementioned Ruby shops) have Rubocop-based style guides. Rubocop has some very strict ideas about Ruby coding style. The defaults are mostly quite sane and it's easy to disable/customize the ones you disagree with.
Not making excuses for some of the more florid parts of Ruby's syntax and stdlib, but in practice I do find things are manageable!
Things like that just often lead to bikeshedding. And then worse, powerful voices may approve ideas that work for them and not everyone else, or even more worse crippling a language to be too safe or bland to be truly useful.
I got into an argument a couple weeks ago whether an unprotected eval() in python should make it's way into production code of a fortune 500 company. The coder's argument was that, "Well the language has it so why not use it?"
"Because with great power, comes great responsibility..."
users.size
users.length
users.count
are all valid, all useful, all have different meanings, are all present in plain Ruby but with different meanings, and contain absolutely no information about what they do.For reference, .length loads everything and gets the length of the collection, .count runs a SQL COUNT query, and .size uses length if the query has already been run and .count if it hasn't.
But Rails has definitely become a PR problem for the language in terms of how many complaints like this it leads to.
I consider myself a sensible developer, but even I’ve had some childish moments with Ruby: doing something I thought was clever and productive but which really just made my code inscrutable and unmaintainable...
...by other people. The flip side is I can just about figure out what I was trying to do when I read my own code: enough so that I still always use Ruby for personal projects.
Ruby is just too much fun and critically, to date, it’s the only language where I can write a page of code at the same speed I am thinking. It also usually executes first time without any errors, which is a joyous thing.
I am not claiming to be some kind of 10x uber hacker. Ruby just happens to be an incredibly wonderful language for thinking aloud with code.
Also, what kind of danger are we talking here? I consider mutation dangerous. Danger could also mean it has side effects or that it can raise an error.
I wouldn't call it inconsistent but I would call it arbitrary.
I would rather just name the method "#{base_method}_#{why_its_dangerous}". For example take ActiveRecord::Base#save and #save!
#save mutates and I would consider that dangerous. #save! can raise an error. I would rather name #save! as #save_or_raise_if_invalid. I know it doesn't look as pretty and takes longer to type but I really don't care. Then again, I'm not a big fan of exceptions so I would never call it.
I have no idea why the few languages that allow it do so. I've never wanted it and I can't imagine it makes parsing simpler in a language where you are sometimes compiling code at runtime and where parsing is already pretty wild.
I've said this before and been wrong so let's hope this turns out to have excellent use cases.
P.S. the 'endless method definition' is meaningless, too.
> def square(x) = x * x
The original reason of this proposal was:
> Ruby syntax is full of “end”s. I’m paranoid that the ends end Ruby. I hope Ruby is endless. --mame (Yusuke Endoh)
It sounds like "let's add a new syntax for lisp because it has too many brackets"
You'll find wisp [0] implemented for several of the larger Schemes. Often because the rationale for adding another syntax can be more nuanced and actually benefitial than a quick joke. [1]
Whilst you're right that caution absolutely applies when modifying a language's syntax, there may be a case for it that reduces friction for the programmer. The change might have been proposed with a joke. I doubt the entire rationale ended there, however.
[0] https://srfi.schemers.org/srfi-119/srfi-119.html
[1] https://srfi.schemers.org/srfi-110/srfi-110.html#rationale
Yes, there’s still some symbols, but nowhere near as many.
I fell totally in love with it almost 20 years ago but these days I think we have better languages to choose from even if their ecosystems aren't always as rich.
Which names do you believe are standard?
I get that they're trying to expose an SQL-like API, but yeah, map is always about mutation, but `select`only does mutation sometimes in SQL.
It’s not anything like C++ or C where the whole coding practice and culture changes depending on your framework (like using Unreal or doing Linux programming). The best practices were the same across the board.
Basically my experience with writing it for a decade doesn’t match these critiques. The quirks in Rails were easily ironed out among intermediate developers. It’s not like it requires advanced programming knowledge to just do what everyone else is doing, which is often share in best practice documents and popular libraries/tutorials/books or (less so) rubocop style plugins.
Personally, I am very excited for this release.
* Matz's goal to get Ruby 3 to be 3x faster than Ruby 2.
--
@sosodev Thanks for the updated info!
https://benchmark-driver.github.io/benchmarks/optcarrot/comm...
Note: I have been using Roda with Ruby 2 and it is pretty fast. Can't wait to see what it would be with 3x3.
For example, processing a large CSV file and inserting new rows in a database from it has always been extremely slow using Ruby/Rails unless you basically just write raw SQL that copies from the CSV and don't do any initializations of Rails models, #create, etc. I wonder if this will improve these things at all, but my guess is that it has to do with memory usage and not the speed of Ruby?
But the right hand assignment operator. What on earth. Nobody asked for that and nobody wants it. Why.
begin
#... do something
rescue StandardError => ex
#... handle exception
end
The ex here can be any assignment expression, it's not just a lexical variable. So you could already do this: class Guru
def meditate=(exception)
puts "caught #{exception.inspect}"
end
end
# later ...
rescue OutOfCheeseError => Guru.new.meditate
i.e. creating a nice opportunity for passing error handlers around as an argument; or, this worrying idea: rescue TransactionError => Thread.current[:exception]
and now I'm afraid you can do this: Cat = Struct.new(:name) do
class << self
def all() = @all ||= Set.new
def adopt=(...)
all << new(...)
end
end
end
"Astrid" => Cat.adopt def my_method
.. code ..
rescue FileNotFoundError => FileNotFoundHandler
rescue StandardError => StandardErrorHandler
end
But yea, as is so often the case with ruby, you can really shoot yourself if you try hard enough :P foo |> bar(20) |> (x)
where x is assigned to. People didn't like that syntax, and there were issues with = being higher precedence than |> [2]. This new right-assignment operator was created in response to that [3].The weird thing is that the pipeline operator got killed, so the original reason for r-assign no longer exists. It looks to me like there's just some people on the Ruby team who took a shine to it.
[1]: https://bugs.ruby-lang.org/issues/15799 [2]: https://bugs.ruby-lang.org/issues/15799#note-22 [3]: https://bugs.ruby-lang.org/issues/15921
I'm not a fan of rightward assignment because I don't see much value and now the => operator has even more meanings.
I'm not a fan of endless methods because how lazy do you have to be to not want to type 'end'? My editor does it for me automatically. Now there is even more parsing.
I have no comment on the rightward bit though. That is more... radical. Until I see how it is adopted generally.
It does nothing but add complexity.
Seems to be well represented by successful companies here.
As I get older the question I ask myself is do I honestly enjoy using it? If the answer is yes, then I put it in my programming toolbox and ignore the hype.
However, now I’m on the operational side of things, and there are 2 types of applications I avoid to deploy/maintain, mainly because of their runtime: Java and Ruby apps. It’s very likely the Ruby runtime has improved, but we actually set up a haproxy with multiple instances of the same ruby app, which we just restarted every 2 hours, just to keep it running properly. Upgrading ruby back-then was a mess, and could break a lot of things. I can’t comment on the language itself, but the runtime left a very bad impression. I since then (4/5 years ago or so) have successfully avoided ruby, so it’s possible things have improved, but first impressions last...
Go is easiest if we're talking about pre compiled binaries. If you include builds, dependency hell is real.
C#, JS, and Java have been easy for me. Install JVM/CLR/Node and run one command. Old school Java with EE servers and Tomcat and such was a nightmare but everything I've done recently is self hosting
class Foo
puts "bar"
endwill just print `bar` when it's parsed.
so something like has_many :baz are just the method call `has_many(:baz)` defined by active record. that creates a few functions using meta-programming. the other thing that ruby uses a lot of are blocks which are just anonymous functions. `do |a,b,c| puts a; end` just a function passed to the method that can be invoked by the function. I think those things are the ones that trip people up the most with when learning.
Not that Ruby = rails
Okay time to upgrade to latest rails and wait for the multithreaded rails release. :P
EventMachine was a nightmare to work on and to work with, but with fibers it and some wrappers you could write some neat code. Most library were making a lot of bad assumptions - "there is a GIL and i'm running on a full thread and also wtf are threads in general, never heard of it?"
Almost no one in ruby world thought about writing a better code to make application faster, it was always about either finding a better gem or adding more application servers. Here is the closest ruby has been towards concurrency https://github.com/igrigorik/em-synchrony guess why it never took off.
Ruby 3.0 is a first step towards having libraries being aware that they are in on fiber and not thread.
If RBS was for end users, adding types inline with the source code would make more sense compared to the RBS approach: keeping the source file and typedef file in sync.
That might actually be a pretty smart move. At first it seemed inconvenient to have to maintain a separate file for the type information, but maybe this focus on type-checking being made easy for the 90% of us who hack scripts is a much smarter one.
JavaScript has a similar pattern with Workers, and it makes concurrency for hot code impractical. Serializing/deserializing objects is a lot slower than just not doing that. In JavaScript’s case, you can also use SharedArrayBuffer, but Safari hasn’t re-enabled it.
However you can always just open a shared memory region and write bytes back and forth. You don't get ruby types but if you are worried about performance that probably isn't much of a concern.
See also: list of the biggest tickets tackled in 3.0: https://www.gitclear.com/open_repos/ruby/ruby/release/pendin...
There are some seriously good stuff there.
Glanced at it from my phone but it looks good! I’m looking forward to seeing it in RubyMine. Still sad that we can’t write these in .rb files but I wonder if the plan is to go the other way, eventually permit typed code in .rbs?
Does anyone know what the story will be with third-party definitions? Are we headed towards a DefinitelyTyped style repository for Ruby?
The other good thing about RBS being in separate files is it can be integrated into a library without breaking compatibility with older Ruby versions.
A matter of perspective, I suppose. You seem to like dynamic typing so static typing seems ubiquitous and inescapable. I find dynamic typing completely infuriating over 100 lines or so, and dynamic typing seems inescapable.
Others have pointed out the big dynamically typed languages, so I won't rehash, but suffice it to say, there basically are some dynamically typed languages left.
But in my opinion, dynamic typing is a terrible idea for production code.
Also dynamic typing is more productive (for application code, not talking bootloaders here). It's a measurable fact and apparent to anyone who has written code long enough. Writing out types for everything is mostly pointless clerical work which should be able to be done by computers.
OTOH, by skipping typing you lose a lot of guardrails and won't discover bugs until runtime.
Hello PHP.
method_missing is a deliberate and principled part of a message-passing approach to object orientated programming that gives you powerful options for composition and delegation.
You can say you don't prefer this style of programming, but it's not well-informed to say it's down to immaturity or ignorance of alternatives on their part.
Also, people always forget to throw NotImplemented errors which can lead to some fun to track down bugs if you make a typo sending a message. Which I guess is why you pretty much have to write tests for everything in ruby. This kind of stuff would be caught by a compiler in other languages.
Disclaimer: I don't buy into the idea of "message passing" or a lot of OOP. They're the microservices of programming languages.
Ruby
puts IO.foreach('logs1.txt').grep /\b\w{15}\b/
Python
from re import compile
with open('logs1.txt', 'r') as fh:
regex = compile(r'\b\w{15}\b')
for line in fh:
if regex.search(line): print(line, end='')
On my MacBook Pro (2013) running Catalina Ruby averaged 1.49 secs and Python 1.27 secs. The file `logs1.txt` is a 20Mb Apache log file. Pre-compilation with: reg = Regex.compile /\b\w{15}\b/
puts IO.foreach('logs1.txt').grep reg
... slowed Ruby down to 1.57 secs.Using --jit didn't change Ruby's overall time but considering it adds 700ms to Ruby's startup time execution time was faster.
regexp = /\b\w{15}\b/
IO.foreach('logs1.txt') do |line|
puts line if regexp.match?(line)
end
I imagine this will in both cases mostly be testing the computer's IO.Regexp.compile doesn't do anything substantially different from Regexp.new or a literal (i.e. it doesn't optimize the regular expression or something) so I think the difference is just random fluctuations.