Adding yet another Array.new form

How about adding a fifth way of constructing new arrays?:

Array.new{|array| block }

Here, array is the newly created array, and the block will initialize it
as it sees fit, e.g,

ary = Array.new{ |ary| 5.times{ |i| ary << i } },

which is a stupid way of doing it (Array.new(5){ |i| i } would do), but
it shows the idea. I often find myself writing methods that fit the
following template:

def a
  ary = []
... construct ary by adding elements to it ...
  ary
end

Lately I've been using the Kernel.returning method from Rails to write
it as

def a
  returning ary = [] do
    ... construct ary by adding elements to it ...
  end
end

which works quite well, but I think that I'd rather be writing it as

def a
  Array.new do |ary|
    ... construct ary by adding elements to it ...
  end
end

Array.new(size){ |index| block } would have to be changed so that size
is optional, and if not given, then this new way of creating an array
would be used. What do you people think? Is this worth yet another
RCR?,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

Why stop with Array? What about all the other classes?

···

On 8/7/05, Nikolai Weibull <mailing-lists.ruby-talk@rawuncut.elitemail.org> wrote:

How about adding a fifth way of constructing new arrays?:

Array.new{|array| block }

--
gavri

I'd rather add another 'new' wrapper, that calls new, calls initialze,
and yields. Maybe call it 'create' or 'construct' or something.

Object,construct(*args) {|obj| .... }

The args would be passed to initialize, the block to construct. Would
fail if the defauly initializer needed a block, but perhaps there's a
way around that.

martin

···

Nikolai Weibull <mailing-lists.ruby-talk@rawuncut.elitemail.org> wrote:

How about adding a fifth way of constructing new arrays?:

Array.new{|array| block }

Here, array is the newly created array, and the block will initialize it
as it sees fit, e.g,

But *what* are the initializations you cannot do nicely ATM? Note, that there are also forms that make use of map and inject that can be quite concise...

Kind regards

    robert

···

Nikolai Weibull <mailing-lists.ruby-talk@rawuncut.elitemail.org> wrote:

How about adding a fifth way of constructing new arrays?:

Array.new{|array| block }

Here, array is the newly created array, and the block will initialize
it as it sees fit, e.g,

ary = Array.new{ |ary| 5.times{ |i| ary << i } },

which is a stupid way of doing it (Array.new(5){ |i| i } would do),
but it shows the idea. I often find myself writing methods that fit
the following template:

def a
ary =
.. construct ary by adding elements to it ...
ary
end

Nikolai Weibull <mailing-lists.ruby-talk@rawuncut.elitemail.org> writes:

Lately I've been using the Kernel.returning method from Rails to write
it as

def a
  returning ary = do
    ... construct ary by adding elements to it ...
  end
end

which works quite well, but I think that I'd rather be writing it as

def a
  Array.new do |ary|
    ... construct ary by adding elements to it ...
  end
end

Array.new(size){ |index| block } would have to be changed so that size
is optional, and if not given, then this new way of creating an array
would be used. What do you people think? Is this worth yet another
RCR?,

I'd rather vote in favor of including #returning to the Ruby core.
It is a very helpful method to DRY.

···

        nikolai

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

Robert Klemme wrote:

Nikolai Weibull wrote:

> How about adding a fifth way of constructing new arrays?:
>
> Array.new{|array| block }
>
> Here, array is the newly created array, and the block will initialize
> it as it sees fit, e.g,
>
> ary = Array.new{ |ary| 5.times{ |i| ary << i } },
>
> which is a stupid way of doing it (Array.new(5){ |i| i } would do),
> but it shows the idea. I often find myself writing methods that fit
> the following template:
>
> def a
> ary =
> .. construct ary by adding elements to it ...
> ary
> end

But *what* are the initializations you cannot do nicely ATM? Note,
that there are also forms that make use of map and inject that can be
quite concise...

Huh? Array#map and Array#inject operate on an array to produce another
array or value. What I'm suggesting is a way to set up the items of an
array in a nice way.

(Actually, as other people have pointed out on this thread, this isn't
necessary limited to arrays, but I'd say it's most applicable to the
initialization of collections.)

Consider the following example from my ruby-lisp format rewrite:

def parse_modifiers
  returning modifiers = do
    until @format.eof?
      if (c = @format.getc) == ?: or c == ?@
        if modifiers.include? c
          raise FormatError.new(@format.pos, "duplicate #{c.chr} modifier")
        end
        modifiers << c
      else
        @format.ungetc(c)
        break
      end
    end
  end
end

Without using returning, that would be

def parse_modifiers
  modifiers =
  until @format.eof?
    if (c = @format.getc) == ?: or c == ?@
      if modifiers.include? c
        raise FormatError.new(@format.pos, "duplicate #{c.chr} modifier")
      end
      modifiers << c
    else
      @format.ungetc(c)
      break
    end
  end
  modifiers
end

I would like to be able to write it as

def parse_modifiers
  Array.new do |modifiers|
    until @format.eof?
      if (c = @format.getc) == ?: or c == ?@
        if modifiers.include? c
          raise FormatError.new(@format.pos, "duplicate #{c.chr} modifier")
        end
        modifiers << c
      else
        @format.ungetc(c)
        break
      end
    end
  end
end

I feel that this makes it clear that parse_modifiers returns a new array
and then the block passed to Array.new sets it up as appropriate.
There's already support for passing a block to initialize an array, but
that can only be done in the following manner:

Array.new(5){ |i| i } # => [0, 1, 2, 3, 4]

or

Array.new(5){ |i| i * 2 } # => [0, 2, 4, 6, 8]

Sure, the format I'm suggesting is perhaps limited in applicability, but
how often do you do Array.new(size){ |index| ... }? I have four methods
in one class whose bodies are a big returning, like parse_modifiers
above, that sets up an array and then returns it,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

Hi --

Nikolai Weibull <mailing-lists.ruby-talk@rawuncut.elitemail.org> writes:

Lately I've been using the Kernel.returning method from Rails to write
it as

def a
  returning ary = do
    ... construct ary by adding elements to it ...
  end
end

[...]

I'd rather vote in favor of including #returning to the Ruby core.
It is a very helpful method to DRY.

It feels a bit side-effect-dependent-ish, as written. It might be
nicer with a more traditional yield/block param syntax:

   returning do |ary| ... end

That shows more of the separation between the fact that you're
returning an array, and the fact that you're assigning the name ary to
that array for use inside the block.

David

···

On Sun, 7 Aug 2005, Christian Neukirchen wrote:

--
David A. Black
dblack@wobblini.net

Christian Neukirchen wrote:

Nikolai Weibull writes:

[Array.new(size = nil){ block } suggestion]

I'd rather vote in favor of including #returning to the Ruby core.
It is a very helpful method to DRY.

Yes, it is. But I don’t see how including Kernel#returning makes the
addition of another form of Array.new pointless,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

It should work either way. I haven't looked at the one in Rails, but mine:

module Kernel
        def returning(*vals)
                yield *vals
        end
end

def a
  returning tmp = do
    tmp << 1; tmp << 2; tmp << 3
  end
end

def b
  returning do |ary|
    ary << 1; ary << 2; ary << 3
  end
end

irb(main):013:0> a
=> [1, 2, 3]
irb(main):014:0> b
=> [1, 2, 3]

And I agree with you. I like how the usage shown in b looks, myself, at least
in the places where I use this construction.

Kirk Haines

···

On Sunday 07 August 2005 10:50 am, David A. Black wrote:

>> def a
>> returning ary = do
>> ... construct ary by adding elements to it ...
>> end
>> end

[...]

> I'd rather vote in favor of including #returning to the Ruby core.
> It is a very helpful method to DRY.

It feels a bit side-effect-dependent-ish, as written. It might be
nicer with a more traditional yield/block param syntax:

   returning do |ary| ... end

That shows more of the separation between the fact that you're
returning an array, and the fact that you're assigning the name ary to
that array for use inside the block.

David A. Black wrote:

> Nikolai Weibull writes:

> > Lately I've been using the Kernel.returning method from Rails to
> > write it as
> >
> > def a
> > returning ary = do
> > ... construct ary by adding elements to it ...
> > end
> > end

> I'd rather vote in favor of including #returning to the Ruby core.
> It is a very helpful method to DRY.

It feels a bit side-effect-dependent-ish, as written. It might be
nicer with a more traditional yield/block param syntax:

  returning do |ary| ... end

That shows more of the separation between the fact that you're
returning an array, and the fact that you're assigning the name ary to
that array for use inside the block.

True. It's simple enough to write it that way as well. In fact,
implementing it as

module Kernel
  def returning(value)
    yield value
    value
  end
end

allows us to write it either way,
        nikolai

···

On Sun, 7 Aug 2005, Christian Neukirchen wrote:

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

Nikolai Weibull wrote:

Robert Klemme wrote:

Nikolai Weibull wrote:

How about adding a fifth way of constructing new arrays?:

Array.new{|array| block }

Here, array is the newly created array, and the block will
initialize it as it sees fit, e.g,

ary = Array.new{ |ary| 5.times{ |i| ary << i } },

which is a stupid way of doing it (Array.new(5){ |i| i } would do),
but it shows the idea. I often find myself writing methods that fit
the following template:

def a
  ary =
  .. construct ary by adding elements to it ...
  ary
end

But *what* are the initializations you cannot do nicely ATM? Note,
that there are also forms that make use of map and inject that can be
quite concise...

Huh? Array#map and Array#inject operate on an array to produce
another array or value. What I'm suggesting is a way to set up the
items of an array in a nice way.

They are methods in Enumerable. map returns an array and inject can be
used to return an array:

(1..10).map{|x| x + 0.5}

=> [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5]

(1..10).inject(){|a,x| a << x + 0.5}

=> [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5]

If you need to create an Array from something enumerable these are quite
conveninent.

(Actually, as other people have pointed out on this thread, this isn't
necessary limited to arrays, but I'd say it's most applicable to the
initialization of collections.)

Consider the following example from my ruby-lisp format rewrite:

def parse_modifiers
  returning modifiers = do
    until @format.eof?
      if (c = @format.getc) == ?: or c == ?@
        if modifiers.include? c
          raise FormatError.new(@format.pos, "duplicate #{c.chr}
        modifier") end
        modifiers << c
      else
        @format.ungetc(c)
        break
      end
    end
  end
end

Without using returning, that would be

def parse_modifiers
  modifiers =
  until @format.eof?
    if (c = @format.getc) == ?: or c == ?@
      if modifiers.include? c
        raise FormatError.new(@format.pos, "duplicate #{c.chr}
      modifier") end
      modifiers << c
    else
      @format.ungetc(c)
      break
    end
  end
  modifiers
end

I would like to be able to write it as

def parse_modifiers
  Array.new do |modifiers|
    until @format.eof?
      if (c = @format.getc) == ?: or c == ?@
        if modifiers.include? c
          raise FormatError.new(@format.pos, "duplicate #{c.chr}
        modifier") end
        modifiers << c
      else
        @format.ungetc(c)
        break
      end
    end
  end
end

I feel that this makes it clear that parse_modifiers returns a new
array and then the block passed to Array.new sets it up as
appropriate.
There's already support for passing a block to initialize an array,
but that can only be done in the following manner:

Array.new(5){ |i| i } # => [0, 1, 2, 3, 4]

or

Array.new(5){ |i| i * 2 } # => [0, 2, 4, 6, 8]

Sure, the format I'm suggesting is perhaps limited in applicability,
but how often do you do Array.new(size){ |index| ... }? I have four
methods in one class whose bodies are a big returning, like
parse_modifiers
above, that sets up an array and then returns it,
        nikolai

In this case I'd prefer the general approach that has been suggested
already:

class Class
  def create(*a)
    obj = new(*a)
    yield obj
    obj
  end
end

=> nil

Array.create do |ar|

?> ar << 1 << 2

end

=> [1, 2]

Kind regards

    robert

Nikolai Weibull wrote:
...

module Kernel
  def returning(value)
    yield value
    value
  end
end

...

Why call it #returning and limit its usefulness? The method can be used
just as well in assignments:

ary = returning do ... end

or as an argument to a method or proc.

Maybe #configure, or #construct?

  def configure(obj)
    yield obj
    obj
  end

  def m1
    configure ary = do
      ary << 1
      ary << 2
    end
  end

  p m1() # ==> [1, 2]

  def m2
    configure do |ary|
      ary << 1
      ary << 2
    end
  end

  p m2() # ==> [1, 2]

I've never used that, but in some cases where there is a parent-child
relationship (or a sibling relationship), I've used a #create method, as
in the following:

  def create(*args)
    klass = args.shift
    obj = klass.new(*args)
    # maybe some additional args or setup based on
    # relation between self and obj
    yield obj
    # register obj in self somehow
    obj
  end

  def m3
    create Array, 5 do |ary|
      ary[0] = 1
      ary[1] = 2
    end
  end

  p m3() # ==> [1, 2, nil, nil, nil]

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Kirk Haines wrote:

module Kernel
        def returning(*vals)
                yield *vals
        end
end

That'd return the last value of the block, not the value passed to
returning.

Also, the returning "function" is apparently also known as the K
combinator (there are many other interesting combinators in lambda
calculus, such as the Y combinator; see, for example,
http://en.wikipedia.org/wiki/Y_combinator\) and can
be found in
vendor/rails/activesupport/lib/active_support/core_ext/kernel.rb in the
Rails distribution,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

Hi --

def a
  returning ary = do
    ... construct ary by adding elements to it ...
  end
end

[...]

I'd rather vote in favor of including #returning to the Ruby core.
It is a very helpful method to DRY.

It feels a bit side-effect-dependent-ish, as written. It might be
nicer with a more traditional yield/block param syntax:

   returning do |ary| ... end

That shows more of the separation between the fact that you're
returning an array, and the fact that you're assigning the name ary to
that array for use inside the block.

It should work either way. I haven't looked at the one in Rails, but mine:

module Kernel
       def returning(*vals)
               yield *vals
       end
end

def a
returning tmp = do
   tmp << 1; tmp << 2; tmp << 3
end
end

That only works by coincidence: tmp << 3 happens to return tmp :slight_smile: If
anything else is the last expression in your block, you'll get a
different result:

   def a
     returning tmp = do
       tmp << 1; tmp << 2; tmp << 3
       puts "I've finished inserting into tmp!"
     end
   end

   a # => nil, because it returns the value of the puts statement

#returning has to explicitly return the thing it yields; otherwise it
will return whatever the block it yielded to returns.

David

···

On Mon, 8 Aug 2005, Kirk Haines wrote:

On Sunday 07 August 2005 10:50 am, David A. Black wrote:

--
David A. Black
dblack@wobblini.net

Robert Klemme wrote:

They are methods in Enumerable. map returns an array and inject can be
used to return an array:

> > (1..10).map{|x| x + 0.5}
=> [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5]
> > (1..10).inject(){|a,x| a << x + 0.5}
=> [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5]

If you need to create an Array from something enumerable these are quite
conveninent.

Yes, yes, but as you say, you still need the enumerable collection.

> Sure, the format I'm suggesting is perhaps limited in applicability,
> but how often do you do Array.new(size){ |index| ... }? I have four
> methods in one class whose bodies are a big returning, like
> parse_modifiers
> above, that sets up an array and then returns it,

In this case I'd prefer the general approach that has been suggested
already:

> > class Class
> > def create(*a)
> > obj = new(*a)
> > yield obj
> > obj
> > end
> > end
=> nil
> > Array.create do |ar|
?> ar << 1 << 2
> > end
=> [1, 2]

Again, this is a little more drastic than adding a line or two to the
initializer of Array for handling a case where the size argument is nil.
Sure, I think that a create method would have its uses, but that doesn't
mean that we can't have a slightly more flexible Array.new as well,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

Yeah. I was typing from memory and I left off that important little last bit.

Ah well. My point was yours. It's easy to implement and works both ways.

Kirk Haines

···

On Sunday 07 August 2005 2:49 pm, Nikolai Weibull wrote:

Kirk Haines wrote:
> module Kernel
> def returning(*vals)
> yield *vals
> end
> end

That'd return the last value of the block, not the value passed to
returning.

Hi --

Nikolai Weibull wrote:
...

module Kernel
  def returning(value)
    yield value
    value
  end
end

...

Why call it #returning and limit its usefulness? The method can be used
just as well in assignments:

ary = returning do ... end

or as an argument to a method or proc.

It's still "returning " in the sense that it's going to return its
argument, even if the block's last expression does not evaluate to
that argument. It's #returning whose return value "returning obj"
refers to. You can, but do not have to, use it as the return value of
a method in which it appears.

For example:

   def x
     ary = returning do |a|
       a.concat %w{a b c d e}
       puts "Done with this block!"
     end
     p ary
     return 100 # or whatever
   end

   x
      => Done with this block!
          ["a", "b", "c", "d", "e"]

Sidenote: it's also interesting how close this gets to:

   .instance_eval {|ary| ... }

(though obviously not identical). I can't think of a good name for:

   .yield_me_and_return_me {|ary| ... }

though :slight_smile:

David

···

On Mon, 8 Aug 2005, Joel VanderWerf wrote:

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

Sidenote: it's also interesting how close this gets to:

  .instance_eval {|ary| ... }

(though obviously not identical).

True.

I can't think of a good name for:

  .yield_me_and_return_me {|ary| ... }

though :slight_smile:

I was thinking of "build", but that's perhaps not very good,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}