More on psuedo arrays; Better way?

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?

Ralph S. wrote:

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,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Marnen Laibow-Koser wrote:

Is there a better way to do this?

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

And you don’t need to_sym either.

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?

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

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.

BC> Marnen Laibow-Koser wrote:

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?

Ralph S. wrote:

BC> Marnen Laibow-Koser wrote:

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,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

BC>> Marnen Laibow-Koser wrote:

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

Ralph S. wrote:

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.

On Mon, Nov 23, 2009 at 4:34 PM, Ralph S. [email protected]
wrote:

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?

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

irb(main):001:0> a = “test”
=> “test”
irb(main):002:0> a.object_id
=> -605126498
irb(main):003:0> b = “test”
=> “test”
irb(main):004:0> b.object_id
=> -605140798
irb(main):005:0> a.to_sym.object_id
=> 87218
irb(main):006:0> b.to_sym.object_id
=> 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.

On Mon, Nov 23, 2009 at 5:06 PM, Brian C. [email protected]
wrote:

   from :0

Symbol.all_symbols.find { |x| x.to_s == “baz” }
=> :baz

Thanks !! I’ve also learnt about the all_symbols method, which is new to
me :slight_smile:

Jesus.

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?

Ralph S.:

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?

It depends on the interpreter – but in MRI the Symbols stay forever.

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

¹ Rails actually uses HashWithIndifferentAccess that
lets you access its elements using Symbol keys as well

— Shot

Jesús Gabriel y Galán wrote:

if you call send with the string, I don’t know if a symbol
is created inside that call or not.

Symbol.all_symbols.find { |x| x.to_s == “baz” }
=> nil

send(“baz”)
NoMethodError: undefined method baz' for main:Object from (irb):4:insend’
from (irb):4
from :0

Symbol.all_symbols.find { |x| x.to_s == “baz” }
=> :baz

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?

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?

Ralph S. 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,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]