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 Shnelvar 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
marnen@marnen.org
--
Posted via http://www.ruby-forum.com/\.

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.

···

--
Posted via http://www.ruby-forum.com/\.

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

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?

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

That is very very cool. Thank you.

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.

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 Shnelvar 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.

···

--
Posted via http://www.ruby-forum.com/\.

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.

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?

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 Shnelvar wrote:

> 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.

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
marnen@marnen.org
--
Posted via http://www.ruby-forum.com/\.

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 4:34 PM, Ralph Shnelvar <ralphs@dos32.com> wrote:

> 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.

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?

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:in `send'
        from (irb):4

Symbol.all_symbols.find { |x| x.to_s == "baz" }

=> :baz

···

from :0

--
Posted via http://www.ruby-forum.com/\.

Do you know the difference between symbols and strings? A million
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?

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

Jesus.

···

On Mon, Nov 23, 2009 at 5:06 PM, Brian Candler <b.candler@pobox.com> wrote:

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:in `send'
from (irb):4
from :0

Symbol.all_symbols.find { |x| x.to_s == "baz" }

=> :baz

Ralph Shnelvar:

> Do you know the difference between symbols and strings? A million
> 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

···

--
Founding member of the Hyphenation Society, a grassroots-based,
not-for-profit, locally-owned-and-operated, cooperatively-managed,
modern-American-English-usage-improvement association.
                                                       [Rick Moen]

> Do you know the difference between symbols and strings? A million
> 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

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).

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 Shnelvar wrote:
[...]

> It depends on the interpreter – but in MRI

MRI?

Matz's Ruby Interpreter (the standard 1.8 implementation).

> 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).

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
marnen@marnen.org

--
Posted via http://www.ruby-forum.com/\.