Determining the attribute names of an object

The way to determine the names of the attributes of objects created
from a Class, Struct and OpenStruct are all different.

For an object created from a Class you call "instance_variables". I
wish that method would have been named "attributes".

For an object created from a Struct you call "members". Why not the
same as the previous case?

For an object created using OpenStruct you call "marshal_dump.keys".
My first guess was to call "table.keys", but the table attribute is
protected.

I think there should be a common way to do this for all three cases.

Suggestion #1
- add an "instance_variables" method to Struct that is the same as "members"
- add an "instance_variables" method to OpenStruct that returns @table.keys

Suggestion #2
- add an "attributes" method to Class that is the same as "instance_variables"
- add an "attributes" method to Struct that is the same as "members"
- add an "attributes" method to OpenStruct that returns @table.keys

···

--
R. Mark Volkmann
Partner, Object Computing, Inc.

Hi --

The way to determine the names of the attributes of objects created
from a Class, Struct and OpenStruct are all different.

For an object created from a Class you call "instance_variables". I
wish that method would have been named "attributes".

instance variables are not the same as attributes. Attributes can be,
and often are, implemented by using instance variables to hold state.
But there is not a one-to-one relation. Even if you define
"attribute" strictly to mean methods defined with the attr_* family,
there still may be instance variables in use that are not connected
with those methods.

For an object created from a Struct you call "members". Why not the
same as the previous case?

There's no connection:

   irb(main):001:0> S = Struct.new("S",:x)
   => Struct::S
   irb(main):002:0> s = S.new
   => #<struct Struct::S x=nil>
   irb(main):003:0> s.x = 1
   => 1
   irb(main):004:0> s.instance_variables
   =>
   irb(main):005:0> s.members
   => ["x"]

Instance variables don't map one-to-one to any higher-level concept
like attributes or members.

David

···

On Wed, 24 Aug 2005, Mark Volkmann wrote:

--
David A. Black
dblack@wobblini.net

Attributes are not the same as instance variables. Attributes really
are code wrappers around instance variables for controlled (and
customized) access.

Attributes may or may not have a related instance variable; and vice versa.

···

On 8/24/05, Mark Volkmann <r.mark.volkmann@gmail.com> wrote:

The way to determine the names of the attributes of objects created
from a Class, Struct and OpenStruct are all different.

For an object created from a Class you call "instance_variables". I
wish that method would have been named "attributes".

--
Mohit Muthanna [mohit (at) muthanna (uhuh) com]
"There are 10 types of people. Those who understand binary, and those
who don't."

instance variables are not the same as attributes. Attributes can be,
and often are, implemented by using instance variables to hold state.
But there is not a one-to-one relation. Even if you define
"attribute" strictly to mean methods defined with the attr_* family,
there still may be instance variables in use that are not connected
with those methods.

I really don't get this. Can you give a definition of each of the
terms "instance variable" and "attribute"? I'm pretty sure most
people that have been doing OO development for years would say that
they thought those were the same thing. Maybe many of us were sleeping
in class when those concepts were taught. :wink:

Are you saying that instance variables are all the things that start
with "@" that have been assigned a value within an object?

Are you saying that attributes are implied by the existence of get and
perhaps set methods?

> For an object created from a Struct you call "members". Why not the
> same as the previous case?

There's no connection:

   irb(main):001:0> S = Struct.new("S",:x)
   => Struct::S
   irb(main):002:0> s = S.new
   => #<struct Struct::S x=nil>
   irb(main):003:0> s.x = 1
   => 1
   irb(main):004:0> s.instance_variables
   =>
   irb(main):005:0> s.members
   => ["x"]

Instance variables don't map one-to-one to any higher-level concept
like attributes or members.

But conceptually what is the difference between members of a Struct
and attributes of an object? And conceptually what is the difference
between the members of a Struct and the members of an OpenStruct? Why
would their be a different way to discover them?

···

On 8/24/05, David A. Black <dblack@wobblini.net> wrote:

--
R. Mark Volkmann
Partner, Object Computing, Inc.

Well, here's an example:

class Name
     def initialize( first, last )
         @first, @last = first, last
     end

     attr_accessor :first, :last

     def full_name
         "#{@first} #{@last}"
     end

     def full_name=( name )
         @first, @last = name.split
     end
end

I would say that the above class has a full_name attribute, but it certainly does not have a @full_name instance variable.

Hope that helps.

James Edward Gray II

···

On Aug 24, 2005, at 9:43 AM, Mark Volkmann wrote:

I really don't get this. Can you give a definition of each of the
terms "instance variable" and "attribute"? I'm pretty sure most
people that have been doing OO development for years would say that
they thought those were the same thing. Maybe many of us were sleeping
in class when those concepts were taught. :wink:

Hi --

instance variables are not the same as attributes. Attributes can be,
and often are, implemented by using instance variables to hold state.
But there is not a one-to-one relation. Even if you define
"attribute" strictly to mean methods defined with the attr_* family,
there still may be instance variables in use that are not connected
with those methods.

I really don't get this. Can you give a definition of each of the
terms "instance variable" and "attribute"? I'm pretty sure most
people that have been doing OO development for years would say that
they thought those were the same thing. Maybe many of us were sleeping
in class when those concepts were taught. :wink:

They may be the same in other languages. In Ruby they're related but
different.

Are you saying that instance variables are all the things that start
with "@" that have been assigned a value within an object?

Yes, by definition, @vars are instance variables.

Are you saying that attributes are implied by the existence of get and
perhaps set methods?

There are a couple of ways to look at that. My reasoning is as
follows:

The utility of method pairs like this:

   def x; @x; end
   def x=(y); @x = y; end

is so great, that the attr_* family of automatic method-writers was
created to make it easy to write them.

The "attr" part of attr_* means attribute -- so presumably those
get/set method pairs give you an attribute.

However, in my opinion, there's no reason to limit the concept of
"attribute" to those that happen to be created with attr_*, or those
that take exactly the same form. You might have an 'x' attribute, and
then decide you need something more complex:

   def x=(y); @x = y.capitalize; end

I personally don't think that should make it less of an 'attribute'.

One could argue it differently, though. In a sense, the *only* thing
that makes something an attribute (as opposed to just a method or pair
of methods) is the presence of the attr_* call. So those shortcut
methods also serve as a kind of documentation of your attributes.

But I think it's a bit harsh, so to speak, to disqualify what might
otherwise be called an attribute because it isn't implemented exactly
the way attr_* implements them. I don't know that it really makes
much difference, except in documentation (and I know there's been
disucssion in the past, for example, of whether RDoc should view
attributes as a separate construct, or just document them as their
underlying methods).

On the other side of the picture: even if you do choose to refer only
to the attr_*/instance-var-based get/set methods as attributes, it's
still true that instance variables are not constrained by that
definition. They can be used for many other purposes.

(I'll stop here and maybe someone else will chime in on Structs.)

David

···

On Wed, 24 Aug 2005, Mark Volkmann wrote:

On 8/24/05, David A. Black <dblack@wobblini.net> wrote:

--
David A. Black
dblack@wobblini.net

Ah ... thanks for the explanation! Had I been paying attention, I
would have understood the distinction between attributes and instance
variables from reading pages 32-33 in Pickaxe 2.

That still leaves the question of why Structs have "members" instead
of "instance variables" and why OpenStructs have neither.

···

--
R. Mark Volkmann
Partner, Object Computing, Inc.

Yeah,

Instance variables are a concern of the developer of the object, but attributes are a concern of the user of the object.

Julian.

···

On 25/08/2005, at 12:53 AM, James Edward Gray II wrote:

On Aug 24, 2005, at 9:43 AM, Mark Volkmann wrote:

I really don't get this. Can you give a definition of each of the
terms "instance variable" and "attribute"? I'm pretty sure most
people that have been doing OO development for years would say that
they thought those were the same thing. Maybe many of us were sleeping
in class when those concepts were taught. :wink:

Well, here's an example:

class Name
    def initialize( first, last )
        @first, @last = first, last
    end

    attr_accessor :first, :last

    def full_name
        "#{@first} #{@last}"
    end

    def full_name=( name )
        @first, @last = name.split
    end
end

I would say that the above class has a full_name attribute, but it certainly does not have a @full_name instance variable.

Hope that helps.

James Edward Gray II

Hi --

Ah ... thanks for the explanation! Had I been paying attention, I
would have understood the distinction between attributes and instance
variables from reading pages 32-33 in Pickaxe 2.

That still leaves the question of why Structs have "members" instead
of "instance variables" and why OpenStructs have neither.

If anything, I would say members correspond to attributes, not to
instance variables. But really neither. A Struct is just a class
that chooses to describe some of its capabilities as members. These
can coexist with attributes:

   irb(main):001:0> S = Struct.new("S",:a,:b)
   => Struct::S
   irb(main):002:0> class S; attr_accessor :x; end
   => nil
   irb(main):003:0> s = S.new
   => #<struct Struct::S a=nil, b=nil>
   irb(main):004:0> s.x = 1
   => 1
   irb(main):006:0> s.instance_variables
   => ["@x"]
   irb(main):007:0> s.members
   => ["a", "b"]

There's some overlap in functionality (just as their is between
'method' and 'attribute'), but I think it's probably good to have a
different name for the very specialized thing that Structs have, which
is created and implemented differently from attributes in the attr_*
sense.

David

···

On Thu, 25 Aug 2005, Mark Volkmann wrote:

--
David A. Black
dblack@wobblini.net

Mark Volkmann wrote:

Ah ... thanks for the explanation! Had I been paying attention, I
would have understood the distinction between attributes and instance
variables from reading pages 32-33 in Pickaxe 2.

That still leaves the question of why Structs have "members" instead
of "instance variables" and why OpenStructs have neither.

Well, Structs are not implemented by using instance variables (well,
they are, but not the way you'd expect).

If I were doing it, I would implement Structs so that there was a
one-to-one correspondence between members and instance variables.
Then this wouldn't be an issue.

As for OpenStruct... have you looked at the code? :slight_smile:

Its author commented once that it was something he threw together
in a few minutes as a toy, and it was amazing how many people
used it.

Issues like this led me to create SuperStruct -- but beware, it has
bugs. If there is enough interest in it, I'll fix it.

Hal

Hi --

···

On Thu, 25 Aug 2005, Hal Fulton wrote:

Mark Volkmann wrote:

Ah ... thanks for the explanation! Had I been paying attention, I
would have understood the distinction between attributes and instance
variables from reading pages 32-33 in Pickaxe 2.

That still leaves the question of why Structs have "members" instead
of "instance variables" and why OpenStructs have neither.

Well, Structs are not implemented by using instance variables (well,
they are, but not the way you'd expect).

If I were doing it, I would implement Structs so that there was a
one-to-one correspondence between members and instance variables.
Then this wouldn't be an issue.

What if you wanted to add methods to the class, or one or more
instances, that used instance variables in a non-member/attr-like way?
It seems arbitrary to decide that Structs can't or shouldn't do that.

David

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

Hi --

Well, Structs are not implemented by using instance variables (well,
they are, but not the way you'd expect).

If I were doing it, I would implement Structs so that there was a
one-to-one correspondence between members and instance variables.
Then this wouldn't be an issue.

What if you wanted to add methods to the class, or one or more
instances, that used instance variables in a non-member/attr-like way?
It seems arbitrary to decide that Structs can't or shouldn't do that.

Granted, but that's the opposite problem from the one I
have fought. If I understand you.

I didn't really mean one-to-one necessarily.

But what I have wished for is the ability to add methods that
referenced the members as normal instance vars (or attributes).

For example, if you have a member named "alpha" you access it
from the outside just like any accessor. That leads you (me)
to believe that it corresponds to an instance var @alpha (as if
we had said attr_accessor :alpha). But it doesn't.

Some people (read: me) have incorrectly assumed that Struct is
"shorthand squared" for defining a class, an initialize, and
a bunch of accessors. But the behavior is different.

Clear? Yeah, I know, there is still some point on which you
disagree. :wink:

Hal

···

On Thu, 25 Aug 2005, Hal Fulton wrote:

That's certainly what I hoped was the case for both Struct and OpenStruct.
Thanks for setting me straight that my assumption was wrong.
Unfortunately I think this means I'll be using those less than I had
anticipated.

···

On 8/25/05, Hal Fulton <hal9000@hypermetrics.com> wrote:

Some people (read: me) have incorrectly assumed that Struct is
"shorthand squared" for defining a class, an initialize, and
a bunch of accessors. But the behavior is different.

--
R. Mark Volkmann
Partner, Object Computing, Inc.

Hi --

David A. Black wrote:

Hi --

Well, Structs are not implemented by using instance variables (well,
they are, but not the way you'd expect).

If I were doing it, I would implement Structs so that there was a
one-to-one correspondence between members and instance variables.
Then this wouldn't be an issue.

What if you wanted to add methods to the class, or one or more
instances, that used instance variables in a non-member/attr-like way?
It seems arbitrary to decide that Structs can't or shouldn't do that.

Granted, but that's the opposite problem from the one I
have fought. If I understand you.

I didn't really mean one-to-one necessarily.

But what I have wished for is the ability to add methods that
referenced the members as normal instance vars (or attributes).

For example, if you have a member named "alpha" you access it
from the outside just like any accessor. That leads you (me)
to believe that it corresponds to an instance var @alpha (as if
we had said attr_accessor :alpha). But it doesn't.

Some people (read: me) have incorrectly assumed that Struct is
"shorthand squared" for defining a class, an initialize, and
a bunch of accessors. But the behavior is different.

Clear? Yeah, I know, there is still some point on which you
disagree. :wink:

I'm just not sure where you would experience a need for that. What
would that enable you to do that you can't do now? I'm thinking you
could always use self.member = x instead of @member = x, in other
methods, which is arguably a good idea anyway.

Or are there other differences I'm not taking into account (between
members and attr_*-style attributes)?

David

···

On Thu, 25 Aug 2005, Hal Fulton wrote:

On Thu, 25 Aug 2005, Hal Fulton wrote:

--
David A. Black
dblack@wobblini.net

I think you're correct; I think the problem is simply one of consistency.

I expected #puts and #print to output their code inline in an ERB template, but (until I hacked the source) they didn't. There were at least two other ways to achieve the same effect, but it causes a context switch when I'm merrily coding along and have to say "Oh, shit, I forgot, I'm inside __this__ case...I need to write my code a little differently."

I feel the same way with Struct...it would be convenient to be able to write:

Person = Struct.new( :first, :last )
class Person
     def fullname
         "#@first #@last"
     end
end

because that's what I (and many others) expected the implementation detail of Struct-created classes to be. Certainly, it's just as easy to write:

Person = Struct.new( :first, :last )
class Person
     def fullname
         "#{first} #{last}"
     end
end

And as you say, it is arguably a good idea to use internal methods of the class to minimize coupling between methods. (Am I correct in assuming that this may result in a non-trivial performance hit, however, invoking methods versus using instance-variable lookup?) It's just a 'special case' from what appears to be the mental model of many people.

···

On Aug 25, 2005, at 8:45 AM, David A. Black wrote:

Some people (read: me) have incorrectly assumed that Struct is
"shorthand squared" for defining a class, an initialize, and
a bunch of accessors. But the behavior is different.

I'm just not sure where you would experience a need for that. What
would that enable you to do that you can't do now? I'm thinking you
could always use self.member = x instead of @member = x, in other
methods, which is arguably a good idea anyway.

Okay, I'll revise my statement. :wink:

If I create a Struct, I can easily add any methods I want to it
because it has generated a new class for me. However, it doesn't seem
that I can do the same with OpenStruct. The class of an object created
with OpenStruct is OpenStruct, not some newly generated class. I wish
OpenStruct were exactly like Struct with the exception of allowing
"attributes" to be added dynamically.

···

On 8/25/05, David A. Black <dblack@wobblini.net> wrote:

Hi --

On Thu, 25 Aug 2005, Hal Fulton wrote:

> David A. Black wrote:
>> Hi --
>>
>> On Thu, 25 Aug 2005, Hal Fulton wrote:
>>
>>>
>>> Well, Structs are not implemented by using instance variables (well,
>>> they are, but not the way you'd expect).
>>>
>>> If I were doing it, I would implement Structs so that there was a
>>> one-to-one correspondence between members and instance variables.
>>> Then this wouldn't be an issue.
>>
>>
>> What if you wanted to add methods to the class, or one or more
>> instances, that used instance variables in a non-member/attr-like way?
>> It seems arbitrary to decide that Structs can't or shouldn't do that.
>>
>
> Granted, but that's the opposite problem from the one I
> have fought. If I understand you.
>
> I didn't really mean one-to-one necessarily.
>
> But what I have wished for is the ability to add methods that
> referenced the members as normal instance vars (or attributes).
>
> For example, if you have a member named "alpha" you access it
> from the outside just like any accessor. That leads you (me)
> to believe that it corresponds to an instance var @alpha (as if
> we had said attr_accessor :alpha). But it doesn't.
>
> Some people (read: me) have incorrectly assumed that Struct is
> "shorthand squared" for defining a class, an initialize, and
> a bunch of accessors. But the behavior is different.
>
> Clear? Yeah, I know, there is still some point on which you
> disagree. :wink:

I'm just not sure where you would experience a need for that. What
would that enable you to do that you can't do now? I'm thinking you
could always use self.member = x instead of @member = x, in other
methods, which is arguably a good idea anyway.

Or are there other differences I'm not taking into account (between
members and attr_*-style attributes)?

--
R. Mark Volkmann
Partner, Object Computing, Inc.