Interesting Ruby anomaly

Hello, all...

I ran across an interesting bit of behavior, and I'm not sure I
understand why it happens.

Here's the background. I have a SuperStruct class which I use frequently
(though I hope to find a better name for it). See the snippet on
rubyforge: http://rubyforge.org/snippet/detail.php?type=snippet&id=25

So. If you call SuperStruct.new, you get a class that is much like
a Struct; if you call SuperStruct.open instead, you get a class that
is more like an OpenStruct.

That is, in the latter case, if you reference a nonexistent attribute,
it will spring into existence:

   klass = SuperStruct.open(:alpha) # Create with attr "alpha"
   foo = klass.new
   x = foo.beta # nil
   foo.gamma = 5 # 5

In fact, when you referenced the getter OR the setter... then the getter
AND the setter would be defined. Make sense so far?

But this leads to an oddity...

   foo.delta ||= 7 # gives an error!
   foo.delta = foo.delta || 7 # I think this also gives an error

I had to fix this by saying: When the getter or setter is referenced,
define ONLY that method. I don't quite like this; but oh, well.

But puzzling out why it works this way has given me a headache.

What do you think?

Hal

Hal Fulton wrote:

Hello, all...

I ran across an interesting bit of behavior, and I'm not sure I
understand why it happens.

Here's the background. I have a SuperStruct class which I use frequently
(though I hope to find a better name for it).

As far as naming goes, have you considered:

MegaStruct
UltraStruct
EvenBetterStruct
StructThatIsLikePlainOldStructButAlsoLikeOpenStruct

Hope this helps.

James

:slight_smile:

Hi,

At Thu, 12 Aug 2004 12:49:50 +0900,
Hal Fulton wrote in [ruby-talk:108944]:

But this leads to an oddity...

   foo.delta ||= 7 # gives an error!
   foo.delta = foo.delta || 7 # I think this also gives an error

`len' is length of `args' to messod_missing at first, not
setter's. And I guess defined setter should fail if any
arguments given.

--- /tmp/nobu/superstruct-orig.rb 2004-08-12 15:19:33.000000000 +0900
+++ /tmp/nobu/superstruct.rb 2004-08-12 15:21:38.000000000 +0900
@@ -131,7 +131,7 @@ class SuperStruct
         setsyms << setter
         table << getter
- len = args.length
         klass.class_eval do
           define_method(setter) do |*args|
+ len = args.length
             if len != 1
               raise ArgumentError, "Wrong # of arguments (#{len} for 1)",
@@ -141,5 +141,5 @@ class SuperStruct
             instance_variable_get(ivar)
           end
- define_method(getter) do
+ define_method(getter) do ||
             instance_variable_get(ivar)
           end
@@ -148,10 +148,5 @@ class SuperStruct
           self.send(setter,*args)
         else
- if len == 0
- self.send(getter)
- else
- raise NoMethodError, "Undefined method '#{mname}' for #{self}",
- caller(1)
- end
+ self.send(getter,*args)
         end
       end

···

--
Nobu Nakada

"Hal Fulton" <hal9000@hypermetrics.com> schrieb im Newsbeitrag
news:411AE8D6.8060607@hypermetrics.com...

Hello, all...

I ran across an interesting bit of behavior, and I'm not sure I
understand why it happens.

Here's the background. I have a SuperStruct class which I use frequently
(though I hope to find a better name for it). See the snippet on
rubyforge: http://rubyforge.org/snippet/detail.php?type=snippet&id=25

So. If you call SuperStruct.new, you get a class that is much like
a Struct; if you call SuperStruct.open instead, you get a class that
is more like an OpenStruct.

That is, in the latter case, if you reference a nonexistent attribute,
it will spring into existence:

   klass = SuperStruct.open(:alpha) # Create with attr "alpha"
   foo = klass.new
   x = foo.beta # nil
   foo.gamma = 5 # 5

In fact, when you referenced the getter OR the setter... then the getter
AND the setter would be defined. Make sense so far?

But this leads to an oddity...

   foo.delta ||= 7 # gives an error!
   foo.delta = foo.delta || 7 # I think this also gives an error

I had to fix this by saying: When the getter or setter is referenced,
define ONLY that method. I don't quite like this; but oh, well.

But puzzling out why it works this way has given me a headache.

What do you think?

I think it doesn't happen with OpenStruct:

foo = OpenStruct.new

=> <OpenStruct>

foo.alpha = nil

=> nil

foo

=> <OpenStruct alpha=nil>

foo.delta ||= 7

=> 7

foo

=> <OpenStruct delta=7 alpha=nil>

Personally I'd implement SuperStruct like this:

require 'ostruct'
class SuperStruct
  def self.new(*attrs)
    Struct.new( *attrs ).new
  end

  def self.open(*attrs)
    st = OpenStruct.new
    attrs.each {|at| st.send( "#{at}=", nil) }
    st
  end
end

x = SuperStruct.new :foo

=> #<struct #<Class:0x10187710> foo=nil>

y = SuperStruct.open :foo

=> <OpenStruct foo=nil>

But apparently you're adding more magic, so that's probably not a solution
for you.

Kind regards

    robert

How bout UberStruct? (JK)

···

On Thu, 12 Aug 2004 13:45:43 +0900, James Britt <jamesunderbarb@neurogami.com> wrote:

Hal Fulton wrote:
> Hello, all...
>
> I ran across an interesting bit of behavior, and I'm not sure I
> understand why it happens.
>
> Here's the background. I have a SuperStruct class which I use frequently
> (though I hope to find a better name for it).

As far as naming goes, have you considered:

MegaStruct
UltraStruct
EvenBetterStruct
StructThatIsLikePlainOldStructButAlsoLikeOpenStruct

Hope this helps.

James

:slight_smile:

James Britt wrote:

As far as naming goes, have you considered:

MegaStruct
UltraStruct
EvenBetterStruct
StructThatIsLikePlainOldStructButAlsoLikeOpenStruct

Hope this helps.

Har har... yeah, I've also thought of

   StarStruct
   SelfdeStruct
   StructOil
   StructOut

:slight_smile:

Hal

"Robert Klemme" <bob.news@gmx.net> schrieb im Newsbeitrag
news:2o0ke5F5jbk9U1@uni-berlin.de...

> What do you think?

I think it doesn't happen with OpenStruct:

>> foo = OpenStruct.new
=> <OpenStruct>
>> foo.alpha = nil
=> nil
>> foo
=> <OpenStruct alpha=nil>
>> foo.delta ||= 7
=> 7
>> foo
=> <OpenStruct delta=7 alpha=nil>
>>

Personally I'd implement SuperStruct like this:

Forget that statement: I didn't see your comments, so your SuperStruct is
quite different from what my suggestion would yield.

Kind regards

    robert

Of course! That is so clear now.

Thank you.

Hal

···

nobu.nokada@softhome.net wrote:

`len' is length of `args' to messod_missing at first, not
setter's. And I guess defined setter should fail if any
arguments given.

Robert Klemme wrote:

Personally I'd implement SuperStruct like this:

[snip]

But apparently you're adding more magic, so that's probably not a solution
for you.

Actually, it might. The code does need simplifying.
I sometimes do things the hard way.

Hal

ObStruct
ConStruct
DeStruct
DeconStruct
AbStruct
HasTrucked
MissTrucked

:-p

···

On Thu, 12 Aug 2004 14:01:59 +0900 Hal Fulton <hal9000@hypermetrics.com> wrote:

James Britt wrote:
> As far as naming goes, have you considered:
>
> MegaStruct
> UltraStruct
> EvenBetterStruct
> StructThatIsLikePlainOldStructButAlsoLikeOpenStruct
>
> Hope this helps.

Har har... yeah, I've also thought of

   StarStruct
   SelfdeStruct
   StructOil
   StructOut

:slight_smile:

--
Anders K. Madsen --- http://lillesvin.linux.dk

"There are 10 types of people in the world.
Those who understand binary - and those who don't."

AbStruct
HasTrucked
MissTrucked

grep -i struct /usr/share/dict/words

beat this :slight_smile:

> AbStruct
> HasTrucked
> MissTrucked

grep -i struct /usr/share/dict/words

That wouldn't give you anything with "truck" and "abstruct"/"abstract"
wouldn't turn up either...

beat this :slight_smile:

Why would I? I never thought this was a competition...

I'm very impressed that you can use grep and the case-insensitive switch
to search in an ASCII-file, but I fail to see where the humour comes
in... Sorry. :-\

  Madsen

···

On Thu, 12 Aug 2004 19:06:27 +0900 Jani Monoses <jani@iv.ro> wrote:

--
Anders K. Madsen --- http://lillesvin.linux.dk

"There are 10 types of people in the world.
Those who understand binary - and those who don't."

Anders K. Madsen wrote:

AbStruct
HasTrucked
MissTrucked

grep -i struct /usr/share/dict/words

That wouldn't give you anything with "truck" and "abstruct"/"abstract"
wouldn't turn up either...

beat this :slight_smile:

Why would I? I never thought this was a competition...

I'm very impressed that you can use grep and the case-insensitive switch
to search in an ASCII-file, but I fail to see where the humour comes
in... Sorry. :-\

I'm pretty sure that "beat this" was a facetious, not serious, challenge.

But, as this branch of the thread careens into total foolishness, I would award more game [0] points for names that manage to avoid any direct reference to the literal string 'struct', yet still convey some twisted spin on the original name.

James

[0] The game being, "Give Hal far more alternative names than he would ever want to even remotely consider."

Maybe Ruby could use a Facetious module, so that one could write code using :), :-O, and so on, and the interpreter would know to not *really* execute the line. Just "sort of" execute it.

# But in the meantime ...

%w< :slight_smile: :confused: :} >.each { |grin| puts(grin) }

···

On Thu, 12 Aug 2004 19:06:27 +0900 > Jani Monoses <jani@iv.ro> wrote:

James Britt wrote:

Maybe Ruby could use a Facetious module, so that one could write code using :), :-O, and so on, and the interpreter would know to not *really* execute the line. Just "sort of" execute it.

That makes more sense than some of the RCRs I have seen.

Hal