How to test for existence of instance variable?

I don’t think this is a good idea, since d isn’t recognized as a member:

irb(main):001:0> mystruct = Struct.new(“Mystruct”,“a”,“b”,“c”)
=> Struct::Mystruct
irb(main):002:0> obj = mystruct.new
=> #<Struct::Mystruct a=nil, b=nil, c=nil>
irb(main):003:0> mystruct.instance_eval { attr_accessor :d }
=> nil
irb(main):004:0> obj.members
=> [“a”, “b”, “c”]

It would be better, I think, to inherit from Struct and write a new
method to dynamically add a member. You can then define members() in
the derived class to include “d” as a member, and you can add a new
method to easily lookup whether a given member is already defined.

Paul

···

On Thu, Feb 20, 2003 at 12:02:21AM +0900, Brian Candler wrote:

#!/usr/local/bin/ruby -w
mystruct = Struct.new(“Mystruct”,“a”,“b”,“c”)
obj = mystruct.new

mystruct.instance_eval { attr_accessor :d } # add a new member

This is only a problem for dynamically-added attributes, since
attributes that are known when the object is created can (and should) be
initialized to nil. To dynamically create an attribute, I need more
that just a simple assignment anyway, so this trick doesn’t work for
dynamic attributes.

Paul

···

On Wed, Feb 19, 2003 at 05:08:19PM +0900, Yukihiro Matsumoto wrote:

I thought it is needed just because

@foo ||=

trick cannot be done for attributes without causing warning.

#!/usr/local/bin/ruby -w
mystruct = Struct.new(“Mystruct”,“a”,“b”,“c”)
obj = mystruct.new

mystruct.instance_eval { attr_accessor :d } # add a new member

I don’t think this is a good idea, since d isn’t recognized as a member:

irb(main):001:0> mystruct = Struct.new(“Mystruct”,“a”,“b”,“c”)
=> Struct::Mystruct
irb(main):002:0> obj = mystruct.new
=> #<Struct::Mystruct a=nil, b=nil, c=nil>
irb(main):003:0> mystruct.instance_eval { attr_accessor :d }
=> nil
irb(main):004:0> obj.members
=> [“a”, “b”, “c”]

Yeah, not sure entirely about that, because even the instance variable is
invisible to ‘inspect’:

irb(main):006:0> obj.d=“foo”
“foo”
irb(main):008:0> obj
#<Struct::Mystruct a=nil, b=nil, c=nil> # where’s d?

But it does work.

It would be better, I think, to inherit from Struct and write a new
method to dynamically add a member. You can then define members() in
the derived class to include “d” as a member, and you can add a new
method to easily lookup whether a given member is already defined.

I want a general method to add a member to the class dynamically, so if
there were
Struct#add_member
I would happily use it.

I don’t see what you mean about subclassing though. Creating SuperStruct as
a subclass of Struct would mean that it had two sets of members (the members
created for the initial Struct and then the members I added later) which
would be horrible - better just to rewrite Struct from scratch, which I
don’t fancy. OTOH, if I wanted to learn the internals of Struct I could add
a new method ‘add_member’ without subclassing it at all.

Subclassing instances of Struct is not what I want either, since it’s not
possible to change existing objects from type A to type B (even if B is a
subclass of A) after they have been created.

Regards,

Brian.

···

On Thu, Feb 20, 2003 at 12:26:57AM +0900, Paul Brannan wrote:

On Thu, Feb 20, 2003 at 12:02:21AM +0900, Brian Candler wrote:

> This is only a problem for dynamically-added attributes, since > attributes that are known when the object is created can (and should) be > initialized to nil.

i disagree with this, i would never do this in C

struct
{
int x;
}
s;

bzero (&s, sizeof (s));

s.x = 0; /* redundant! */

just as i would never in ruby do

class S
attr_accessor :x

def initialize
  @x = nil	  # redundant
end

end

s = S.new

since ruby does this for me and it simply clutters the source file IMHO.

-a

···

On Thu, 20 Feb 2003, Paul Brannan wrote:

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================

Hi,

···

In message “Re: How to test for existence of instance variable?” on 03/02/20, Paul Brannan pbrannan@atdesk.com writes:

@foo ||=

trick cannot be done for attributes without causing warning.

This is only a problem for dynamically-added attributes, since
attributes that are known when the object is created can (and should) be
initialized to nil. To dynamically create an attribute, I need more
that just a simple assignment anyway, so this trick doesn’t work for
dynamic attributes.

Could you describe “more” in “I need more”? Something like
AttrWithDefault in [ruby-talk:65182]?

						matz.

Hi,

···

In message “Re: How to test for existence of instance variable?” on 03/02/20, Brian Candler B.Candler@pobox.com writes:

I want a general method to add a member to the class dynamically, so if
there were
Struct#add_member
I would happily use it.

Ah, probably you have misunderstood Ruby’s Struct. It is a fixed
array with symbolic index. Members should not be added dynamically.
Use Objects and attributes instead for dynamic slots.

						matz.

i disagree with this, i would never do this in C

struct
{
int x;
}
s;

bzero (&s, sizeof (s));

s.x = 0; /* redundant! */

This isn’t what I intended to mean. The bzero call is unnecessary,
since x is properly initialized on the following line. What would be a
problem is this:

struct { int x; } s;
printf(“%d\n”, s.x);

because you are using a value that may not be initialized (if s has
static storage duration, then x will be initialized to 0, but it’s not
necessarily a good idea to depend on this behavior).

just as i would never in ruby do

class S
attr_accessor :x

def initialize
  @x = nil	  # redundant
end

end

s = S.new

since ruby does this for me and it simply clutters the source file IMHO.

I see no clutter here. It is clear here that @x is being initialized to
nil, whereas if you leave out the initialization of @x, then it is not
immediately obvious that you intended for @x to have the value nil.

Paul

···

On Thu, Feb 20, 2003 at 01:11:37AM +0900, ahoward wrote:

To add an attribute dynamically, one must:

  1. Check to see if the attribute already exists
  2. Create the attribute (Brian did this with instance_eval and
    attr_accessor)
  3. Set the attribute to some value (the default value is nil, but
    depending on this value is not a good idea)

Using ||= alone is sufficient for (1) and (3), but not for (2).

Paul

···

On Thu, Feb 20, 2003 at 01:23:36AM +0900, Yukihiro Matsumoto wrote:

This is only a problem for dynamically-added attributes, since
attributes that are known when the object is created can (and should) be
initialized to nil. To dynamically create an attribute, I need more
that just a simple assignment anyway, so this trick doesn’t work for
dynamic attributes.

Could you describe “more” in “I need more”? Something like
AttrWithDefault in [ruby-talk:65182]?

OK, that's good enough for me. I had assumed that
Struct.new("Foo","a","b","c") was more or less the same as

  class Struct
    class Foo
      attr_accessor :a,:b,:c
    end
  end
    
So more general question, what is the recommended way to generate a class
with a dynamic name? I really want to avoid the string version of eval:

   klassname="Foo"
   eval "class #{klassname} ... "

because this seems like a last resort :slight_smile:

Just as background: I am generating classes which represent rows in a table;
when table X is read in, the accessors are created automatically based on
the column names. I can then read in different tables, and I get a fresh
class for the rows of each one, all with the right attributes.

This is convenient:

   a = Table.new(dbh,'select * from foo','id') # id = primary key field
   puts a[17].name

A Struct is fine here: @klass = Struct.new("Foo","id","name","address"...)
is generated automatically, and each row read in is generates a new object
of this class.

But then I want to add additional information when postprocessing the rows;
for example add a new attribute called 'children' which is a hash of objrefs
to rows in another table. That's what these dynamically-added attr_accessors
are for.

If Struct is not the right thing for this case, then maybe I would be
better storing each row as an object consisting of:
       * array [of values]
       * objref [to object which describes the column names]
and then using method_missing to select a column? I doubt it would be as
efficient as Struct though.

Regards,

Brian.

···

On Thu, Feb 20, 2003 at 01:26:42AM +0900, Yukihiro Matsumoto wrote:

>I want a general method to add a member to the class dynamically, so if
>there were
> Struct#add_member
>I would happily use it.

Ah, probably you have misunderstood Ruby's Struct. It is a fixed
array with symbolic index. Members should *not* be added dynamically.
Use Objects and attributes instead for dynamic slots.

This isn’t what I intended to mean. The bzero call is unnecessary,
since x is properly initialized on the following line.

i meant that the ‘s.x = 0;’ statement was unnecessary! :wink: considering ruby
does the equivalent of

bzero (&s, sizeof (s));

automatically in your stead. eg. everything starts out as ‘nil’.

I see no clutter here.

def initialize
@a = nil
@b = nil
@c = nil
@d = nil
@e = nil
@f = nil
@g = nil

@w = nil
@x = nil
@y = nil
@z = nil
end

begins to look cluttered.

i would much rather see only those attributes with values OTHER than nil in
the ctor, since it is KNOWN that all other values will have the value of nil
and assigning nil to them is redundant, if not clear.

It is clear here that @x is being initialized to nil, whereas if you leave
out the initialization of @x, then it is not immediately obvious that you
intended for @x to have the value nil.

true. but appropriate warning are already issued if you missuse (try to call
a method) on an instance variable with nil value at runtime. this seems to be
the appropriate behaviour for an interpreted language, though i will concede
you point for compiled ones. what you suggest does not jive with my notion
of autovivification and seems little short of requirng a declaration. after
all, requiring one to say

def initialize
@var = nil
end

to prevent warnings is exactly equivalent to requiring

void *var = NULL;

in order to use ‘var’ without warning.

-a

···

On Thu, 20 Feb 2003, Paul Brannan wrote:

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================

Hi,

To add an attribute dynamically, one must:

  1. Set the attribute to some value (the default value is nil, but
    depending on this value is not a good idea)

It seems one thing if you think the intent of the code is more
clearly expressed having redundant @var = nil expressions in the
object initializer; but, saying we’d be wrong somehow to depend on
Ruby guaranteeing variables’ default value is nil? Why shouldn’t
this be a behavior that’s reasonable to depend on? Is it going to
change in the future?

Assuming variable contents defaulting to nil is guaranteed by the
language, not being willing to depend on it seems a little like
suggesting a #release method be added to Object, so we can
explicitly free all our instances when we’re through with them,
'cause we can’t depend on the garbage collector doing it for us.

In other words, somewhat obliquely, I don’t think all “best
practices” in ‘C’ necessarily translate to Ruby… Ruby does a lot
more for us (the programmers.)

Just a thought…

Regards,

Bill

···

From: “Paul Brannan” pbrannan@atdesk.com

Hi,

So more general question, what is the recommended way to generate a class
with a dynamic name? I really want to avoid the string version of eval:

klassname=“Foo”
eval "class #{klassname} … "

Foo = Class.new(super) {
def foo

end

}

						matz.

p.s.
Hey, we need no English, just Ruby to talk with.

···

In message “Re: How to test for existence of instance variable?” on 03/02/20, Brian Candler B.Candler@pobox.com writes:

This is not true. Everything starts out as not being there at all:

class Foo
def initialize
p @x #=> nil
p instance_variables() #=>
p defined?(@x) #=> nil

  @x = nil
  p @x                   #=> nil
  p instance_variables() #=> ["@x"]
  p defined?(@x)         #=> "instance-variable"
end

end

f = Foo.new

Ruby is not initializing @x to nil here; instead, it is giving you nil
when you try to use an instance variable that doesn’t exist. Depending
on this behavior is bad style and may lead to very subtle bugs.

Paul

···

On Thu, Feb 20, 2003 at 02:52:14AM +0900, ahoward wrote:

i meant that the ‘s.x = 0;’ statement was unnecessary! :wink: considering ruby
does the equivalent of

bzero (&s, sizeof (s));

automatically in your stead. eg. everything starts out as ‘nil’.

Brian Candler B.Candler@pobox.com writes:

···

On Thu, Feb 20, 2003 at 01:26:42AM +0900, Yukihiro Matsumoto wrote:

I want a general method to add a member to the class dynamically, so if
there were
Struct#add_member
I would happily use it.
klassname=“Foo”
eval "class #{klassname} … "

because this seems like a last resort :slight_smile:

I wouldn’t be averse to using the string version of eval for this. By
creating the class beforehand you can minimize the time spent in it
and thereby make the code easier to understand.

class = Class.new
class_name = "Foo"
eval("#{class_name} = class")


matt

Ruby can’t set instance variables to nil by default, can it? It
doesn’t know about them until it trips over them (i.e. there’s no
instance variable declaration), and the attr_accessor trick couldn’t
do it because it operates at a class level.

May be wrong…

Gavin

···

On Thursday, February 20, 2003, 6:17:28 AM, Bill wrote:

  1. Set the attribute to some value (the default value is nil, but
    depending on this value is not a good idea)

It seems one thing if you think the intent of the code is more
clearly expressed having redundant @var = nil expressions in the
object initializer; but, saying we’d be wrong somehow to depend on
Ruby guaranteeing variables’ default value is nil? Why shouldn’t
this be a behavior that’s reasonable to depend on? Is it going to
change in the future?

>So more general question, what is the recommended way to generate a class
>with a dynamic name? I really want to avoid the string version of eval:
>
> klassname="Foo"
> eval "class #{klassname} ... "

  Foo = Class.new(super) {
     def foo
       ...
     end
     ...
  }

But then its name is fixed in the code as 'Foo'? What if the name I want to
give to the class is in the string object 'klassname'? (Actually probably
not important, as I'd be better to create an anonymous class and hold onto a
reference to it rather than use it by name, but I'd still like to know :slight_smile:

Is the above example for Ruby 1.8+? I can't get it to work under 1.6.8, and
the Pickaxe doesn't say anything about Class.new taking a block argument:

irb(main):001:0> k = Class.new(Object) {
irb(main):002:1* def foo
irb(main):003:2> puts "hello"
irb(main):004:2> end
irb(main):005:1> }
=> #<Class 0lx81652fc>
irb(main):006:0> obj = k.new
=> #<#<Class 0lx81652fc>:0x81631b4>
irb(main):007:0> obj.foo
NameError: undefined method `foo' for #<#<Class 0lx81652fc>:0x81631b4>
        from (irb):7

The best I can manage is:

  k = Class.new(Object)
  k.module_eval {
    def foo
      puts "hello"
    end
  }

Hey, we need no English, just Ruby to talk with.

The sign of an expressive language :slight_smile:

Regards,

Brian.

···

On Thu, Feb 20, 2003 at 02:25:30AM +0900, Yukihiro Matsumoto wrote:

ahhh. you are correct there. i still maintain, however, that requiring
forward intialization on instance variables, due to ruby’s dual
delclare/define syntax, is more than requiring initialization (lhs expr), but
is also requiring forward declaration/definition. why not simply make

attr_xxx :foo

initialize @foo to nil? or is that what you were suggesting?

-a

···

On Thu, 20 Feb 2003, Paul Brannan wrote:

On Thu, Feb 20, 2003 at 02:52:14AM +0900, ahoward wrote:

i meant that the ‘s.x = 0;’ statement was unnecessary! :wink: considering ruby
does the equivalent of

bzero (&s, sizeof (s));

automatically in your stead. eg. everything starts out as ‘nil’.

This is not true. Everything starts out as not being there at all:

class Foo
def initialize
p @x #=> nil
p instance_variables() #=>
p defined?(@x) #=> nil

  @x = nil
  p @x                   #=> nil
  p instance_variables() #=> ["@x"]
  p defined?(@x)         #=> "instance-variable"
end

end

f = Foo.new

Ruby is not initializing @x to nil here; instead, it is giving you nil
when you try to use an instance variable that doesn’t exist. Depending
on this behavior is bad style and may lead to very subtle bugs.

Ara Howard
NOAA Forecast Systems Laboratory
Information and Technology Services
Data Systems Group
R/FST 325 Broadway
Boulder, CO 80305-3328
Email: ahoward@fsl.noaa.gov
Phone: 303-497-7238
Fax: 303-497-7259
====================================

That's neat, thank you. Some more stuff falls into place :slight_smile:

I can see the futility of choosing the names of constants dynamically! Much
better to stick all my newly-created classes into a hash and reference them
from that.

Thanks again,

Brian.

···

On Thu, Feb 20, 2003 at 06:52:40AM +0900, Matt Armstrong wrote:

I wouldn't be averse to using the string version of eval for this. By
creating the class beforehand you can minimize the time spent in it
and thereby make the code easier to understand.

    class = Class.new
    class_name = "Foo"
    eval("#{class_name} = class")

You must concede that Guy Decoux had the idea first (or was the first
one to really implement it :slight_smile:

Now, how do I say that in Ruby?

idea = ideas[‘Ruby to communicate’]
idea.inventor?(‘Guy Decoux’)
=> true

···

On Thu, Feb 20, 2003 at 02:25:30AM +0900, Yukihiro Matsumoto wrote:

So more general question, what is the recommended way to generate a class
with a dynamic name? I really want to avoid the string version of eval:

klassname=“Foo”
eval "class #{klassname} … "

Foo = Class.new(super) {
def foo

end

}

  					matz.

p.s.
Hey, we need no English, just Ruby to talk with.


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

And Bruce is effectively building BruceIX
– Alan Cox

Hi again,

Everything starts out as not being there at all:

class Foo
def initialize
p @x #=> nil
p instance_variables() #=>
p defined?(@x) #=> nil

  @x = nil
  p @x                   #=> nil
  p instance_variables() #=> ["@x"]
  p defined?(@x)         #=> "instance-variable"
end

end

f = Foo.new

Ruby is not initializing @x to nil here; instead, it is giving you nil
when you try to use an instance variable that doesn’t exist. Depending
on this behavior is bad style and may lead to very subtle bugs.

As someone who is generally fanatical about getting better at
writing programs with next-to-zero bugs in them, I’m still unclear
as to why depending on the behavior of uninitialized variables
defaulting to nil might lead to very subtle bugs.

What you’ve written above with instance variables seems so analagous
to me with:

h = {} => {}
p h[‘x’] => nil
h.keys =>
p h.has_key? ‘x’ => false

h[‘x’] = nil => nil
p h[‘x’] => nil
h.keys => [“x”]
p h.has_key? ‘x’ => true

I’m not accustomed to viewing reliance on default values for non-
existent hash keys with trepidation… So I’m wondering if you have
any specific 'gotcha’s in mind with instance variables.

(I admit i’m playing a bit 'o the Devils Advocate here… since in
actuality I always run with ruby -w … :slight_smile:

Thanks,

Bill

···

From: “Paul Brannan” pbrannan@atdesk.com