We're hiring!

We're actively seeking developers and designers for our Detroit & Ann Arbor locations.

Kicking the Tires on Ruby 2.1 Preview

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.

Ruby 2.0 vs 2.1-preview performance

Ruby_2.1_preview_time_in_gc

More Ruby GC info can be found in this talk and more basic GC breakdown here.

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'
# => [#<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST LINK[lo0]>,
       #<Socket::Ifaddr lo0 UP,LOOPBACK,RUNNING,MULTICAST fe80::1%lo0 netmask=ffff:ffff:ffff:ffff::>,
       ...
       #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,NOTRAILERS,MULTICAST,0x800 fe80::baf6:b1ff:fe1b:4ebb%en0 netmask=ffff:ffff:ffff:ffff::>,
       #<Socket::Ifaddr en0 UP,BROADCAST,RUNNING,NOTRAILERS,MULTICAST,0x800 10.5.70.230 netmask=255.255.255.? (7 bytes for 16 bytes sockaddr_in) broadcast=10.5.70.255>,
 #<Socket::Ifaddr p2p0 UP,BROADCAST,RUNNING,MULTICAST,0x800 LINK[p2p0 0a:f6:b1:1b:4e:bb]>]

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.
 

Shawn Anderson (33 Posts)

Maker at Atomic Object. Lover of Ruby. Hobbyist game developer.

This entry was posted in Ruby and tagged . Bookmark the permalink. Both comments and trackbacks are currently closed.

11 Comments

  1. Bob
    Posted September 26, 2013 at 2:28 pm

    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.

    • Shawn Anderson
      Posted September 26, 2013 at 2:34 pm

      Glad you liked it Bob. Knowing where your objects are created is incredibly powerful.

  2. AndrewO
    Posted September 26, 2013 at 2:29 pm

    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?

    contract pre: -> { some_precondition },
    post: -> { some_postcondition },
    def transfer_money(amount)

    end

    • Shawn Anderson
      Posted September 26, 2013 at 2:36 pm

      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.

      • AndrewO
        Posted September 26, 2013 at 2:41 pm

        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. :)

        • Shawn Anderson
          Posted September 26, 2013 at 2:47 pm

          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.

  3. Posted September 26, 2013 at 4:55 pm

    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

    • Shawn Anderson
      Posted September 26, 2013 at 8:57 pm

      Good point, I haven’t used that gem before.

  4. Breno
    Posted September 26, 2013 at 8:32 pm

    Nice post!

    • Shawn Anderson
      Posted September 26, 2013 at 8:57 pm

      Thanks Breno, glad you liked it.

  5. Posted September 28, 2013 at 11:28 pm

    Nice post!

    GC was really needing an improvement, hope someday Ruby will be a reference in Games world