Skip to content

Instantly share code, notes, and snippets.

@chrisseaton
Created January 12, 2015 10:04
Show Gist options
  • Save chrisseaton/252e4f42448b4dee45fa to your computer and use it in GitHub Desktop.
Save chrisseaton/252e4f42448b4dee45fa to your computer and use it in GitHub Desktop.

Take this spec:

https://github.com/rubinius/rubinius/blob/ae81a26ec0b3c81aa287db053b4d11e634aa67e4/spec/ruby/core/fixnum/fdiv_spec.rb#L45-L48

I've reimplemented it here for simplicity:

class Mock
  def coerce(x)
    [1, 10]
  end
end

p 1.fdiv(Mock.new)

That calls fdiv on a Fixnum:

def fdiv(other)
  self.to_f / other
end

That converts the receiver to a Float and calls /. As the RHS is a Mock the primitive for Float#/ will fail and will call redo_coerced.

def divide(other)
  Rubinius.primitive :float_div
  redo_coerced :/, other
end

That calls other.coerce. Our mock object returns [1, 10] for this. Then we re-call / on the first value, with the operand as the right value. That's 1./(10). That does integral division.

def math_coerce(other, error=:coerce_error)
  begin
    values = other.coerce(self)
  rescue
    if error == :coerce_error
      raise TypeError, "#{other.class} can't be coerced into #{self.class}"
    else
      raise ArgumentError, "comparison of #{self.class} with #{other.class} failed"
    end
  end

  unless Rubinius::Type.object_kind_of?(values, Array) && values.length == 2
    raise TypeError, "coerce must return [x, y]"
  end

  return values[1], values[0]
end

def redo_coerced(meth, right)
  b, a = math_coerce(right)
  a.__send__ meth, b
end

So why does the test produce a Float, 0.1? When I run this code in Truffle I get a Fixnum, 0, which makes sense to me reading the code, but it isn't right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment