Preserve value-type semantics in imported types


#1

I’m importing a value type from the CLR and I’d like to preserve value
type
semantics in Ruby … I’m not sure this can be done.

Consider the Point struct in C# as an example:

Point p1 = new Point(2, 3);
Point p2 = p1; // value types get copied in the CLR upon assignment
p2.X += 1;
Assert.Equals(p1.X + 1, p2.X);

So the equivalent code that uses my RubyCLR bridge doesn’t display the
equivalent semantics:

p1 = Point.new(2, 3)
p2 = p1 # the object reference gets copied in Ruby, so this is now an
alias
p2.X += 1
assert_equal p1.X, p2.X

The value types are stored as opaque blobs in Ruby’s T_DATA struct.

Since I can’t overload the assignment operator, are there any tricks
that
can help me? Or do I have to write a custom implementation of clone for
value types that memcpys the T_DATA struct?

Thanks
-John
http://www.iunknown.com


#2

Dear John,

Welcome to ref-value world!
I am not sure what is your problem in real, but I might suggest
you to read the clone and dup methods of Object class at
http://www.ruby-doc.org/core

Don’t you think how deep your need to copy an object is
case by case after all? I leave here three samples below.
sorry, if I haven’t got the point.

BTW you wrote p1.X, p1.Y and so on, but starting with a
capital letter means a constant in Ruby language.
If you were about to mean variables, they should start with a small
such that p1.x, p1.y…

cheers,
nori


#3

Thanks, Nori!

Perhaps it wasn’t super clear in my example, but this line of code:

p = Point.new(3, 4)

actually creates a new CLR Point value type inside of a Ruby VALUE
object. A
CLR value type is an opaque blob of data (but in this case is really a
couple of 32 bit integers packed together), so I store it in a T_DATA
struct. So I allocate enough memory to hold the value type, and tell the
CLR
to create the value type at the address of the T_DATA struct in the
VALUE
object.

X and Y are properties defined in the Point value type class in the CLR.
They map to accessor methods get/set_X and get/set_Y. My RubyCLR bridge
maps
these things automagically through liberal use of const_missing and
method_missing. So I can’t change these names even if they aren’t
Ruby-esque. Those are the case-sensitive method and property names
defined
by the value type in the CLR.

I guess the real issue is that I don’t think there’s a way to force
value
type semantics onto Ruby reference types. It would be nice to preserve
CLR
value type semantics inside of Ruby, but hey- they’re different type
systems
so you need to abide by the rules of those type systems.

I’m just worried that it might introduce bugs in code that use my
bridge:

p1 = p2 is just so much more intuitive than p1 = p2.clone

If you’re curious about my RubyCLR bridge, you can download my first
public
drop of the bits here:
http://www.iunknown.com/articles/2006/01/12/first-drop-of-rubyclr

I’m working on a new drop that marshals value types correctly - hence
this
question on the list. Hopefully I’ll have support early next week for
folks
to play with.

Thanks
-John
http://www.iunknown.com


#4

sorry John, I forgot to paste the sample code, but it may not be
necessary as you already know clone and dup.

I have just browsed RubyCLR and some more.
However, let me excuse writing here rather general things
because I haven’t read your program carefully.

As you already know, we cannot assume classes of arguments
when we make libraries in ruby, and types we use in ruby are not fully
the same as those in the system. But I am not worried, wish neither
would
you be. It seems that the types you need to keep right are not of
values
inside ruby programs, but of those to interface to outside ruby, that
is the places we carefully use ruby->C and C->ruby functions, right?
Such type information in ruby objects shall be only accessible to read
so that ruby applications do not change.

I guess everybody overcome p2 = p1 and p2 = pl.clone
strangeness sooner or later :slight_smile:

greetings to you, Mathew, Ben and their mom… and more?
nori


#5

On Feb 10, 2006, at 5:20 PM, John L. wrote:

I’m just worried that it might introduce bugs in code that use my
bridge:

p1 = p2 is just so much more intuitive than p1 = p2.clone

In the eye of the beholder…

I like that Ruby insists on uniform semantics for assignment.
As such, I don’t ever have to consider if p1 = p2 is really p1 =
p2.clone

Side note:

Is it fair to say that Object#clone should be written such that
b = a.clone always results in (a == b) being true and
(a.equal?(b)) being false? Is it OK for clone to return self
or should an exception be raised as with Fixnum, Symbol, etc.
when a new instance would break the value/identity semantics of the
class?

Gary W.