Array#first is not Array#

I made a class that is a subclass of Array :

class MyClass < Array
def
“Here you go: #{super(i)}”
end
end

and I thought that Array#first and Array#last was just syntactic sugar
that would translate to Array#[0] and Array#[-1] respectively. But
it’s not:

irb> g = MyClass.new([1,2,3])
=> [1, 2, 3]
irb> g[0]
=> “Here you go: 1”
irb> g.first
=> 1

Now, isn’t that really, really crazy? Am I supposed to define
MyClass#first and MyClass#last separately???

Best regards,
Fredrik

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Fredrik wrote:
| I made a class that is a subclass of Array :
|
| class MyClass < Array
| def
| “Here you go: #{super(i)}”
| end
| end
|
| and I thought that Array#first and Array#last was just syntactic sugar
| that would translate to Array#[0] and Array#[-1] respectively. But
| it’s not:
|
| irb> g = MyClass.new([1,2,3])
| => [1, 2, 3]
| irb> g[0]
| => “Here you go: 1”
| irb> g.first
| => 1
|
| Now, isn’t that really, really crazy? Am I supposed to define
| MyClass#first and MyClass#last separately???

C:\scripts>ruby temp.rb
Here you go: 1
1

C:\scripts>cat temp.rb
class MyClass < Array
~ def
~ “Here you go: #{super(i)}”
~ end
end

g = MyClass.new([1,2,3])

puts g[0]
puts g.first

C:\scripts>ruby -v
ruby 1.8.6 (2008-03-03 patchlevel 114) [i386-mswin32]

Hm…


Phillip G.
Twitter: twitter.com/cynicalryan
Blog: http://justarubyist.blogspot.com

~ Calvin: Can you make a living playing silly games? His Dad:
Actually, you can be among the most overpaid people on the planet.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkgW1xUACgkQbtAgaoJTgL8ozACfeThkZk1S/FDCSSYeSBEhog6V
PA4AoIQJjVJlB092JSYBPAXA4jF7UYfE
=c2AX
-----END PGP SIGNATURE-----

I see that Array#each wont do what I want it to do either. I guess I
have to do it like this:

class MyClass < Array
def initialize(arg)
super(arg.map{ |i| “Here you go: #{i}”})
end
end

This would give me all the behavior I want, except that it’s a
wasteful use of memory if I have a really big array and want to
include the same text in all my array elements. I just want to have
some fixed text attached to ANY operations I do with array elements.
To achieve that, do I really need to do it like this?

/Fredrik

from: Fredrik [mailto:[email protected]]

include the same text in all my array elements. I just want to have

some fixed text attached to ANY operations I do with array elements.

there are other better ways, but i just extended your initial
thought/code,

class MyArray < Array
Array.methods.each do |m|
define_method(m) do
“Here you go: #{super}”
end
end
end
#=>…

g=MyArray.new [1,2,3]
#=> Here you go: [1, 2, 3]
g[1]
#=> “Here you go: 2”
g[0]
#=> “Here you go: 1”
g.first
#=> 1
g.last
#=> 3
g[-1]
#=> “Here you go: 3”

kind regards -botp

From: Peña, Botp [mailto:[email protected]]
#…

Array.methods.each do |m|

   ^^^^^^^^^^^^^

make that

   Array.instance_methods.each do |m|

sorry, my bad.

so,

class MyArray < Array
Array.instance_methods.each do |m|
define_method(m) do
“Here you go: #{super}”
end
end
end
#=>…

g=MyArray.new [1,2,3]
#=> Here you go: [1, 2, 3]
g[0]
#=> “Here you go: 1”
g.first
#=> “Here you go: 1”
g[-1]
#=> “Here you go: 3”
g.last
#=> “Here you go: 3”
g[2]
#=> “Here you go: 3”

kind regards -botp

Maybe is better using instance_methods instead

class MyArray < Array
Array.instance_methods.each do |m|
define_method(m) do
“Here you go: #{super}”
end
end
end

irb(main):033:0> g=MyArray.new [1,2,3]
=> Here you go: [1, 2, 3]
irb(main):034:0> g.first
=> “Here you go: 1”
irb(main):035:0>

On Apr 29, 5:36 pm, Peña, Botp [email protected] wrote:

 end

g.first
#=> 1
g.last
#=> 3
g[-1]
#=> “Here you go: 3”

kind regards -botp

But that doesn’t work (though I don’t understand why). I want it to
always say “Here you go: …”, no matter how I retrieve an element out
of the array.

From: Fredrik [mailto:[email protected]]

irb> g.size

=> “Here you go: 3”

That’s a strange size :slight_smile:

So this solution solves some problems but creates new ones instead…

you wanted to put text on all ops

so even

irb> g.last
=> “Here you go: 3”

is already strange, right?

my suggestion is if you just want to view some output w text, just
wrapped it in a text,

like so,

puts “Here you go: #{g.last}”

kind regards -botp

Thanks! But how about this then:

irb> g.size
=> “Here you go: 3”

That’s a strange size :slight_smile:
So this solution solves some problems but creates new ones instead…

I’m sorry, I think I am too vague about what I want to achieve. What I
want is to have is an “array” that behaves exactly like an array
EXCEPT that each element has some text attached to it. Array#size is
not an element but Array#last is an element for example.

Maybe it’s not doable in any other way than copying the text into each
element since I would like this text to follow into Array#each,
Array#map and all those methods.

What I am still thinking about though, is this:
Why on earth is Array#first not calling Array#[0] ???

Fredrik

From: Fredrik [mailto:[email protected]]

I’m sorry, I think I am too vague about what I want to achieve. What I

want is to have is an “array” that behaves exactly like an array

EXCEPT that each element has some text attached to it. Array#size is

not an element but Array#last is an element for example.

Maybe it’s not doable in any other way than copying the text into each

element since I would like this text to follow into Array#each,

Array#map and all those methods.

ok, then just modify those you want

eg,

class Array2 < Array
%w([] first last).each do |m|
define_method(m) do
r = super
puts “Here you go: #{r}”
r
end
end
end
#=> ["[]", “first”, “last”]
a=Array2.new [1,2,3]
#=> [1, 2, 3]
a[0]
Here you go: 1
#=> 1
a.first
Here you go: 1
#=> 1
a.size
#=> 3

What I am still thinking about though, is this:

Why on earth is Array#first not calling Array#[0] ???

that would be calling two methods, and would be quite expensive, right?

kind regards -botp

From: Peña, Botp [mailto:[email protected]]

From: Fredrik [mailto:[email protected]]

# irb> g.size

# => “Here you go: 3”

# That’s a strange size :slight_smile:

# So this solution solves some problems but creates new ones

instead…

you wanted to put text on all ops

so even

irb> g.last

=> “Here you go: 3”

is already strange, right?

my suggestion is if you just want to view some output w text,

just wrapped it in a text,

like so,

puts “Here you go: #{g.last}”

ok, how about combining what we want, ie, put the text yet still
returning the object, so

class MyArray < Array
Array.instance_methods.each do |m|
define_method(m) do
r=super
puts “Here you go: #{r}”
r
end
end
end
#=> …

g=MyArray.new [1,2,3]
Here you go: [1, 2, 3]
#=> [1, 2, 3]
g[0]
Here you go: 1
#=> 1
g.first
Here you go: 1
#=> 1
g.last
Here you go: 3
#=> 3
g.size
Here you go: 3
#=> 3
puts “size is: #{g.size}”
Here you go: 3
size is: 3
#=> nil

is that ok?

kind regards -botp

“David A. Black” [email protected] writes:

On Tue, 29 Apr 2008, Fredrik wrote:

What I am still thinking about though, is this:
Why on earth is Array#first not calling Array#[0] ???

The real question is: why should it? They’re completely separate
methods.

I can’t think of a good reason to ever have: Array#first != Array#

Hi –

On Tue, 29 Apr 2008, Fredrik wrote:

Why on earth is Array#first not calling Array#[0] ???
The real question is: why should it? They’re completely separate
methods.

Mind you, if you dig through the ruby-lang archives, you’ll find Ben
Tilly and Mathieu Bouchard patiently explaining to me the answer to
the same question :slight_smile: My initial assumption was that all get and set
operations would go through [] and []=. They don’t, though. It would
make it very easy to do Perl-style “tie” operations if they did, but
it would also be less efficient; in other words, not going through []
and []= is an optimization.

I’m perennially working on a “tie” module, and never seem to get it
how I want it… but I’ll have another look at it and see how close
it’s getting.

David

Hi –

On Wed, 30 Apr 2008, Brian A. wrote:

“David A. Black” [email protected] writes:

On Tue, 29 Apr 2008, Fredrik wrote:

What I am still thinking about though, is this:
Why on earth is Array#first not calling Array#[0] ???

The real question is: why should it? They’re completely separate
methods.

I can’t think of a good reason to ever have: Array#first != Array#

That’s not the question, though; the question is why #first doesn’t
actually call #[].

David

Brian A. [email protected] writes:

“David A. Black” [email protected] writes:

On Tue, 29 Apr 2008, Fredrik wrote:

What I am still thinking about though, is this:
Why on earth is Array#first not calling Array#[0] ???

The real question is: why should it? They’re completely separate
methods.

I can’t think of a good reason to ever have: Array#first != Array#

Sorry about that. I’m having a bit of trouble with the Gnus news reader,
so this got attached to the wrong message - it should’ve followed
David’s of course.

Ok, I got it. So Array#first is a matter of optimization. I thought it
was syntactic sugar that the Ruby interpreter translates to Array#[]
(0).
But I understand now that Array#first is not there for my coding
convenience but rather for computational speed.

Thanks for clearing it up!
Fredrik

Hi,

On Wed, Apr 30, 2008 at 4:50 AM, Brian A. [email protected]
wrote:

“David A. Black” [email protected] writes:

The real question is: why should it? They’re completely separate
methods.

I can’t think of a good reason to ever have: Array#first != Array#

They’re still separate methods. The point is, internally, Ruby saves
another
dynamic method dispatch by hard-coding Array#first to just grab the
first
item from the internal data structure – just like calling Array#
would, but it’s faster. It might even make a noticeable difference in
some
application that calls Array#first and #last a lot… (I don’t propose
such
cases do exist, but every small part counts)

array.c:
static VALUE
rb_ary_first(int argc, VALUE *argv, VALUE ary)
{
if (argc == 0) {
if (RARRAY_LEN(ary) == 0) return Qnil;
return RARRAY_PTR(ary)[0];
}
else {
return ary_shared_first(argc, argv, ary, Qfalse);
}
}

Here seen retrieving the first item manually.

Arlen

Fredrik wrote;

But I understand now that Array#first is not there for my coding
convenience but rather for computational speed.

I’m using some other scripting language (PHP), and when it becomes known
that method A to do something is faster than method B to do something,
everybody turns to use method A no matter how ugly it looks. (When I say
“method” I don’t mean the object orient meaning. I simply mean “way”.)

Now,

If #first was slower than #[0], nobody would have used it!
Having #first is nice. It has merit (clarity). So the only way to have
it and have people use it is not to have it slower than #[0].

So on the contrary: #first is there for your convenient, not for
computational speed.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs