A preview of Ruby 2.1 was released a couple of days ago with these release notes:
VM (method cache)
RGENGC
refinements
syntax
Decimal Literal
Frozen String Literal
def’s return value
Bignum
128bit
GMP
String#scrub
Socket.getifaddrs
new Rubygem
I found myself scratching my head for a minute. I don’t know what most of these are! So let’s dig into them and dive into some of the details.
RGenGC
Ruby 2.1 includes a new generational garbage collector. Prior to 2.1, MRI Ruby used a conservative stop the world while I take out the trash version of mark and sweep for its garbage collector. In the 2.1 preview, it still uses mark and sweep, but with a little generational twist.
The new approach tracks objects in two buckets: young and old. The mark and sweep GC is always run on the young generation and only run on the older generation if there is a need for more memory before resizing the heap. Young objects are promoted to old after surviving a single GC (most objects die young, or at least the good ones).
The new garbage collector is backwards compatible and should not break existing C extensions.
The few benchmarks that I’ve ran show a slight improvement from 2.0 to 2.1. What stood out to me was the 39% less time spent in the GC, which means less time with the whole world being stopped. That should mean less jitter from GC in things like Gamebox games.
More Ruby GC info can be found in this talk.
ObjectSpace.trace_object_allocations
Tracking allocations in Ruby used to require creative tracing or recompiling Ruby itself. In 2.1 ObjectSpace.trace_object_allocations
lets you turn on tracing for a single block of code. This would have been useful when I was debugging some serious Array
creation problems in a game I was working on.
require 'objspace'
ObjectSpace.trace_object_allocations do
a = [2,3,5,7,11,13,17,19,23,29,31]
puts ObjectSpace.allocation_sourcefile(a)
puts ObjectSpace.allocation_sourceline(a)
end
trace_object_allocations
will allow for more complex APIs to be built. (such as objectspace-stats).
Refinements (for real this time)
Refinements, marked experimental in 2.0, are now official in Ruby 2.1. They essentially allow for local monkey patching. Like all monkeys, they should be used with extreme caution. Refinements should help reduce a lot of the issues that come with global monkey patching.
class Foo
def bar
puts "Foo#bar"
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
puts Foo.new.bar
module WorkingWithFooExt
using FooExt
# only place where the refinement is applied
puts Foo.new.bar
end
puts Foo.new.bar
klasscache (method caching patch)
The method cache is no longer global. Ruby 2.1 introduces a hierarchical class cache similar to the what Rubinius and JRuby use. I never realized how bad MRI’s method cache was. This post by James Golick does a great job of explaining these changes. The gist is: less clearing out the cache, better cache hit percentages, generally better performance.
Syntax
Required Keyword Args
If you’ve seen the keyword arguments from Ruby 2.0, then the syntax for required keywords will make sense.
def foo(bar:)
end
foo(bar: 12) # ok
foo # ArgumentError: missing keyword: bar
Decimal Literal
Ruby 2.1 added the r
and i
suffixes as syntactical sugar for creating Rational
and Complex
numbers respectively:
27r # => Rational(27/1)
1/2r # => Rational(1/2)
12+33i # => Complex(12,33)
Frozen String Literal
You can now create shared frozen strings with the f
suffix. This will definitely be helpful for templating libraries.
3.times{ puts 'blah'.object_id }
# => 70287241728160
# => 70287241728080
# => 70287241728020
3.times{ puts 'blah'f.object_id }
# => 70287241709760 same object
# => 70287241709760
# => 70287241709760
def returns a symbol of method name
In previous version of Ruby, the def
keyword returned nil
. It now returns the symbol of the method name. I don’t have many practical uses of this in my head. The only one I’ve seen is for method access:
class Foo
# foo will be private
private def foo
end
# public
def bar
end
end
Big Numbers Get a Speed Boost
Ruby 2.1 uses 128bit integers when available and makes use of Gnu Multiple Precision (GMP). These changes will improve performance for anyone using large numbers in Ruby.
Socket.getifaddrs
This new method on Socket
is a wrapper to the getifaddrs
function. It returns an Array
of Ifaddr
instances.
ruby -rpp -rsocket -e 'pp Socket.getifaddrs'
# => [#,
#,
...
#,
#,
#]
Conclusion
I’m glad to see a shorter release cycle for Ruby. The VM improvements and generational garbage collector make me wish the preview was here already. But like any preview, all of these details are subject to change between now and the release date of Christmas 2013.
Thanks for this. I too was scratching my head about what exactly some of items in the release notes really meant.
I bet GitHub would have loved to have ObjectSpace.trace_object_allocations when investigating this issue.
Glad you liked it Bob. Knowing where your objects are created is incredibly powerful.
def returns a symbol of method name… I don’t have many practical uses of this in my head.
How about a Contract Programming library?
AndrewO,
Sounds like a fun idea, send me a link when it’s done. ;)
Seriously though, I’m sure there are a lot of great ideas based off the return value of def, I just couldn’t think of any for the blog post.
Any idea why they didn’t return the Method object itself?
Meant to say before: great write-up! Thanks for doing the leg work. Looking forward to playing with some of these… except refinements. I will be forever leery of them. :)
That’s what I asked too! My guess is that returning a symbol is lighter weight and probably what you want most of the time.
In previous version of Ruby, the def keyword returned nil. It now returns the symbol of the method name. I don’t have many practical uses of this in my head.
One I can think of is memoization using the memoist gem: https://github.com/matthewrudy/memoist
Good point, I haven’t used that gem before.
Nice post!
Thanks Breno, glad you liked it.
Nice post!
GC was really needing an improvement, hope someday Ruby will be a reference in Games world