A Tale of Two Rubies...with apologies to Charles Dickens
About Me
Joshua BallancoName:
About Me
Ankara, TurkeyLocation:
About Me
Burnside DigitalEmployer:
How many Ruby implementations do
you use?
Matz’s Ruby InterpreterJRuby
Rubinius
IronRubyMacRuby
RubyMotion
MagLev Cardinal
Topaz
What impact do alternate Rubies have
on me?
What about fragmentation?
A Story...Once upon a time there was a Rails app,
that needed to be ported to JRuby
• Ditch C-extensions
• Look for JRuby specific versions of gems
• Find a good app server
• Run your test suite!
What do you do when...
ArgumentError: comparison of ActiveSupport::TimeWithZone with ActiveSupport::TimeWithZone failed
A Side Note on Reading Code
Read Code
A Side Note on Reading Code
Read Code!
A Side Note on Reading Code
Read A Lot of Code
A Side Note on Reading Code
Read Twice as Much Code as You Write
A Side Note on Reading Code
Read Ten Times as Much Code as You Write
A Side Note on Reading Code
Read Code
Let’s Go Code Diving!activesupport-3.2.13/lib/active_support/time_with_zone.rb
Let’s Go Code Diving!
Confused yet?
When was the last time you called TimeWithZone.new anyway???
We Have to go Deeper!
activesupport-3.2.13/lib/active_support/core_ext/time/zones.rb
activesupport-3.2.13/lib/active_support/core_ext/date_time/zones.rb
We Have to go Deeper!
Read Code...and Comments
So Far...
• TimeWithZone initializes @utc to a Time or DateTime
• Comparison with <=> passes through “other” to @utc’s <=> operator
But then...
...why?
Remember This?
It Gets Worse...
Remember this?
Oh, ActiveSupport...
activesupport-3.2.13/lib/active_support/core_ext/date_time/calculations.rb
Oh, ActiveSupport...
activesupport-3.2.13/lib/active_support/core_ext/time/calculations.rb
This isn’t a Rails Talk...
Really...it’s not...
Getting to the Heart of the Matter: JRuby
• If “other” is a Time object, compare
• Otherwise: nil
src/org/jruby/RubyTime.java
Getting to the Heart of the Matter: MRI
Getting to the Heart of the Matter: MRI
• If “other” is a Time object, compare
• If not, call <=> on other, passing self as the argument
• If that works, take the negation of the result
• Otherwise: nil
So...Fix JRuby
1 Ruby Down1 To Go
AlwaysBeCurious
What Classes Reverse Compare Like This?• Time
• ...
• String
• ...
• That’s it!
BUT!
Oh, MRI...
Break it down...
If “other” is a string, do a string comparison(in the else clause...yay)
Break it down...
If “other” can not be converted into a string, return nil
Break it down...
If “other” also doesn’t have its own comparison operator, return nil
Break it down...
If “other” does have its own comparison operator, call it and return the negation of the result
BUT! ...
Remember this?
Uhh...
Fun With Poorly Specified Behavior
...but I thought <=> only ever returned -1, 0, or 1?
So...Fix MRI
fin?Not quite...
What about...
Crap...
Fun With Mutual Recursion
Fun With Mutual Recursion
Fun With Mutual Recursion
The Moral
• When MRI was the only game in town, whatever MRI did was “Ruby”
• Re-implementing “Ruby” allows us to reconsider behaviors
• The key is communication and community
finQuestions?