Problem assigning an Array object to an Array-subclass object

[ I apologize if this is a second post. My earlier one seems to have gotten
lost in the ethernet :slight_smile: ]

notes =<<NOTES
I didn’t like to_s’ output for an Array of strings.
Array#to_s simply concatenated them
or inserted a comma separator.
So I wrote my own.
But as the last line indicates, I failed.

Apparently, array assignment to myA1
changed the reference from a MyArrayType object
to an Array object.

Two questions:
1.  How can I set myA1 to an array value
    and preserve it's type?
2.  Isn't there a "Ruby way" to set the separator
(I thought there was some special symbol a la Perl
but I couldn't find any in Thomas' or Fulton's
books.)

NOTES

class MyArrayType < Array
def to_s
print "Starting MyArrayType#to_s"
s = ""
s.each { |x| s += "; " if s.length>0; s += x.to_s }
s
end
end

myA1 = MyArrayType.new
myA1 = %w[x1, y1]
puts myA1.to_s # x1,y1 … expected x1; x2 … MyArrayType#to_s not
invoked

···

Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.659 / Virus Database: 423 - Release Date: 4/17/2004

puts myA1.to_s # x1,y1 … expected x1; x2 … MyArrayType#to_s not

should read:

puts myA1.to_s # x1,y1 … expected x1; y1 … MyArrayType#to_s not
reached

···

Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/21/2004

Richard,

myA1 = MyArrayType.new
myA1 = %w[x1, y1]

Your problem is that you assign myA1 the object (MyArrayType.new),

then you assign myA1 the object (%w[x1, y1]). This is similar to
saying:

x = 2
x = 5

Also note that (%w[x1, y1]) is equivalent to (["x1,", "y1"]), which

is why you thought you were getting a comma separator.

  1. How can I set myA1 to an array value
    and preserve it’s type?
You would need to either use one of the self-modifying functions of

array (e.g. Array#replace), or add similar functionality to your
MyArrayType class.

  1. Isn’t there a “Ruby way” to set the separator
Well, Array#to_s simply calls Array#join, and Array#join accepts a

string separator that defaults to the variable $, (dollar comma). So
you can either set $, to whatever you want, or you can simply call
Array#join yourself.

I hope this helps.

- Warren Brown

[ I apologize if this is a second post. My earlier one seems to have gotten
lost in the ethernet :slight_smile: ]

notes =<<NOTES
I didn’t like to_s’ output for an Array of strings.
Array#to_s simply concatenated them
or inserted a comma separator.
So I wrote my own.
But as the last line indicates, I failed.

Apparently, array assignment to myA1
changed the reference from a MyArrayType object
to an Array object.

Two questions:
1.  How can I set myA1 to an array value
    and preserve it's type?
2.  Isn't there a "Ruby way" to set the separator
(I thought there was some special symbol a la Perl
but I couldn't find any in Thomas' or Fulton's
books.)

NOTES

class MyArrayType < Array
def to_s
print “Starting MyArrayType#to_s”
s = “”
s.each { |x| s += "; " if s.length>0; s += x.to_s }
s
end
end

myA1 = MyArrayType.new
myA1 = %w[x1, y1]
puts myA1.to_s # x1,y1 … expected x1; x2 … MyArrayType#to_s not
invoked

try this:

class MyArrayType < Array
def to_s
join ‘;’
end
end

myA1 = MyArrayType[‘x1’, ‘y1’]
puts myA1.to_s # => x1;y1
puts myA1 # => x1\ny1

your statement:

Apparently, array assignment to myA1
changed the reference from a MyArrayType object
to an Array object.

was correct

what you did i just like

myA1 = MyArrayType.new
myA1 = ‘fubar’

so, of course, your method was not called

something else to be aware of:

  • Object#puts behaves different if passed an Array, or sub-class of Array,
    see above

in general it can be tricky to inherit from the built-ins.
-a

···

On Fri, 23 Apr 2004, Richard Lionheart wrote:

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

Hi,
if all you want to do is change the to_s method, why not
just add it to Array?

class Array
def my_to_s
join("; ")
end
end

a = %w[x1 y1]
puts a.my_to_s

#note (you could even replace the to_s method)

···

On Fri, 23 Apr 2004 11:15:16 -0400, Richard Lionheart wrote:

notes =<<NOTES
I didn’t like to_s’ output for an Array of strings.
Array#to_s simply concatenated them
or inserted a comma separator.
So I wrote my own.

class MyArrayType < Array
def to_s
print “Starting MyArrayType#to_s”
s = “”
s.each { |x| s += "; " if s.length>0; s += x.to_s }
s
end
end

myA1 = MyArrayType.new
myA1 = %w[x1, y1]
puts myA1.to_s # x1,y1 … expected x1; x2 … MyArrayType#to_s not
invoked

“Richard Lionheart” NoOne@Nowhere.com schrieb im Newsbeitrag
news:iLSdne99T7Y0rhTdRVn-jw@comcast.com

[ I apologize if this is a second post. My earlier one seems to have
gotten
lost in the ethernet :slight_smile: ]

notes =<<NOTES
I didn’t like to_s’ output for an Array of strings.
Array#to_s simply concatenated them
or inserted a comma separator.
So I wrote my own.
But as the last line indicates, I failed.

Apparently, array assignment to myA1
changed the reference from a MyArrayType object
to an Array object.

Two questions:
1.  How can I set myA1 to an array value
    and preserve it's type?
2.  Isn't there a "Ruby way" to set the separator
(I thought there was some special symbol a la Perl
but I couldn't find any in Thomas' or Fulton's
books.)

NOTES

class MyArrayType < Array
def to_s
print “Starting MyArrayType#to_s”
s = “”
s.each { |x| s += "; " if s.length>0; s += x.to_s }
s
end
end

myA1 = MyArrayType.new
myA1 = %w[x1, y1]

There seems to be a misunderstanding on your side about variables, objects
and types. Variables do not have a type, they just hold references to any
object. So your code does not declare a variable “myA1” of type
MyArrayType, it merely first assigns the result of MyArrayType.new (a new
instance of class MyArrayType) and then assigns the result of %w[x1, y1] to
myA1, loosing the reference to the MyArrayType instance.

Simply use Array#join:

irb(main):014:0> %w[x1, x2].join( '; ’ )
=> “x1,; x2”

Note: the ‘,’ is part of the first word. You probably wanted

irb(main):015:0> %w[x1 x2].join( '; ’ )
=> “x1; x2”

Regards

robert

Hi Ara,

Great answers. BTW, I had another typo in my original post, which I
corrected below. I’ve got a couple more questions, but if you don’t feel
like spending any more time on this question, please ignore this post.

  join ';'

That’s a lot better than my procedural code. Works great

myA1 = MyArrayType[‘x1’, ‘y1’]

(Q1) That worked, but where the heck did you come up with that? Is that
documented somewhere? I’ve got The Pragmatic Programmer/Thomas and The Ruby
Way/Fulton and didn’t notice that in either work (though I certainly have
not read every word of either one.)

Object#puts behaves different if passed an Array, or sub-class of Array

In my case, I think I was passing puts the the last expression executed in
the to_s method of an Array-subclass object. So I really wasn’t passing an
Array nor a sub-class of Array.
(Q2) Do you agree?

Below are several variants of code for this question.
(Q3) My last question is how can I make the MyArrayType3 invocation work?

MyArrayType1 uses my original code (absent the typo) and is invoked with an
array of explicitly quoted strings as you suggest. Works great.

MyArrayType2 uses your join expresson and is invoked with an array of
explicitly quoted strings as you suggest. Works great.

MyArrayType3 uses your join expresson but adds an initialize method so it
can be invoked with an array object argument. Fails.
(Q4) Why?

Again, thanks for your great response.

Regards,
Richard

class MyArrayType1 < Array
def to_s
s = “”
self.each { |x|
s += "; " if s.length>0
s += x.to_s
}
s
end
end

class MyArrayType2 < Array
def to_s
join '; ’
end
end

class MyArrayType3 < Array
def to_s
sOut = @s.join '; ’
end
def intialize(aIn)
@s = aIn
end
end

myA1 = MyArrayType1[‘x1’, ‘y1’]
puts myA1.to_s # x1; y1

myA2 = MyArrayType2[‘x1’, ‘y1’]
puts myA2.to_s # x1; y1

a3 = %w[x1, y1]
myA3 = MyArrayType(a3) # undefined method `MyArrayType’ for main:Object
(NoMethodError)
puts myA3.to_s

···

Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/22/2004

notes =<<NOTES
I didn’t like to_s’ output for an Array of strings.
Array#to_s simply concatenated them
or inserted a comma separator.
So I wrote my own.

class MyArrayType < Array
def to_s
print “Starting MyArrayType#to_s”
s = “”
s.each { |x| s += "; " if s.length>0; s += x.to_s }
s
end
end

myA1 = MyArrayType.new
myA1 = %w[x1, y1]
puts myA1.to_s # x1,y1 … expected x1; x2 … MyArrayType#to_s not
invoked

Hi,
if all you want to do is change the to_s method, why not
just add it to Array?

class Array
def my_to_s
join("; ")
end
end

a = %w[x1 y1]
puts a.my_to_s

Trouble is some other Array using method may expect tho old behaviour,
but you can do this on a per instance basis:

0rasputin@lb:rasputin$ ruby instancedef.rb
before override: a = foobarack, b = eenymeenymineymo
after override: a = foo:bar:ack, b = eenymeenymineymo
0rasputin@lb:rasputin$ cat instancedef.rb
a =
b =

a = %w( foo bar ack)
b = %w(eeny meeny miney mo)

puts “before override: a = #{a.to_s}, b = #{b.to_s}”

def a.to_s
self.join(‘:’)
end

puts “after override: a = #{a.to_s}, b = #{b.to_s}”
0rasputin@lb:rasputin$

···

On Fri, 23 Apr 2004 11:15:16 -0400, Richard Lionheart wrote:


Is it possible that software is not like anything else, that it is
meant to be discarded: that the whole point is to always see it as a
soap bubble?
Rasputin :: Jack of All Trades - Master of Nuns

Thanks, Kristof

class Array
def my_to_s
join("; ")
end
end

a = %w[x1 y1]
puts a.my_to_s

#note (you could even replace the to_s method)

I realize now I could just append
…join("; ").to_s
to my array and not bother with subclassing Array, etc.

Regards,
Richard

···

Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/26/2004

Hi Robert,

Thanks for your response.

There seems to be a misunderstanding on your side about variables, objects
and types. Variables do not have a type, they just hold references to any
object. So your code does not declare a variable “myA1” of type
MyArrayType, it merely first assigns the result of MyArrayType.new (a new
instance of class MyArrayType) and then assigns the result of %w[x1, y1]
to
myA1, loosing the reference to the MyArrayType instance.

Good point. I’ve got it now!

Simply use Array#join:

irb(main):014:0> %w[x1, x2].join( '; ’ )
=> “x1,; x2”

Yes, much, much better than my original idea

Note: the ‘,’ is part of the first word. You probably wanted

irb(main):015:0> %w[x1 x2].join( '; ’ )
=> “x1; x2”

Yes, that’s what I wanted and was surprised when the comma followed “x1” in
the output. So I deleted the comma and added extra spaces just to confirm
that a set of one or more spaces was interpreted as a separator in Ruby’s
notation.

Again, thanks for your help,
Richard

···

Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/26/2004

Hi Ara,

Great answers. BTW, I had another typo in my original post, which I
corrected below. I’ve got a couple more questions, but if you don’t feel
like spending any more time on this question, please ignore this post.

  join ';'

That’s a lot better than my procedural code. Works great

myA1 = MyArrayType[‘x1’, ‘y1’]

(Q1) That worked, but where the heck did you come up with that? Is that
documented somewhere? I’ve got The Pragmatic Programmer/Thomas and The Ruby
Way/Fulton and didn’t notice that in either work (though I certainly have
not read every word of either one.)

frankly, i find that book amazing. it got me into ruby and yet i still find
things in it almost weekly. to answer your question, it’s in

‘Built-in Classes and Methods’->‘Array’->‘

the html version of the book is very useful.

note that ‘’ is simply an alias for Array#new, which in turn will construct
an Array object and call #initialize on it.

Object#puts behaves different if passed an Array, or sub-class of Array

In my case, I think I was passing puts the the last expression executed in
the to_s method of an Array-subclass object. So I really wasn’t passing an
Array nor a sub-class of Array.
(Q2) Do you agree?

yes. just a warning.

Below are several variants of code for this question.
(Q3) My last question is how can I make the MyArrayType3 invocation work?

myA3 = MyArrayType(a3) # undefined method MyArrayType' for main:Object ^ ^ ^ ^ 3.new ^^^^^ ^^^^^ myA3 = MyArrayType3.new(a3) # undefined method MyArrayType’ for main:Object
^^^^^

typo? :wink:

perhaps something like this (un-tested)?

class MyArrayType < Array
def initialize(*args, &block)
if Array === args.first
ary = args.shift
super
update ary
else
super
end
end
def to_s;join '; ';end
end

again, be very careful extending/inheriting builtin classes - it’s powerful
because you get so much for free, but it can come back to bite you when you
expect it to be just like to built-ins, eg:

ma = MyArrayType[‘42’]
a = [‘forty-two’]

ma + a # => this will be an Array!

ma << 42.0 # => MyArrayType
a << 42.0 # => Array

eg. alot of the methods you inherit will not return objects of your
specialized class, but of the parent class (Array in this case). this isn’t
too much of a problem unless you expect these object to have you new methods
(to_s for instance)…

an aggregate class is often safer and less frustrating to debug…

MyArrayType1 uses my original code (absent the typo) and is invoked with an
array of explicitly quoted strings as you suggest. Works great.

MyArrayType2 uses your join expresson and is invoked with an array of
explicitly quoted strings as you suggest. Works great.

MyArrayType3 uses your join expresson but adds an initialize method so it
can be invoked with an array object argument. Fails.
(Q4) Why?

see above. code looks correct, just a typo.

Again, thanks for your great response.

no worries, it’s just karma - i’ve gotten plenty of great responses myself…

Regards,
Richard

class MyArrayType1 < Array
def to_s
s = “”
self.each { |x|
s += "; " if s.length>0
s += x.to_s
}
s
end
end

class MyArrayType2 < Array
def to_s
join '; ’
end
end

class MyArrayType3 < Array
def to_s
sOut = @s.join '; ’
end
def intialize(aIn)
@s = aIn
end
end

myA1 = MyArrayType1[‘x1’, ‘y1’]
puts myA1.to_s # x1; y1

myA2 = MyArrayType2[‘x1’, ‘y1’]
puts myA2.to_s # x1; y1

a3 = %w[x1, y1]
myA3 = MyArrayType(a3) # undefined method `MyArrayType’ for main:Object
(NoMethodError)
puts myA3.to_s

cheers.

-a

···

On Sat, 24 Apr 2004, Richard Lionheart wrote:

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

Hi Ara,

Great answers. BTW, I had another typo in my original post, which I
corrected below. I’ve got a couple more questions, but if you don’t
feel
like spending any more time on this question, please ignore this post.

  join ';'

That’s a lot better than my procedural code. Works great

myA1 = MyArrayType[‘x1’, ‘y1’]

(Q1) That worked, but where the heck did you come up with that? Is
that
documented somewhere?

Since MyArrayType inherits from Array, you get all it’s methods for
free. One of those is Array, which creates a new array from the
arguments passed. Since you call it using MyArrayType rather than
Array, it creates an instance of MyArrayType. It’s documented in
PickAxe with Array’s other class methods.

Object#puts behaves different if passed an Array, or sub-class of
Array

In my case, I think I was passing puts the the last expression
executed in
the to_s method of an Array-subclass object. So I really wasn’t
passing an
Array nor a sub-class of Array.
(Q2) Do you agree?

Correct. You were passing it a String. I think Ara was just making a
related observation about how Kernel#puts works.

Below are several variants of code for this question.
(Q3) My last question is how can I make the MyArrayType3 invocation
work?

Three reasons it won’t work properly:

  • You are calling MyArrayType3(data), rather than the appropriate
    MyArrayType3[data] (note the square brackets).

  • Your initialize method is spelled wrong

  • You aren’t calling MyArrayType3.new, which would call the initialize
    function. You are calling MyArrayType3() which is interpreted to be a
    method of Object; ie., Object#MyArrayType3()

  • You are assigning the array data to an instance variable, then
    joining it for to_s. What you have there is an empty MyArrayType
    instance with an instance variable that’s holding an array. This will
    give you wrong behavior if you do anything with that instance other
    than call to_s: other method calls will use the non-existant internal
    array data.

To make it work properly, you might do it like this:

class MyArrayType3 < Array
def initialize(ary)
self.concat! ary
end
def to_s
join "; "
end
end

···

On Apr 23, 2004, at 9:29 PM, Richard Lionheart wrote:

MyArrayType1 uses my original code (absent the typo) and is invoked
with an
array of explicitly quoted strings as you suggest. Works great.

MyArrayType2 uses your join expresson and is invoked with an array of
explicitly quoted strings as you suggest. Works great.

MyArrayType3 uses your join expresson but adds an initialize method so
it
can be invoked with an array object argument. Fails.
(Q4) Why?

Again, thanks for your great response.

Regards,
Richard

class MyArrayType1 < Array
def to_s
s = “”
self.each { |x|
s += "; " if s.length>0
s += x.to_s
}
s
end
end

class MyArrayType2 < Array
def to_s
join '; ’
end
end

class MyArrayType3 < Array
def to_s
sOut = @s.join '; ’
end
def intialize(aIn)
@s = aIn
end
end

myA1 = MyArrayType1[‘x1’, ‘y1’]
puts myA1.to_s # x1; y1

myA2 = MyArrayType2[‘x1’, ‘y1’]
puts myA2.to_s # x1; y1

a3 = %w[x1, y1]
myA3 = MyArrayType(a3) # undefined method `MyArrayType’ for
main:Object
(NoMethodError)
puts myA3.to_s


Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/22/2004

Hi Dick,

Gotcha! Applying your ideas, modified slightly I believe, I tested:

F:_Projects_Current_Projects_Ruby\P001f-Arrays#3\MyArr3.rb

a =
b =

a = %w( foo bar ack)
b = %w(eeny meeny miney mo)
puts “Before override: a = #{a.to_s}, b = #{b.to_s}”

class Array
def to_s
join("; ")
end
end

a = %w( foo bar ack)
b = %w(eeny meeny miney mo)
puts “After override: a = #{a.to_s}, b = #{b.to_s}”

####### Got results:

ruby MyArr3.rb Arg1 Arg2
Before override: a = foobarack, b = eenymeenymineymo
After override: a = foo; bar; ack, b = eeny; meeny; miney; mo

···

Exit code: 0

Neat stuff!

Thanks,
Richard


Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/26/2004

Hi Dick,

I think I’m on top of the subtleties involved with my question:

  1. I dropped the initial assignments to a and b, because no matter what
    they refer to (empty array, string, whatever), they’ll be assigned new
    references by the subsequent assignments. I confirmed this by adding a puts

  2. I initially dropped the “my_” prefix to to_s, since it looked more
    elegant (to me, at least). But when testing, I found now way to undo that
    change to Array so that unexpected results would probably obtain in extended
    use of my revised approach.

Here’s my last word on the subject:

a = %w( foo bar ack)
puts "After assignment “a = %w( foo bar ack)”, a.class.to_s =
#{a.class.to_s}"
b = %w(eeny meeny miney mo)
puts “Before override: a = #{a.to_s}, b = #{b.to_s}”

class Array # Override to_s
def my_to_s
join("; ")
end
end

puts “After override: a = #{a.my_to_s}, b = #{b.my_to_s}”

results =<<RESULTS
After assignment “a = %w( foo bar ack)”, a.class.to_s = Array
Before override: a = foobarack, b = eenymeenymineymo
After override: a = foo; bar; ack, b = eeny; meeny; miney; mo
RESULTS

Again, many thanks for your advice,
Richard

···

Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/26/2004

Hi Mark,

Okay, following your advice, I got this working perfectly:

class MyArrayType3 < Array
def to_s
join '; '
end
def initalize(aIn)
self.concat! aIn
end
end

a3 = %w[x3 y3]
myA3 = MyArrayType3[a3]
puts myA3.to_s # ==> x3; y3

In testing it, I had puts statements in both methods and found that
MyArrayType3#intialize is never called in this invocation.

That’s consistent with what you told me: MyArrayType3.new would invoke
initialize.

That begs the question: In what circumstance would MyArrayType3#intialize
be invoked.

I apologize for the several typos I had in my previous attempt(s). Thanks
for your excellent explanations. They’re much appreciated.

Regards,
Richard

P.S. I mistakenly replied to you directly rather than posting back on this
thread. Please excuse me.

···

Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/22/2004

Hi Ara,

Thanks for your additional info.

myA3 = MyArrayType3.new(a3) # undefined method `MyArrayType’ for
main:Object
^^^^^

typo? :wink:

Yes, indeed! I apologize for mixing up sloppy coding with my ignorant
coding. IMHO, the latter is exusable, but the former is not.

perhaps something like this (un-tested)?

No problem!! I’ll test it :slight_smile:

class MyArrayType < Array
def initialize(*args, &block)
if Array === args.first
ary = args.shift
super
update ary
else
super
end
end
def to_s;join '; ';end
end

a4 = %w[x4 y4]
myA4 = MyArrayType.new(a4) # ==> undefined method `update’ for [“x4”,
“y4”]:MyArrayType (NoMethodError)
puts myA4b.to_s # wasn’t reached

The Thomas/Hunt book says ‘update’ is a method in Hash and CGI::Session,
but not in Array.

again, be very careful extending/inheriting builtin classes …

Thanks. I’ve already experienced some of the ones you mentioned in the
course of this exercise, so I feel up-to-speed on the matter.

Your ‘initialize’ method did present me with a few things I have to ask you
about, particularly whether my understanding/guess is correct:

def initialize(*args, &block)

Could (must?) be invoked as MyArrayType[‘x’,‘y’]{|i| dostuff(i)}
so that block(element) could be executed
which in turn would invoke dostuff(elemement)
for selected elements in the array(s)
in args.

  if Array === args.first

My guess is that this statement is equivalent to “if ‘Array’ is the type of
the first item in the ‘args’ array.” That doesn’t comport with “Programming
Ruby”, Thomas et al, 2001, page 283, which seems to indicate “element by
element comparison of two arrays.” But I can’t see how you could intend to
compare Array’s elements, because I don’t think Array HAS any elements when
‘initialize’ is invoked.

    ary = args.shift

Equivalent to “ary = args[0]” in this instance, since ‘args’ is not modified
(no “!” after “shift”).

    super

Invokes Array#initialze with the original arguments that ‘initialize’ got,
but I don’t see what this accomplishes.

an aggregate class is often safer and less frustrating to debug…
I assume you’re talking about using a Module and including it into a class
or classes.

As before, I appreciate your tutoring.

Regards,
Richard

···

Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/22/2004

Richard Lionheart wrote:

Hi Dick,

I think I’m on top of the subtleties involved with my question:

  1. I dropped the initial assignments to a and b, because no matter what
    they refer to (empty array, string, whatever), they’ll be assigned new
    references by the subsequent assignments. I confirmed this by adding a puts

  2. I initially dropped the “my_” prefix to to_s, since it looked more
    elegant (to me, at least). But when testing, I found now way to undo that
    change to Array so that unexpected results would probably obtain in extended
    use of my revised approach.

if you want to save the old version of to_s you can use the alias method

class Array # Override to_s
alias old_to_s to_s
def to_s
join("; ")
end
end

then you can access the old to_s behaviour by using the old_to_s method.
Or if you want to change to_s back to it’s default behaviour you can use

class Array
alias to_s old_to_s
end

i.e.

a = %w( foo bar ack)
puts “After assignment "a = %w( foo bar ack)", a.class.to_s =
#{a.class.to_s}”
b = %w(eeny meeny miney mo)
puts “Before override: a = #{a.to_s}, b = #{b.to_s}”

class Array # Override to_s
alias old_to_s to_s
def to_s
join("; ")
end
end

puts “After override: a = #{a.to_s}, b = #{b.to_s}”

class Array
alias to_s old_to_s
end

puts “After re-override: a = #{a.to_s}, b = #{b.to_s}”

results=<<RESULTS
After assignment “a = %w( foo bar ack)”, a.class.to_s =
Array
Before override: a = foobarack, b = eenymeenymineymo
After override: a = foo; bar; ack, b = eeny; meeny; miney; mo
After re-override: a = foobarack, b = eenymeenymineymo
RESULTS

···


Mark Sparshatt

The Thomas/Hunt book says ‘update’ is a method in Hash and CGI::Session, but
not in Array.

sorry - i meant Array#replace

def initialize(*args, &block)

Could (must?) be invoked as MyArrayType[‘x’,‘y’]{|i| dostuff(i)} so that
block(element) could be executed which in turn would invoke
dostuff(elemement) for selected elements in the array(s) in args.

~ > cat a.rb
class A
def initialize(*args, &block)
puts ‘—’
p “args <#{ args.inspect }>”
block.call if block
end
end

A.new
A.new{ p ‘forty-two’}
A.new 42
A.new(42){ p ‘forty-two’}

~ > ruby a.rb

···

On Sat, 24 Apr 2004, Richard Lionheart wrote:

“args <>”

“args <>”
“forty-two”

“args <[42]>”

“args <[42]>”
“forty-two”

if you look at the docs for Array#new you’ll see it comes in three of the
flavors above, since i needed the same method signature as Array#new this was
a fast dirty way to do it without really needing to know the exact methed
signature. if you program C this is about like saying

int
method()
{
}

or in C++

int
method(…)
{
}

execpt it’s much easier to get at whatever args the methods has been
called with!

  if Array === args.first

My guess is that this statement is equivalent to “if ‘Array’ is the type of
the first item in the ‘args’ array.” That doesn’t comport with “Programming
Ruby”, Thomas et al, 2001, page 283, which seems to indicate “element by
element comparison of two arrays.” But I can’t see how you could intend to
compare Array’s elements, because I don’t think Array HAS any elements when
‘initialize’ is invoked.

note the ‘===’ vs ‘==’. the method being invoked is the class method
‘===’. in this case Array inherits this method from Class - one of it’s
parents. so check out the class method of Class named ‘===’. :wink:

eg.

~ > cat b.rb
array = [42]
hash = {4 => 2}
file = open FILE

[array, hash, file].each do |obj|
  [Array, Hash, File].each do |klass|
   printf "<%s> %s <%s>\n", obj.inspect, (klass === obj ? "is a" : "is not a"), klass 
  end
end

~ > ruby b.rb
<[42]> is a
<[42]> is not a
<[42]> is not a
<{4=>2}> is not a
<{4=>2}> is a
<{4=>2}> is not a
<#<File:b.rb>> is not a
<#<File:b.rb>> is not a
<#<File:b.rb>> is a

case uses ‘===’ by default, so you can also

~ > cat c.rb
array = [42]
hash = {4 => 2}
file = open FILE

[array, hash, file].each do |obj|
case obj
when Array
puts “<#{ obj.inspect }> is a Array”
when Hash
puts “<#{ obj.inspect }> is a Hash”
when File
puts “<#{ obj.inspect }> is a File”
end
end

~ > ruby c.rb
<[42]> is a Array
<{4=>2}> is a Hash
<#<File:c.rb>> is a File

this is a bit more rubyish i think - but both peices of code are asking if an
object is of a certain type

    ary = args.shift

Equivalent to “ary = args[0]” in this instance, since ‘args’ is not modified
(no “!” after “shift”).

you can always play and find out:

~ > irb
irb(main):001:0> a = [0,1,2]
=> [0, 1, 2]
irb(main):002:0> a.shift
=> 0
irb(main):003:0> a
=> [1, 2]

shift is a method that DOES modify it’s reciever. not all such methods end in
‘!’, such as Array#delete. there is no hard and fast rule about this in ruby,
but in general one can say that methods for which it is non-intuitive that the
method would modify the reciever have a bang, and methods for which there are
two versions (modifying and non-modifying) have a bang version. essentially
it’s up to the designer of the class to decide which methods are ‘dangerous’.
eg.

~ > irb
irb(main):001:0> a = [0,1,2]
=> [0, 1, 2]
irb(main):002:0> a.map{|elem| elem ** 2}
=> [0, 1, 4]
irb(main):003:0> a
=> [0, 1, 2]
irb(main):004:0> a.map!{|elem| elem ** 2}
=> [0, 1, 4]
irb(main):005:0> a
=> [0, 1, 4]
irb(main):006:0> a.delete 0
=> 0
irb(main):007:0> a
=> [1, 4]

    super

Invokes Array#initialze with the original arguments that ‘initialize’ got,
but I don’t see what this accomplishes.

that’s sort of the point - who knows what Array#initialize does, but we are
trying to ‘be an Array’ so we had better do it. we could look into the
sources for Array and find out, or let ruby do it for us. consider:

~ > cat d.rb
class Base
def initialize val
@val = val
end
def meth
p(@val + 2)
end
end

class Derived0 < Base
def initialize(*args, &block)
super
end
end
class Derived1 < Base
def initialize(*args, &block)
# nothing
end
end

d0 = Derived0.new 40
d1 = Derived1.new 40

d0.meth
d1.meth

~ > ruby d.rb
42
d.rb:7:in meth': undefined method +’ for nil:NilClass (NoMethodError)
from d.rb:26

an aggregate class is often safer and less frustrating to debug…
I assume you’re talking about using a Module and including it into a class
or classes.

As before, I appreciate your tutoring.

well - don’t take my word for it, play around and read the group - lot’s of
way to skin a cat. :wink:

cheers.

-a

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
TRY :: for l in ruby perl;do $l -e “print "\x3a\x2d\x29\x0a"”;done
===============================================================================

Hi Mark,

Thanks. You must be a mind-reader :slight_smile: That’s exactly the kind of thing I
wanted to do. I tried to “undefine” the to_s modification by adding the
following after the invocation of the modified Array:

class Array
def to_s
self.to_s
end
end

Of course, that netted me “stack level too deep (SystemStackError)”

Again, I much appreciate your advice. It was especially generous of you to
post your complete solution because I might not have known how to apply your
suggestion. (In this case, happily, I understood your suggestion
immediately.)

Regards,
Richard

“Mark Sparshatt” msparshatt@yahoo.co.uk wrote in message
news:408FFEBE.8060008@yahoo.co.uk

···

Richard Lionheart wrote:

if you want to save the old version of to_s you can use the alias method

class Array # Override to_s
alias old_to_s to_s
def to_s
join("; ")
end
end

then you can access the old to_s behaviour by using the old_to_s method.
Or if you want to change to_s back to it’s default behaviour you can use

class Array
alias to_s old_to_s
end

i.e.

a = %w( foo bar ack)
puts “After assignment "a = %w( foo bar ack)", a.class.to_s =
#{a.class.to_s}”
b = %w(eeny meeny miney mo)
puts “Before override: a = #{a.to_s}, b = #{b.to_s}”

class Array # Override to_s
alias old_to_s to_s
def to_s
join("; ")
end
end

puts “After override: a = #{a.to_s}, b = #{b.to_s}”

class Array
alias to_s old_to_s
end

puts “After re-override: a = #{a.to_s}, b = #{b.to_s}”

results=<<RESULTS
After assignment “a = %w( foo bar ack)”, a.class.to_s =
Array
Before override: a = foobarack, b = eenymeenymineymo
After override: a = foo; bar; ack, b = eeny; meeny; miney; mo
After re-override: a = foobarack, b = eenymeenymineymo
RESULTS


Mark Sparshatt


Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/26/2004

Hi Ara,

“Ara.T.Howard” ahoward@fattire.ngdc.noaa.gov wrote in message
news:Pine.LNX.4.44.0404250819470.15467-100000@fattire.ngdc.noaa.gov

The Thomas/Hunt book says ‘update’ is a method in Hash and CGI::Session,
but
not in Array.

sorry - i meant Array#replace

I successfully used your previous suggestion after fixing it with ‘replace’
as you suggest.

~ > cat a.rb

Thanks for all these examples. I’m going to go through them one-by-one in a
little while. Before I received them, I’d pretty much internalized all the
suggestions I’ve received in this thread and put together a number of
different usages of Array, documenting each one to point out the nuances
that seem important to me. Your recent examples will give me a bunch more!

Which leads to a question about the first one I started with, shown below.
In my comments, I tried to indicate how the derived array got initialized,
claiming it “uses the Array# method with an Array argument .” That
turns out not to be correct, because MyArrayType1# did not get
invoked.

So what method in Array does get invoked? Or maybe it’s a method in Array’s
parent, Class.

Except for that, do my other comments correct?

Thanks again for your superb Ruby guidance. I’ll soon be able to figure out
these kinds of questions for myself, but I haven’t gotten there yet.

Regards,
Richard

···

On Sat, 24 Apr 2004, Richard Lionheart wrote:


Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.665 / Virus Database: 428 - Release Date: 4/30/2004