Forum: Ruby-core Specs for coercion?

45196398e9685000d195ec626d477f0e?d=identicon&s=25 Thomas Sawyer (7rans)
on 2013-02-17 20:24
(Received via mailing list)
Issue #3434 has been updated by trans (Thomas Sawyer).


=begin
Regarding the coercion spec, I had need of coercion for Array the other
day while implementing a set logic system. So I wondered if coercion
can't be more general and not just isolated to Numerics. Is there a
necessary reason coercion can't work in general for ((*operators*))
across ((*all classes*))?
=end

----------------------------------------
RubySpec #3434: Specs for coercion?
https://bugs.ruby-lang.org/issues/3434#change-36450

Author: marcandre (Marc-Andre Lafortune)
Status: Assigned
Priority: Normal
Assignee: marcandre (Marc-Andre Lafortune)
Category:
Target version: 2.0.0


=begin
 What are the official specs of coercion for mathematical classes?

 I will take Matrix as an example, but my questions are meant to be for
the general case.

 My understanding is that for a  `obj.coerce(obj_2)` should return
`[compatible_2, compatible]` such that `compatible2.send(some_operation,
compatible)` returns (if possible) a meaningful result.

 Can we assume anything more about coercion? I'm asking because I find
in test_matrix (@m1 being a Matrix):

   def test_scalar_mul
     s1 = @m1.coerce(1).first
     assert_equal(Matrix[[1]], (s1 * 1) * Matrix[[1]])
     assert_equal(Vector[2], s1 * Vector[2])
     assert_equal(Matrix[[2]], s1 * Matrix[[2]])
     o = Object.new
     def o.coerce(x)
       [1, 1]
     end
     assert_equal(1, s1 * o)
   end

 1) Should the first and last assert work? Are implementers of other
mathematical classes mandated/encouraged to provide that level of
compatibility? Are users of `coerce` encouraged (or guaranteed success)
when doing any other operation than `compatible2 * compatible` or
similar?

 My feeling is that the only thing one should do with the results of
coerce is to call an operation on the first element and pass the second
element. Doing operations using only one of the two returned elements
with another new object should yield undetermined results.

 If this is the case, I feel the Matrix library would be best to assume
that Scalar#* is called with a Matrix or Vector (remember that the
Scalar is not meant to be used directly by anybody else than the Matrix
lib), and these two assert would _not_ work.

 2) The second assert is clearly implementation dependant. In the
current implementation, both Vector and Matrix use Matrix::Scalar as a
temporary class, but that could change.

 3) I am assuming that compatible doesn't have to be equal?, eql? or ==
to obj nor of the same class, and the same is true for compatible_2 vs
obj_2, right? Thus the third assert isn't a spec guaranteed for all
implementations.

 4) Finally, a somewhat trivial question: should `obj.coerce(obj_2)`
succeed if `obj` and `obj_2` are of the same class (and presumably
return `[obj_2, obj]`)? Clearly this is not very useful, but the specs
should be made precise.

 This is the case for Numeric and is explicit in the documentation but
fails for Matrix:

     Matrix.I(2).coerce(Matrix.I(2))  # => TypeError: Matrix can't be
coerced into Matrix

 Coercion should always work for the trivial case of two objects of the
same class, right?

 Thanks.
 --
 Marc-André
=end
This topic is locked and can not be replied to.