[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: object reference handle (like perl's reference to scalar

Eric Mahurin

5/4/2005 11:16:00 PM

> > In ruby, is there a way to get a handle of an object
> reference? In
> > perl, this is the \ operator:
> >
> > $x = 1; # \$x is a handle to change $x
> > $a = [1,2,3]; # \$a-> [1] is a handle to change an element
> in $a
> >
> > As far as I can tell, the closest that Ruby has to this is
> a
> > symbol. But, this only works for object references that
> have an
> > associated variable name. For example, there is no symbol
> > associated with an element of an array (or hash).
>
> What are you trying to do? There is no equivalent to what you
> want
> in Ruby, but in most cases, it's not necessary. A little bit
> of
> rethinking, on the other hand, is necessary.

I've have various ways I can do what I need. I just wanted to
see if I could do it the perl way.

> There is no way to do the following:
>
> a = [1, 2, 3]
> x = a[1]
> x = 4 # a == [1, 4, 3]
>
> Variables in Ruby are simply labels for object references.
> They are
> not objects themselves. In Ruby, variables are transient
> names --
> they are effectively "weightless" and take up no space
> (effectively).

Ruby variables must at least take up the space of a pointer (32
or 64 bits) and I would also imagine an entry in a symbol
table. But, that space probably isn't tracked by
ObjectSpace/GC. Not tracking that space like an object is
probably the reason why you can't have a general reference to
an object reference like perl has.

> In Perl and C-like languages, variables
> themselves
> take up space on the call stack and may refer to other places
> on the
> heap.

You are probably right about perl (treat variables like
objects), but C is more like ruby in this respect. In C most
variables are on the stack and thus transient. You can make a
reference to one of those variables (i.e. a pointer to
somewhere in the stack), but that space will become invalid
once the variable goes out of scope.

Instead of having a general one-size fits-all reference to an
object reference, you could make a new class for each type of
object reference within each class. Of course you'd want a
common store/retrieve interface to all of these. For example:

class Array

def ref(*index)
Ref.new(self,*index)
end

class Ref
def initialize(a,*i)
@a = a
@i = i
end
def value
@a[*@i]
end
def value=(v)
@a[*@i]=v
end
end

end


Example:

a = [1,2,3]
x = a.ref(1)
x.value -> 2
x.value = 4
a -> [1,4,3]
y = a.ref(0..1) # reference to a slice!
y.value -> [1,4]
y.value = [6,5,4]
a -> [6,5,4,3]

I think you could do this with just about anything. Here is
the info you need for changing various object references:

* array element/slice: array, index (and length .. or range)
* string element/slice: string, index (and length .. or range)
* hash value: hash, key
* hash key: hash, key (changes)
* local variable: binding, symbol
* instance variable: object, symbol
etc.

This goes beyond what perl references do! perl can't do
references to array slices and references to hash keys!

It looks like I answered my own question...

Now, I think putting this type of thing in the libraries could
be quite useful. At a minimum, it would allow you to easily do
the pass-by-reference thing that I've seen several questions
on.




Discover Yahoo!
Find restaurants, movies, travel and more fun for the weekend. Check it out!
http://discover.yahoo.com/we...



16 Answers

Austin Ziegler

5/6/2005 5:15:00 PM

0

On 5/4/05, Eric Mahurin <eric_mahurin@yahoo.com> wrote:
[...]
>> What are you trying to do? There is no equivalent to what you
>> want in Ruby, but in most cases, it's not necessary. A little bit
>> of rethinking, on the other hand, is necessary.
> I've have various ways I can do what I need. I just wanted to
> see if I could do it the perl way.

I'm not sure why.

>> There is no way to do the following:
>>
>> a = [1, 2, 3]
>> x = a[1]
>> x = 4 # a == [1, 4, 3]
>>
>> Variables in Ruby are simply labels for object references. They
>> are not objects themselves. In Ruby, variables are transient
>> names -- they are effectively "weightless" and take up no space
>> (effectively).
> Ruby variables must at least take up the space of a pointer (32
> or 64 bits) and I would also imagine an entry in a symbol
> table.

Must they? I'm not sure of that. *Objects* in Ruby take up a certain
amount of space, but whether the various labels for those objects
take up any space at all is a different question -- and completely
irrelevant to the execution of Ruby.

> But, that space probably isn't tracked by ObjectSpace/GC. Not
> tracking that space like an object is probably the reason why you
> can't have a general reference to an object reference like perl
> has.

With solely an implementation perspective, you might be right.
However, Matz could have easily made that space accessible -- Perl
did it, after all -- and could have made it so that variables were
real objects. He chose not to. Variable names in Ruby are just
labels. How much space they take up is completely irrelevant.
Matz deliberately chose to stay away from Perl-like semantics here
because Perl references and C pointers are some of the largest
sources of errors in those languages.

>> In Perl and C-like languages, variables themselves take up space
>> on the call stack and may refer to other places on the heap.
> You are probably right about perl (treat variables like objects),
> but C is more like ruby in this respect. In C most variables are
> on the stack and thus transient. You can make a reference to one
> of those variables (i.e. a pointer to somewhere in the stack), but
> that space will become invalid once the variable goes out of
> scope.

No, C is not at all like Ruby in this respect. The transience of a C
variable is, to be quite honest, something of an irrelevancy. You
*can* take an address of it. If I declare:

char* foo;

Yes, foo is a pointer to char, but I can still take the address of
foo (getting the pointer to the pointer). This cannot be done in any
way with Ruby. This is an undesirable thing in Ruby.

> Instead of having a general one-size fits-all reference to an
> object reference, you could make a new class for each type of
> object reference within each class. Of course you'd want a
> common store/retrieve interface to all of these. For example:

Sure, you can create a Ref class. If you look on ruby-talk archives,
you'll see several implementations in the past three years. However,
such an object is useless. It can't act as the object for which it
holds the reference. It won't report as the object for which it
holds the reference.

...

> Now, I think putting this type of thing in the libraries could
> be quite useful. At a minimum, it would allow you to easily do
> the pass-by-reference thing that I've seen several questions
> on.

No, it wouldn't (to either question: be useful, or allow
pass-by-reference). Ruby's semantics are pass-reference-by-value.
This is something that people who use Ruby just have to get used to.

That you can do what you've done in this and the next post shows
that Ruby is powerful -- but neither is useful to most (I'd argue
99%+ development cases). I have had little need for such an object
at all. (There's one case that I have in PDF::Writer where such a
reference would be mildly useful, but the reality of what I need to
do here is more the elimination of all instance variable use in what
I'm trying to do. And *that* is a different beast entirely.)

-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca



Dave Burt

5/7/2005 3:44:00 AM

0

"Austin Ziegler" <halostatue@gmail.com> contended:
> Sure, you can create a Ref class. If you look on ruby-talk archives,
> you'll see several implementations in the past three years. However,
> such an object is useless. It can't act as the object for which it
> holds the reference. It won't report as the object for which it
> holds the reference.

Why do you assert these things about any concievable Ref implementation?
Even my Ref implementation does act as the object for which it holds the
reference for all purposes except explicitly querying type and reference
reassignment. Surely it's entirely conceivable to have a reference object
whose only difference from the referenced object is that it responds to
deref and deref=?

> (There's one case that I have in PDF::Writer where such a
> reference would be mildly useful, but the reality of what I need to
> do here is more the elimination of all instance variable use in what
> I'm trying to do. And *that* is a different beast entirely.)

I'd be interested to hear a little more about this, as you've said this is a
sub-1% problem - it must be interesting.

Cheers,
Dave


Austin Ziegler

5/7/2005 4:12:00 AM

0

On 5/6/05, Dave Burt <dave@burt.id.au> wrote:
> "Austin Ziegler" <halostatue@gmail.com> contended:
>> Sure, you can create a Ref class. If you look on ruby-talk
>> archives, you'll see several implementations in the past three
>> years. However, such an object is useless. It can't act as the
>> object for which it holds the reference. It won't report as the
>> object for which it holds the reference.
> Why do you assert these things about any concievable Ref
> implementation? Even my Ref implementation does act as the object
> for which it holds the reference for all purposes except
> explicitly querying type and reference reassignment. Surely it's
> entirely conceivable to have a reference object whose only
> difference from the referenced object is that it responds to deref
> and deref=?

I don't recall the problems mentioned, but Ref objects have been
mentioned in the past as problems. If anything does a class-based
check, then the Ref object will never have a chance (and, yes, I do
this in PDF::Writer some; not much, but some). More to the point, I
was looking at the CSV code the other day to help someone and we
saw:

case foo
when String
when IO
when ...
end

(1) It doesn't work with StringIO. (2) It can't/won't work with a
Ref object, because you'd need to redefine Class#=== (or is it
Module#===) to get this to work right.

>> (There's one case that I have in PDF::Writer where such a
>> reference would be mildly useful, but the reality of what I need
>> to do here is more the elimination of all instance variable use
>> in what I'm trying to do. And *that* is a different beast
>> entirely.)
> I'd be interested to hear a little more about this, as you've said
> this is a sub-1% problem - it must be interesting.

It's a purity problem. Right now, when you render a SimpleTable, it
makes some modifications to bits of the data in the SimpleTable.
This makes it very fragile. You cannot write the same SimpleTable to
two different PDF files at the same time, because of this. If you
render a SimpleTable, you may get a slightly different result if you
render it again.

I've got a (broken) reimplementation that separate out these
variables into a RenderVars object (it could as well be an
OpenStruct, but this also lets me pull some methods out of
SimpleTable that are really only related to the RenderVars). Doing
this will let me get around the problem of calls like:

_y, _height = __table_column_headings(_y, @data)

It's that place where a ref-object might be useful -- I update _y in
place rather than by reassignment at the end. But it's a small thing
in comparison to everything else that I do.

-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca



Dave Burt

5/7/2005 7:45:00 AM

0

"Austin Ziegler" <halostatue@gmail.com> conversed:
> On 5/6/05, Dave Burt <dave@burt.id.au> wrote:
>> Surely it's
>> entirely conceivable to have a reference object whose only
>> difference from the referenced object is that it responds to deref
>> and deref=?
>
> I don't recall the problems mentioned, but Ref objects have been
> mentioned in the past as problems. If anything does a class-based
> check, then the Ref object will never have a chance (and, yes, I do
> this in PDF::Writer some; not much, but some). More to the point, I
> was looking at the CSV code the other day to help someone and we
> saw:
>
> case foo
> when String
> when IO
> when ...
> end
>
> (1) It doesn't work with StringIO. (2) It can't/won't work with a
> Ref object, because you'd need to redefine Class#=== (or is it
> Module#===) to get this to work right.

That's not even difficult.

class Ref
def kind_of?(mod) __getobj__.kind_of?(mod) end
end
class Module
def ===(other) other.kind_of? self end
end

My Ref module at http://www.dave.burt.id.au/r... now tries to behave
as much like the referred-to object as possible. You above Module case
statement will work with Refs now, as will uses of respond_to? is_a?
kind_of? and class. A Ref will additionally respond_to a few unique methods
(ie deref, deref=).

>>> (There's one case that I have in PDF::Writer where such a
>>> reference would be mildly useful...
>
> It's a purity problem. Right now, when you render a SimpleTable, it
> makes some modifications to bits of the data in the SimpleTable.
> This makes it very fragile. You cannot write the same SimpleTable to
> two different PDF files at the same time, because of this. If you
> render a SimpleTable, you may get a slightly different result if you
> render it again.
>
> I've got a (broken) reimplementation that separate out these
> variables into a RenderVars object (it could as well be an
> OpenStruct, but this also lets me pull some methods out of
> SimpleTable that are really only related to the RenderVars). Doing
> this will let me get around the problem of calls like:
>
> _y, _height = __table_column_headings(_y, @data)
>
> It's that place where a ref-object might be useful -- I update _y in
> place rather than by reassignment at the end. But it's a small thing
> in comparison to everything else that I do.

Obviously an OpenStruct (or even an Array) could do the job, but why not try
a Ref? It's see-through! (Except for assignment, you have to do ref.deref=)
Of course, it's not much different from a Struct.new(:deref).

Cheers,
Dave


Robert Klemme

5/7/2005 7:57:00 AM

0


"Dave Burt" <dave@burt.id.au> schrieb im Newsbeitrag
news:am_ee.5577$31.897@news-server.bigpond.net.au...
> "Austin Ziegler" <halostatue@gmail.com> conversed:
>> On 5/6/05, Dave Burt <dave@burt.id.au> wrote:
>>> Surely it's
>>> entirely conceivable to have a reference object whose only
>>> difference from the referenced object is that it responds to deref
>>> and deref=?
>>
>> I don't recall the problems mentioned, but Ref objects have been
>> mentioned in the past as problems. If anything does a class-based
>> check, then the Ref object will never have a chance (and, yes, I do
>> this in PDF::Writer some; not much, but some). More to the point, I
>> was looking at the CSV code the other day to help someone and we
>> saw:
>>
>> case foo
>> when String
>> when IO
>> when ...
>> end
>>
>> (1) It doesn't work with StringIO. (2) It can't/won't work with a
>> Ref object, because you'd need to redefine Class#=== (or is it
>> Module#===) to get this to work right.
>
> That's not even difficult.
>
> class Ref
> def kind_of?(mod) __getobj__.kind_of?(mod) end
> end
> class Module
> def ===(other) other.kind_of? self end
> end
>
> My Ref module at http://www.dave.burt.id.au/r... now tries to
> behave as much like the referred-to object as possible. You above Module
> case statement will work with Refs now, as will uses of respond_to? is_a?
> kind_of? and class. A Ref will additionally respond_to a few unique
> methods (ie deref, deref=).

Hm, and what do you do if you have to test for Ref objects?

>>>> (There's one case that I have in PDF::Writer where such a
>>>> reference would be mildly useful...
>>
>> It's a purity problem. Right now, when you render a SimpleTable, it
>> makes some modifications to bits of the data in the SimpleTable.
>> This makes it very fragile. You cannot write the same SimpleTable to
>> two different PDF files at the same time, because of this. If you
>> render a SimpleTable, you may get a slightly different result if you
>> render it again.
>>
>> I've got a (broken) reimplementation that separate out these
>> variables into a RenderVars object (it could as well be an
>> OpenStruct, but this also lets me pull some methods out of
>> SimpleTable that are really only related to the RenderVars). Doing
>> this will let me get around the problem of calls like:
>>
>> _y, _height = __table_column_headings(_y, @data)
>>
>> It's that place where a ref-object might be useful -- I update _y in
>> place rather than by reassignment at the end. But it's a small thing
>> in comparison to everything else that I do.
>
> Obviously an OpenStruct (or even an Array) could do the job, but why not
> try a Ref? It's see-through! (Except for assignment, you have to do
> ref.deref=) Of course, it's not much different from a Struct.new(:deref).

I didn't follow this thread thoroughly, all I can say is that I personally
haven't missed refs in Ruby until now. There are certainly things that
speak in favour of your concept.

But there are also problems. Ironically some of them seem to be caused by
the fact that you make a Ref behave like the original instance as much as
possible. That way Ref usage is more implicit than explicit and this can
lead to confusion or subtle errors due to aliasing (i.e. you think you got a
copy of something and modify it and some other piece of code breaks because
it was just a ref).

<soapbox>
It still might be worthwile, I just get the feeling that people try to stuff
things from other programming languages into Ruby because they found them
cute / useful / the only way to solve certain things in that language. IMHO
programming languages are different for a reason and often it's much better
to adhere to the old saying "when in Rome do as the Romans do"... :-)
</soapbox>

Kind regards

robert

Austin Ziegler

5/7/2005 12:33:00 PM

0

On 5/7/05, Dave Burt <dave@burt.id.au> wrote:
[...]
> Obviously an OpenStruct (or even an Array) could do the job, but
> why not try a Ref? It's see-through! (Except for assignment, you
> have to do ref.deref=) Of course, it's not much different from a
> Struct.new(:deref).

If _y were the only place this were an issue, I'd agree with you --
a Ref (perhaps even a WeakRef) might be better. But it's not -- and
I can gain other efficiencies once I go through the development time
again. (The table rendering code is a mess. The only reason it's
still a mess is that the major refactoring broke it worse.)

-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca



Dave Burt

5/7/2005 12:53:00 PM

0

>> My Ref module at http://www.dave.burt.id.au/r... now tries to
>> behave as much like the referred-to object as possible. You above Module
>> case statement will work with Refs now, as will uses of respond_to? is_a?
>> kind_of? and class. A Ref will additionally respond_to a few unique
>> methods (ie deref, deref=).
>
> Hm, and what do you do if you have to test for Ref objects?

variable.ref?

> I didn't follow this thread thoroughly, all I can say is that I personally
> haven't missed refs in Ruby until now. There are certainly things that
> speak in favour of your concept.
>
> But there are also problems. Ironically some of them seem to be caused by
> the fact that you make a Ref behave like the original instance as much as
> possible. That way Ref usage is more implicit than explicit and this can
> lead to confusion or subtle errors due to aliasing (i.e. you think you got
> a copy of something and modify it and some other piece of code breaks
> because it was just a ref).

You're right about that. I prefer the new implementation:
Ref = Struct.new(:deref)

> <soapbox>
> It still might be worthwile, I just get the feeling that people try to
> stuff things from other programming languages into Ruby because they found
> them cute / useful / the only way to solve certain things in that
> language. IMHO programming languages are different for a reason and often
> it's much better to adhere to the old saying "when in Rome do as the
> Romans do"... :-)
> </soapbox>

I don't think what I've done here is anything like that. The concept of a
reference here is just a wrapper or pointer, and it has to have a use. Sure,
it causes problems in C and Perl, and Ruby definitely offers more elegant
tools fo most of the problems that are solved in those languages with
pointers, but I'm coming from a Rubyist's perspective here, and all I'm
proposing is a new container, for a single object.

And I think Austin's PDF::Writer example is one case where it's useful (that
is, passing an object by reference into a method so the method can replace
the object).

Cheers,
Dave


Robert Klemme

5/7/2005 3:28:00 PM

0


"Dave Burt" <dave@burt.id.au> schrieb im Newsbeitrag
news:HS2fe.5993$31.2330@news-server.bigpond.net.au...
>>> My Ref module at http://www.dave.burt.id.au/r... now tries to
>>> behave as much like the referred-to object as possible. You above Module
>>> case statement will work with Refs now, as will uses of respond_to?
>>> is_a? kind_of? and class. A Ref will additionally respond_to a few
>>> unique methods (ie deref, deref=).
>>
>> Hm, and what do you do if you have to test for Ref objects?
>
> variable.ref?
>
>> I didn't follow this thread thoroughly, all I can say is that I
>> personally haven't missed refs in Ruby until now. There are certainly
>> things that speak in favour of your concept.
>>
>> But there are also problems. Ironically some of them seem to be caused
>> by the fact that you make a Ref behave like the original instance as much
>> as possible. That way Ref usage is more implicit than explicit and this
>> can lead to confusion or subtle errors due to aliasing (i.e. you think
>> you got a copy of something and modify it and some other piece of code
>> breaks because it was just a ref).
>
> You're right about that. I prefer the new implementation:
> Ref = Struct.new(:deref)
>
>> <soapbox>
>> It still might be worthwile, I just get the feeling that people try to
>> stuff things from other programming languages into Ruby because they
>> found them cute / useful / the only way to solve certain things in that
>> language. IMHO programming languages are different for a reason and
>> often it's much better to adhere to the old saying "when in Rome do as
>> the Romans do"... :-)
>> </soapbox>
>
> I don't think what I've done here is anything like that.

I had to place that comment in some of these threads that I feel we're seing
more and more recently. I probably didn't pick the most appropriate one...
:-)

> The concept of a reference here is just a wrapper or pointer, and it has
> to have a use. Sure, it causes problems in C and Perl, and Ruby definitely
> offers more elegant tools fo most of the problems that are solved in those
> languages with pointers, but I'm coming from a Rubyist's perspective here,
> and all I'm proposing is a new container, for a single object.
>
> And I think Austin's PDF::Writer example is one case where it's useful
> (that is, passing an object by reference into a method so the method can
> replace the object).

Yuck, may well be. On a side note, the fact that ruby methods can return an
arbitrary number of objects is a really great thing, that can also help with
some of these replacement problems.

Kind regards

robert


dblack

5/7/2005 3:58:00 PM

0

Dave Burt

5/7/2005 10:35:00 PM

0


"Robert Klemme" <bob.news@gmx.net> wrote:
>>> <soapbox>
>>> It still might be worthwile, I just get the feeling that people try to
>>> stuff things from other programming languages into Ruby because they
>>> found them cute / useful / the only way to solve certain things in that
>>> language. IMHO programming languages are different for a reason and
>>> often it's much better to adhere to the old saying "when in Rome do as
>>> the Romans do"... :-)
>>> </soapbox>

> "Dave Burt" <dave@burt.id.au> schrieb:
>> I don't think what I've done here is anything like that.

> I had to place that comment in some of these threads that I feel we're
> seing more and more recently. I probably didn't pick the most appropriate
> one... :-)

There are two reasons I like these threads.

The first is that when Perl- or C- or Whatever-thinkers ask these questions
to this list, they will be exposed to the Ruby Way of solving a class of
problems, and helped to free their mind.

Secondly, Ruby's a great language to push around and mould to your own whim
as a programmer. It's a great language to create DSLs in. These interesting
hacks are not going to displace the Ruby Way, but they help expand my
thinking in a similar way to learning Ruby (where I learned to routinely use
closures and meta-programming).

>> ... all I'm proposing is a new container, for a single object.
>>
>> And I think Austin's PDF::Writer example is one case where it's useful
>> (that is, passing an object by reference into a method so the method can
>> replace the object).
>
> Yuck, may well be. On a side note, the fact that ruby methods can return
> an arbitrary number of objects is a really great thing, that can also help
> with some of these replacement problems.

Heh, I think that's Austin's view, too. He seems to badly want to rewrite it
:) Anyway, multiple returns are interesting. You get an extra container
there, too (My Ref is just an extra container). They're often quite
disobvious, and I'm sure there are cases where it would seem more obvious to
modify an argument "in-place", even though "that's not possible in Ruby".

Cheers,
Dave