More on psuedo arrays; Better way?

R

Ralph Shnelvar

Newbie here:

Consider:



N_X_METHODS = 20

class X
20.times do |i|
define_method "x%02d=" % i do |arg|
# the puts, below, is just a placeholder for a more complicated method
puts "Hi " + i.to_s + arg.to_s
end
end
end


m = Array.new(N_X_METHODS) do |i|
("x%02d=" % i).to_sym
end

p m


10.times do |i|
x = X.new

# select a random method
x.method(m[rand(i % N_X_METHODS)]).call(i)
end






Let's focus on the line
x.method(m[rand(i % N_X_METHODS)]).call(i)


Is there a better way to do this? Is there a more Ruby-ish way to do
anything else in the code, above?
 
M

Marnen Laibow-Koser

Ralph said:
Newbie here:

Consider:



N_X_METHODS = 20

class X
20.times do |i|
define_method "x%02d=" % i do |arg|
# the puts, below, is just a placeholder for a more complicated
method
puts "Hi " + i.to_s + arg.to_s
end
end
end


m = Array.new(N_X_METHODS) do |i|
("x%02d=" % i).to_sym
end

p m


10.times do |i|
x = X.new

# select a random method
x.method(m[rand(i % N_X_METHODS)]).call(i)
end






Let's focus on the line
x.method(m[rand(i % N_X_METHODS)]).call(i)


Is there a better way to do this?

x.send("x#{rand(i % N_X_METHODS)]".to_sym))

You don't need m at all.
Is there a more Ruby-ish way to do
anything else in the code, above?

Yes: use operators to make X look like a real array.

class X
def []=(i, arg)
puts "Hi " + i.to_s + arg.to_s
end
end

N_X_METHODS = 20

10.times do |i|
x = X.new # should this be outside the loop?
x[rand(i % N_X_METHODS)] = i
end

Best,
 
R

Ralph Shnelvar

MLK> x.send("x#{rand(i % N_X_METHODS)]".to_sym))

MLK> You don't need m at all.

Isn't there a significant cost in the overhead of doing the
string substitution
"x#{rand(i % N_X_METHODS)]"
a million times?

MLK> Yes: use operators to make X look like a real array.

MLK> class X
MLK> def []=(i, arg)
MLK> puts "Hi " + i.to_s + arg.to_s
MLK> end
MLK> end

MLK> N_X_METHODS = 20

MLK> 10.times do |i|
MLK> x = X.new # should this be outside the loop?
MLK> x[rand(i % N_X_METHODS)] = i
MLK> end

That is very very cool. Thank you.
 
R

Ralph Shnelvar

BC> Marnen Laibow-Koser said:
Is there a better way to do this?

x.send("x#{rand(i % N_X_METHODS)]".to_sym))

BC> And you don't need to_sym either.

This x.send() will be executed a million times.

Doesn't that have a fairly high overhead? Won't a million symbols be
generated? In my case ... with the m array, only 20 symbols would be
generated.

Does it matter?

Is it possible to run out of symbols?
 
R

Ralph Shnelvar

BC>> Marnen Laibow-Koser said:
Is there a better way to do this?

x.send("x#{rand(i % N_X_METHODS)]".to_sym))

BC>> And you don't need to_sym either.

RS> This x.send() will be executed a million times.

RS> Doesn't that have a fairly high overhead? Won't a million symbols be
RS> generated? In my case ... with the m array, only 20 symbols would be
RS> generated.

RS> Does it matter?

RS> Is it possible to run out of symbols?

Argh ... I was the OP.

That 10.times should have read 1_000_000.times (or some very large
number of times).

To refresh ... the following should have been the code ...



N_X_METHODS = 20

class X
20.times do |i|
define_method "x%02d=" % i do |arg|
# n.b. x00= ... x19= already exist and I have no control over
# there names or the fact that they were created that way.
# the puts, below, is just a placeholder for a more complicated method
puts "Hi " + i.to_s + arg.to_s
end
end
end


m = Array.new(N_X_METHODS) do |i|
("x%02d=" % i).to_sym
end

p m


1_000_000.times do |i|
x = X.new

# select a random method
x.method(m[rand(i % N_X_METHODS)]).call(i)
end
 
M

Marnen Laibow-Koser

Ralph said:
BC> Marnen Laibow-Koser said:
Is there a better way to do this?

x.send("x#{rand(i % N_X_METHODS)]".to_sym))

BC> And you don't need to_sym either.

This x.send() will be executed a million times.

Doesn't that have a fairly high overhead? Won't a million symbols be
generated? In my case ... with the m array, only 20 symbols would be
generated.

Does it matter?

Is it possible to run out of symbols?

Do you know the difference between symbols and strings? A million
strings may be generated (and quickly GC'd), but only 20 symbols will.

What are you trying to do here, anyway? I strongly suspect that there's
a better approach thanyour pseudoarray. If you can describe the use
case, I'll see what comes to mind.

Best,
 
J

Jesús Gabriel y Galán

BC> Marnen Laibow-Koser said:
Is there a better way to do this?

x.send("x#{rand(i % N_X_METHODS)]".to_sym))

BC> And you don't need to_sym either.

This x.send() will be executed a million times.

Doesn't that have a fairly high overhead? =A0Won't a million symbols be
generated? =A0In my case ... with the m array, only 20 symbols would be
generated.

Does it matter?

Is it possible to run out of symbols?

A symbol is the same object for the same String representation:

irb(main):001:0> a =3D "test"
=3D> "test"
irb(main):002:0> a.object_id
=3D> -605126498
irb(main):003:0> b =3D "test"
=3D> "test"
irb(main):004:0> b.object_id
=3D> -605140798
irb(main):005:0> a.to_sym.object_id
=3D> 87218
irb(main):006:0> b.to_sym.object_id
=3D> 87218

So even if you calling to_sym on different string objects many times,
only one symbol for each different string will be created. On the
other hand, if you call send with the string, I don't know if a symbol
is created inside that call or not.

Jesus.
 
B

Brian Candler

Ralph said:
Isn't there a significant cost in the overhead of doing the
string substitution
"x#{rand(i % N_X_METHODS)]"
a million times?

It won't be significant unless you build your application, profile it,
and find that this is the bottleneck. I'd say this is highly unlikely,
and in any case, I doubt the final application will be calling methods
at random.

Ruby apps are building and throwing away objects all the time. Did you
realise, for example, that a loop containing

puts "hello"

creates a new string object every iteration? This is normal. Strings are
mutable, and Ruby has no way of knowing that you haven't mutated the
last one it created, so it has to create a fresh one each time.

As for
x.send("x#{rand(i % N_X_METHODS)]".to_sym)
vs
x.send("x#{rand(i % N_X_METHODS)]")

- they both do the same. If given a String argument, send will convert
it to a symbol itself.
 
B

Brian Candler

Jesús Gabriel y Galán said:
if you call send with the string, I don't know if a symbol
is created inside that call or not.
NoMethodError: undefined method `baz' for main:Object
from (irb):4:in `send'
from (irb):4
from :0
 
J

Jesús Gabriel y Galán

NoMethodError: undefined method `baz' for main:Object
=A0 =A0 =A0 =A0from (irb):4:in `send'
=A0 =A0 =A0 =A0from (irb):4
=A0 =A0 =A0 =A0from :0
=3D> :baz

Thanks !! I've also learnt about the all_symbols method, which is new to me=
:)

Jesus.
 
R

Ralph Shnelvar

MLK> Do you know the difference between symbols and strings? A million
MLK> strings may be generated (and quickly GC'd), but only 20 symbols will.

I thought I did ... but apparently I didn't.

I see that
irb(main):001:0> "xyz01".to_sym.object_id
=> 156018
irb(main):002:0> ("xyz%02d" % 1).to_sym.object_id
=> 156018


So ....
Do symbols hang around "forever"? Once a symbol is created it is
not deleted until the interpreter goes away?
 
R

Ralph Shnelvar

MLK> Do you know the difference between symbols and strings? A million
SPS> It depends on the interpreter – but in MRI

MRI?

SPS> the Symbols stay forever.

SPS> That’s why Rails uses Strings as keys in the params Hash¹; if Symbols
SPS> were used, you could theoretically create a denial of service attack by
SPS> making requests with a lot of unique GET parameters (which Rails would
SPS> turn into Symbols and MRI would not garbage-collect).

Wow ... that's really interesting.

Thank you for your interesting and informative response.

So given that one could accumulate and accumulate and accumulate
symbols ... what is the point of symbols? Are they really needed in
Ruby and/or Rails?
 
M

Marnen Laibow-Koser

Ralph Shnelvar wrote:
[...]
SPS> It depends on the interpreter – but in MRI

MRI?

Matz's Ruby Interpreter (the standard 1.8 implementation).
SPS> the Symbols stay forever.

SPS> That’s why Rails uses Strings as keys in the params Hash¹; if
Symbols
SPS> were used, you could theoretically create a denial of service
attack by
SPS> making requests with a lot of unique GET parameters (which Rails
would
SPS> turn into Symbols and MRI would not garbage-collect).

Wow ... that's really interesting.

Thank you for your interesting and informative response.

So given that one could accumulate and accumulate and accumulate
symbols ...

Only if their string representations are different. But the Rails
consideration is sort of a special case.
what is the point of symbols?

The point is that :abc is guaranteed to refer to the same object every
time, whereas "abc" creates a new object every time. Normally, this
means that symbols are more efficient.

Are they really needed in
Ruby and/or Rails?

Absolutely. Message passing uses symbols for the message names. If it
used strings instead, the interpreter would quickly bog down, since
every method call in Ruby is implemented with message sending.

You're asking fairly basic questions that a close reading of the Pickaxe
Book should answer...

Best,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top