Using .each with constructors

Is there a nice elegant way of creating several named objects of the
same class? I naively tried

a,b,c,d = 0
[a, b, c, d].each { |o| o = SomeClass.new }

and found that while they get initialised inside the block, they get
destroyed leaving it. I can't believe

a = SomeClass.new
b = SomeClass.new
etc.

is the best way to do it. I can populate an array, but let's
hypothesise that for reasons relating to irritating corporate coding
standards, the variables need specific names... :wink:

Thoughts appreciated! Cheers

···

--
Ben

I am sure some of the real Ruby hackers will have a better solution,
but you can do something like:

a,b,c = Array.new(3).map { Foo.new(42) }

pth

···

On 7/20/06, Ben Zealley <transhumanist@gmail.com> wrote:

is the best way to do it. I can populate an array, but let's
hypothesise that for reasons relating to irritating corporate coding
standards, the variables need specific names... :wink:

=> ["0", "1", "2", "3"]

Hope that helps.

James Edward Gray II

···

On Jul 20, 2006, at 1:35 PM, Ben Zealley wrote:

Is there a nice elegant way of creating several named objects of the
same class? I naively tried

a,b,c,d = 0
[a, b, c, d].each { |o| o = SomeClass.new }

>> a, b, c, d = Array.new(4) { |i| String.new(i.to_s) }

Ben Zealley wrote:

Is there a nice elegant way of creating several named objects of the
same class? I naively tried

a,b,c,d = 0
[a, b, c, d].each { |o| o = SomeClass.new }

and found that while they get initialised inside the block, they get
destroyed leaving it. I can't believe

a = SomeClass.new
b = SomeClass.new
etc.

is the best way to do it. I can populate an array, but let's
hypothesise that for reasons relating to irritating corporate coding
standards, the variables need specific names... :wink:

Thoughts appreciated! Cheers

The parallel assignment/array expansion approach suggested by patrick and james will definitely work. You could also try

[:a,:b,:c,:d].each { |x| eval "#{x} = SomeClass.new" }

Ben Zealley wrote:

Is there a nice elegant way of creating several named objects of the
same class? I naively tried

a,b,c,d = 0
[a, b, c, d].each { |o| o = SomeClass.new }

and found that while they get initialised inside the block, they get
destroyed leaving it. I can't believe

a = SomeClass.new
b = SomeClass.new
etc.

is the best way to do it. I can populate an array, but let's
hypothesise that for reasons relating to irritating corporate coding
standards, the variables need specific names... :wink:

Thoughts appreciated! Cheers

Surely overkill but:

  require 'facet/enumerable/every

  a,b,c = ([SomeClass] * 3).every.new

T.

I prefer to write

class Class
    def *(num)
        a =
        num.times do
            a << new
        end
        a
     end
end

a, b, c = String * 3

···

On 7/20/06, Ben Zealley <transhumanist@gmail.com> wrote:

Is there a nice elegant way of creating several named objects of the
same class? I naively tried

a,b,c,d = 0
[a, b, c, d].each { |o| o = SomeClass.new }

and found that while they get initialised inside the block, they get
destroyed leaving it. I can't believe

a = SomeClass.new
b = SomeClass.new
etc.

is the best way to do it. I can populate an array, but let's
hypothesise that for reasons relating to irritating corporate coding
standards, the variables need specific names... :wink:

Thoughts appreciated! Cheers

--
Ben

###########
a << "hi"
puts a.inspect
puts b.inspect
puts c.inspect

too bad I cannot work out how to write

a, b, c = String * :many

Cheers
Robert
--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

Hi --

···

On Fri, 21 Jul 2006, Mike Harris wrote:

Ben Zealley wrote:

Is there a nice elegant way of creating several named objects of the
same class? I naively tried

a,b,c,d = 0
[a, b, c, d].each { |o| o = SomeClass.new }

and found that while they get initialised inside the block, they get
destroyed leaving it. I can't believe

a = SomeClass.new
b = SomeClass.new
etc.

is the best way to do it. I can populate an array, but let's
hypothesise that for reasons relating to irritating corporate coding
standards, the variables need specific names... :wink:

Thoughts appreciated! Cheers

The parallel assignment/array expansion approach suggested by patrick and james will definitely work. You could also try

[:a,:b,:c,:d].each { |x| eval "#{x} = SomeClass.new" }

That won't work. The variables will be local to the eval, and not
available outside it.

David

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

Mike Harris wrote:

The parallel assignment/array expansion approach suggested by patrick
and james will definitely work. You could also try

[:a,:b,:c,:d].each { |x| eval "#{x} = SomeClass.new" }

I notice the first two can be combined to

a, b, c = Array.new(3) { SomeClass.new }

losing both the .map and the |i|, and that still works (go Ruby! I
continue to be amazed by how much it can work out...). But all of these
leave an anonymous array of the variables sitting around, which doesn't
get GC'd. Can it be done without that, or should I reduce my pedantic
tendencies slightly and live with it? :wink:

Thanks for all the great responses!

···

--
Ben

Mike Harris wrote:

Ben Zealley wrote:

Is there a nice elegant way of creating several named objects of the
same class? I naively tried

a,b,c,d = 0
[a, b, c, d].each { |o| o = SomeClass.new }

and found that while they get initialised inside the block, they get
destroyed leaving it. I can't believe

a = SomeClass.new
b = SomeClass.new
etc.

is the best way to do it. I can populate an array, but let's
hypothesise that for reasons relating to irritating corporate coding
standards, the variables need specific names... :wink:

Thoughts appreciated! Cheers

The parallel assignment/array expansion approach suggested by patrick and james will definitely work. You could also try

[:a,:b,:c,:d].each { |x| eval "#{x} = SomeClass.new" }

You're right, it works if you do the a=b=c=d=0 line first to init scope outside the block. I tested with that and then forgot to include it.

Robert Dober wrote:

I prefer to write

class Class
    def *(num)
        a =
        num.times do
            a << new
        end
        a
     end
end

Hmm...It's too bad that #times below returns 3. It be pretty neat if it
acted like #map in this respect instead.

  3.times { Object.new }

Also

  ([lambda{Object.new}]*3).collect{|c| c.call }

and Robert's solution lead me too:

  class Proc
    def *(i)
      a =
      i.times{ a << call }
      a
    end
  end

  lambda{ Object.new } * 3

Which is pretty versitle. Unforunately I already have Proc#* tied up
with function composition.

T.

I was just using the i to produce different Strings so you could see what was going on in the output. :wink:

James Edward Gray II

···

On Jul 20, 2006, at 2:25 PM, Ben Zealley wrote:

I notice the first two can be combined to

a, b, c = Array.new(3) { SomeClass.new }

losing both the .map and the |i|, and that still works

Ben Zealley wrote

[...]
a, b, c = Array.new(3) { SomeClass.new }

losing both the .map and the |i|, and that still works (go Ruby! I
continue to be amazed by how much it can work out...). But all of these
leave an anonymous array of the variables sitting around, which doesn't
get GC'd. Can it be done without that, or should I reduce my pedantic
tendencies slightly and live with it? :wink:

The array holds references to the new objects, but the objects don't know
that there is an array:

···

-------------------------------------------
GC.start
p ObjectSpace.each_object(Array) {}
a, b, c = Array.new(3) { Object.new }
p ObjectSpace.each_object(Array) {}
GC.start
p ObjectSpace.each_object(Array) {}
-------------------------------------------

output:
67
68
67

Thanks for all the great responses!

btw i like

a, b, c = (1..3).map {Object.new}

or

a, b, c = [42] * 3

but only for immutable types.

:slight_smile:

cheers

Simon

transfire@gmail.com wrote:

Robert Dober wrote:

I prefer to write

class Class
   def *(num)
       a =
       num.times do
           a << new
       end
       a
    end
end
   
Hmm...It's too bad that #times below returns 3. It be pretty neat if it
acted like #map in this respect instead.

3.times { Object.new }

The solution i use to this is (1..3).map { Object.new }. It's elegant/concise enough for me

···

Also

([lambda{Object.new}]*3).collect{|c| c.call }

and Robert's solution lead me too:

class Proc
   def *(i)
     a =
     i.times{ a << call }
     a
   end
end

lambda{ Object.new } * 3

Which is pretty versitle. Unforunately I already have Proc#* tied up
with function composition.

T.

There's no conflict:

class Proc
  def *(x)
    if Integer===x
       (0...x).map{call}
    else
       #...compose procs
       proc{|*args| self[x[*args]]}
    end
  end
end

···

On 7/20/06, transfire@gmail.com <transfire@gmail.com> wrote:

  class Proc
    def *(i)
      a =
      i.times{ a << call }
      a
    end
  end

  lambda{ Object.new } * 3

Which is pretty versitle. Unforunately I already have Proc#* tied up
with function composition.

irb(main):001:0> RUBY_VERSION
=> "1.9.0"
irb(main):002:0> a, b, c = 3.times.map { Object.new }
=> [#<Object:0x2382c8>, #<Object:0x2381d8>, #<Object:0x238070>]

Just saying is all.

···

On Jul 20, 2006, at 7:32 PM, transfire@gmail.com wrote:

Hmm...It's too bad that #times below returns 3. It be pretty neat if it
acted like #map in this respect instead.

  3.times { Object.new }

Simon Kröger wrote:

btw i like

a, b, c = (1..3).map {Object.new}

Now that's elegant. Why would you only use it for immutable types?

···

--
Ben

Mike Harris wrote:

> 3.times { Object.new }
>
>
The solution i use to this is (1..3).map { Object.new }. It's
elegant/concise enough for me

Sure. But it does have the additional overhead of creating a Range
object.

T.

Caleb Clausen wrote:

···

On 7/20/06, transfire@gmail.com <transfire@gmail.com> wrote:
> class Proc
> def *(i)
> a =
> i.times{ a << call }
> a
> end
> end
>
> lambda{ Object.new } * 3
>
> Which is pretty versitle. Unforunately I already have Proc#* tied up
> with function composition.

There's no conflict:

class Proc
  def *(x)
    if Integer===x
       (0...x).map{call}
    else
       #...compose procs
       proc{|*args| self[x[*args]]}
    end
  end
end

Nice. I'll use that.

Thanks!
T.

Hi --

Hmm...It's too bad that #times below returns 3. It be pretty neat if it
acted like #map in this respect instead.

3.times { Object.new }

irb(main):001:0> RUBY_VERSION
=> "1.9.0"
irb(main):002:0> a, b, c = 3.times.map { Object.new }
=> [#<Object:0x2382c8>, #<Object:0x2381d8>, #<Object:0x238070>]

Interesting.... That reveals that one of the problems with this magic
enumerator thing is that the method names weren't necessarily chosen
with this in mind, and don't work very well. 3.times.map very
strongly does *not* communicate a 0...3 mapping to me. My first
reading is:

    3.map

since I expect 3.times to return 3. My second reading is:

   3.times { map { Object.new } }

which also makes no sense. It's quite a leap to figure out that it
means:

   (0...3).map { Object.new }

I fear the magic enumerator doesn't sit very well with the language as
designed without it.

David

···

On Fri, 21 Jul 2006, Logan Capaldo wrote:

On Jul 20, 2006, at 7:32 PM, transfire@gmail.com wrote:

--
http://www.rubypowerandlight.com => Ruby/Rails training & consultancy
Ruby for Rails => RUBY FOR RAILS (reviewed on
                                     Slashdot, 7/12/2006!)
http://dablog.rubypal.com => D[avid ]A[. ]B[lack's][ Web]log
dblack@wobblini.net => me

Ben Zealley wrote:

Simon Kröger wrote:

btw i like

a, b, c = (1..3).map {Object.new}

Now that's elegant. Why would you only use it for immutable types?

No, that's ok for normal objects, but

a, b, c = [42] * 3

isn't, because:

a, b, c = ["123"] * 3
b << '4'
puts a # => 1234

a, b and c are referencing the same object.

cheers

Simon