Implicit block parameter?

Hi,

Probably this has been considered before, but I'll ask anyway.

Before I used Ruby, I used Groovy. In some ways they are (well, were anyway) quite similar, and one feature that I found cool in Groovy that I often miss in Ruby is the implicit (/default/whatever?) block parameter, 'it':

  [1,2,3].each { puts it }

AFAIR this was only provided when no 'it' existed in scope, and the block had a single argument passed when none were declared. Maybe this would interfere with Ruby's warnings about block parameter mismatch, or maybe the implementation doesn't allow for it, but I just wondered if it might be possible, because I notice I do:

  [1,2,3].each { |it| puts it }

and it bugs me a little bit :smiley:

I did try hacking it from the Ruby side and came up with a halfway solution using instance variables and the Binding extension from Rubyforge:

  require 'rubygems'
  require 'extensions/binding'

  def itproc(&blk)
    class << blk
      def [](*args)
        if args.length == 1
          begin
            old = binding[:@it]
            binding[:@it] = args[0]
            super
          ensure
            binding[:@it] = old
          end
        else
          super
        end
      end

      alias :call :[]
    end
    blk
  end

But of course this doesn't work with regular procs (doing it on Proc causes a segfault here, I guess because extensions uses procs itself to do the binding stuff?) and of course it doesn't happen with yielded blocks, even when passed from procs:

  pr = itproc { puts "@it = #{@it.inspect}" }
  pr2 = itproc { |one| puts "@it = #{@it.inspect}; one = #{one.inspect}" }
  pr3 = itproc { |a, b| puts "@it = #{@it.inspect}; a = #{a.inspect}; b = #{b}" }

  # Works
  puts "Call"
  pr.call('Hello')
  pr2.call('Hello')
  pr3.call('He','llo')

  # Works
  puts "\n[]"
  pr['Bye']
  pr2['Bye']
  pr3['Bye','Bye']

  # Doesn't work through yield though :frowning:
  puts "\nYield"
  [1,2,3].each &pr
  [1,2,3].each &pr2
  [1,2,3].each &pr3

Anyway, it's a bit of an abuse of instance vars I guess, and obviously doesn't do the job properly - I wonder if anyone else has thought about this, and whether it's something that doesn't already exist in Ruby itself for a reason?

Cheers,

···

--
Ross Bamford - rosco@roscopeco.remove.co.uk

I got a bit closer by defining an attr_reader 'it' on Kernel, but still it doesn't work with all Procs or via Yield...

···

On Mon, 02 Jan 2006 20:20:30 -0000, I wrote:

Before I used Ruby, I used Groovy. In some ways they are (well, were anyway) quite similar, and one feature that I found cool in Groovy that I often miss in Ruby is the implicit (/default/whatever?) block parameter, 'it':

  [1,2,3].each { puts it }

[...]

I did try hacking it from the Ruby side and came up with a halfway solution using instance variables and the Binding extension from Rubyforge:

--
Ross Bamford - rosco@roscopeco.remove.co.uk

I have also proposed this in October:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/162588

And it seems to have been proposed before.

I have actually implemented it for ruby 1.9 lately (it should work similar for 1.8). It's just a small patch for eval.c:

--- eval_org.c 2005-12-30 02:17:49.000000000 +0100
+++ eval.c 2006-01-02 23:25:46.000000000 +0100
@@ -4656,6 +4656,7 @@ rb_yield_0(VALUE val, VALUE self, VALUE
      NODE *cnode = ruby_current_node;
      int lambda = flags & YIELD_LAMBDA_CALL;
      int state;
+ VALUE it_val = Qnil;

      rb_need_block();

@@ -4675,8 +4676,10 @@ rb_yield_0(VALUE val, VALUE self, VALUE
      scope_vmode = (flags & YIELD_PUBLIC_DEF) ? SCOPE_PUBLIC : block->vmode;
      ruby_block = block->prev;
      if (block->flags & BLOCK_D_SCOPE) {
+ if (avalue && RARRAY(val)->len != 0) it_val = RARRAY(val)->ptr[0];
+ if (!avalue && val != Qundef) it_val = val;
         /* put place holder for dynamic (in-block) local variables */
- ruby_dyna_vars = new_dvar(0, 0, block->dyna_vars);
+ ruby_dyna_vars = new_dvar(0, it_val, block->dyna_vars);
      }
      else {
         /* FOR does not introduce new scope */
@@ -7596,6 +7599,15 @@ rb_exec_end_proc(void)
      ruby_safe_level = safe;
  }

+static VALUE
+rb_f_it(void)
+{
+ if (ruby_dyna_vars) {
+ if (ruby_dyna_vars->id == 0) return ruby_dyna_vars->val;
+ }
+ return Qnil;
+}

···

On Mon, 02 Jan 2006 21:32:57 +0100, Ross Bamford <rosco@roscopeco.remove.co.uk> wrote:

Hi,

Probably this has been considered before, but I'll ask anyway.

+
  void
  Init_eval(void)
  {
@@ -7650,6 +7662,8 @@ Init_eval(void)
      rb_define_global_function("global_variables", rb_f_global_variables, 0); /* in variable.c */
      rb_define_global_function("local_variables", rb_f_local_variables, 0);

+ rb_define_global_function("it", rb_f_it, 0);
+
      rb_define_method(rb_mKernel, "send", rb_f_send, -1);
      rb_define_method(rb_mKernel, "__send__", rb_f_send, -1);
      rb_define_method(rb_mKernel, "funcall", rb_f_funcall, -1);

This defines a global function #it that always returns the first block argument, it is not assignable. #it is available whether other block parameters are there or not. #it defaults to nil (if no arguments are given or if not in a block context.

$ cat test_it.rb
p (1..5).to_a.map { -it }

%w[a b c].each { |x| p [x, it] }

p it
$ ./miniruby test_it.rb
[-1, -2, -3, -4, -5]
["a", "a"]
["b", "b"]
["c", "c"]
nil

Dominik

Ross Bamford ha scritto:

Hi,

Probably this has been considered before, but I'll ask anyway.

Before I used Ruby, I used Groovy. In some ways they are (well, were anyway) quite similar, and one feature that I found cool in Groovy that I often miss in Ruby is the implicit (/default/whatever?) block parameter, 'it':

    [1,2,3].each { puts it }

AFAIR this was only provided when no 'it' existed in scope, and the block had a single argument passed when none were declared. Maybe this would interfere with Ruby's warnings about block parameter mismatch, or maybe the implementation doesn't allow for it, but I just wondered if it might be possible, because I notice I do:

    [1,2,3].each { |it| puts it }

and it bugs me a little bit :smiley:

eh, I alwaya thought the same.
And I just discovered that "it" is used in at least another environment:
AliceML seem to use it to mean "the result of the last expression", similarly to how we use "_" in irb.

Isn't it nice to write
  x= 2+2
  print it

:wink:

how about?

class Array
  alias :each1 :each
  def each(&b)
    each1{|i| b.call($i = i) }
  end
end
%w(a b c).each{p $i} #-> "a" "b" "c"

···

On 1/2/06, Ross Bamford <rosco@roscopeco.remove.co.uk> wrote:

On Mon, 02 Jan 2006 20:20:30 -0000, I wrote:

> Before I used Ruby, I used Groovy. In some ways they are (well, were
> anyway) quite similar, and one feature that I found cool in Groovy that
> I often miss in Ruby is the implicit (/default/whatever?) block
> parameter, 'it':
>
> [1,2,3].each { puts it }

--
Simon Strandgaard

Wicked :slight_smile: I can confirm that seems to work in 1.8 (though I had to make one change manually because the source is slightly different of course). I guessed it'd be something that would be reasonably easy (when you know how ;)) from the C side.

FWIW +1 for inclusion in a future Ruby.

Cheers,

···

On Mon, 02 Jan 2006 22:54:43 -0000, Dominik Bathon <dbatml@gmx.de> wrote:

On Mon, 02 Jan 2006 21:32:57 +0100, Ross Bamford > <rosco@roscopeco.remove.co.uk> wrote:

Hi,

Probably this has been considered before, but I'll ask anyway.

I have also proposed this in October:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/162588

And it seems to have been proposed before.

I have actually implemented it for ruby 1.9 lately (it should work similar for 1.8). It's just a small patch for eval.c:

... [snipped patch] ...

--
Ross Bamford - rosco@roscopeco.remove.co.uk

For what it's worth, some of us proposed the same thing for the boo
language [1]. Also groovy has this feature [2]. (might be worth
putting in proposal that two other ruby & python inspired languages use
or want to use this, as well as AliceML)
Pnuts also has a related feature [3]:

print myitems[it % 2 == 0]

Essentially you can pass a boolean expression or a closure to an
indexer. Above would return all even items. I'm not proposing it for
ruby, just mentioning. "it" is very powerful.
Comega (or c-omega from microsoft) also has this feature [4]

1.
http://groups.google.com/group/boolang/browse_frm/thread/52d619066407bfe/082fc0286faec24c
2. http://groovy.codehaus.org/Closures
3. http://pnuts.org/snapshot/latest/doc/lang.html
4. http://research.microsoft.com/Comega/

or how about?

module Kernel
  def it
    $i
  end
end
class Array
  alias :each1 :each
  def each(&b)
    each1{|i| b.call($i = i) }
  end
end

[1, 2, 3].each{ puts it } # 1 2 3

···

On 1/2/06, Simon Strandgaard <neoneye@gmail.com> wrote:

On 1/2/06, Ross Bamford <rosco@roscopeco.remove.co.uk> wrote:
> On Mon, 02 Jan 2006 20:20:30 -0000, I wrote:
>
> > Before I used Ruby, I used Groovy. In some ways they are (well, were
> > anyway) quite similar, and one feature that I found cool in Groovy that
> > I often miss in Ruby is the implicit (/default/whatever?) block
> > parameter, 'it':
> >
> > [1,2,3].each { puts it }

--
Simon Strandgaard

could I use this mechanisms for String ?

actually i've a function call :

s="Happy new year!"
s_utf8=to_UTF8(s)
p s_utf8

with :

def to_UTF8(s)
    return Iconv.new('UTF-8', 'MacRoman').iconv(s)
end

something like :

class String
    def to_utf8(s)
        return Iconv.new('UTF-8', 'MacRoman').iconv(s)
    end
end

p "Happy new year!".to_UTF8

does that make sense ?

···

Simon Strandgaard <neoneye@gmail.com> wrote:

class Array
  alias :each1 :each
  def each(&b)
    each1{|i| b.call($i = i) }
  end
end
%w(a b c).each{p $i} #-> "a" "b" "c"

--
une bévue

Hi --

···

On Tue, 3 Jan 2006, Ross Bamford wrote:

On Mon, 02 Jan 2006 22:54:43 -0000, Dominik Bathon <dbatml@gmx.de> wrote:

On Mon, 02 Jan 2006 21:32:57 +0100, Ross Bamford >> <rosco@roscopeco.remove.co.uk> wrote:

Hi,

Probably this has been considered before, but I'll ask anyway.

I have also proposed this in October:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/162588

And it seems to have been proposed before.

I have actually implemented it for ruby 1.9 lately (it should work similar for 1.8). It's just a small patch for eval.c:

... [snipped patch] ...

Wicked :slight_smile: I can confirm that seems to work in 1.8 (though I had to make one change manually because the source is slightly different of course). I guessed it'd be something that would be reasonably easy (when you know how ;)) from the C side.

FWIW +1 for inclusion in a future Ruby.

You can submit it as an RCR if you wish, at http://www.rcrchive.net.
(I'll vote "Strongly opposed", but don't let that stop you :slight_smile:

David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!

None of which I think is actually a reason for Ruby to get it.

I am in the "opposed" camp on this, because I think that it will
result in less-readable code overall.

-austin

···

On 03/01/06, Doug H <doug00@gmail.com> wrote:

For what it's worth, some of us proposed the same thing for the boo
language [1]. Also groovy has this feature [2]. (might be worth
putting in proposal that two other ruby & python inspired languages use
or want to use this, as well as AliceML)
Pnuts also has a related feature [3]:

--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

I think he wants this for any single parameter block though, not just
arrays.

What about automatically creating aliases, too? Like where you put
"alias :each1 :each", have it automatically create an alias
":old_methodname" whenever you overwrite an existing method (replace
"methodname" with actual name").
..

Cool, didn't consider doing it that way :slight_smile: I was thinking in more general terms, but this way does get it working with each. I did notice, though, that it doesn't seem too happy with other Enumerable methods (select and collect seem pretty odd)...

Cheers,

···

On Mon, 02 Jan 2006 22:06:49 -0000, Simon Strandgaard <neoneye@gmail.com> wrote:

On 1/2/06, Simon Strandgaard <neoneye@gmail.com> wrote:

On 1/2/06, Ross Bamford <rosco@roscopeco.remove.co.uk> wrote:
> On Mon, 02 Jan 2006 20:20:30 -0000, I wrote:
>
> > Before I used Ruby, I used Groovy. In some ways they are (well, were
> > anyway) quite similar, and one feature that I found cool in Groovy that
> > I often miss in Ruby is the implicit (/default/whatever?) block
> > parameter, 'it':
> >
> > [1,2,3].each { puts it }

or how about?

module Kernel
  def it
    $i
  end
end
class Array
  alias :each1 :each
  def each(&b)
    each1{|i| b.call($i = i) }
  end
end

[1, 2, 3].each{ puts it } # 1 2 3

--
Ross Bamford - rosco@roscopeco.remove.co.uk

dblack@wobblini.net wrote:

Hi --

Wicked :slight_smile: I can confirm that seems to work in 1.8 (though I had to make one change manually because the source is slightly different of course). I guessed it'd be something that would be reasonably easy (when you know how ;)) from the C side.

FWIW +1 for inclusion in a future Ruby.

You can submit it as an RCR if you wish, at http://www.rcrchive.net.
(I'll vote "Strongly opposed", but don't let that stop you :slight_smile:

For what it's worth, I'll probably only vote "neutral" for the lack of readability it encourages (not naming the things). It's not as if people name their variables "it" a lot... :slight_smile:

Devin

···

On Tue, 3 Jan 2006, Ross Bamford wrote:

That would be nice, but I wonder what'd happen if a method was aliased more than once. The alias is another bit of noise, and doesn't protect you from manually overwriting a previous alias, but at least you get the chance to fix it.

Cheers,

···

On Mon, 02 Jan 2006 22:26:46 -0000, Doug H <doug00@gmail.com> wrote:

What about automatically creating aliases, too? Like where you put
"alias :each1 :each", have it automatically create an alias
":old_methodname" whenever you overwrite an existing method (replace
"methodname" with actual name").
.

--
Ross Bamford - rosco@roscopeco.remove.co.uk

Hi --

···

On Tue, 3 Jan 2006, Doug H wrote:

I think he wants this for any single parameter block though, not just
arrays.

What about automatically creating aliases, too? Like where you put
"alias :each1 :each", have it automatically create an alias
":old_methodname" whenever you overwrite an existing method (replace
"methodname" with actual name").

I've done that sometimes (alias old_meth meth), but I wouldn't want it
happening automatically. It would have the potential to clutter the
program space with methods I hadn't asked for and wouldn't need.

David

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!

Devin Mullins ha scritto:

For what it's worth, I'll probably only vote "neutral" for the lack of readability it encourages (not naming the things). It's not as if people name their variables "it" a lot... :slight_smile:

True, but considering how often people write
  each {|x| stuff(x)}
I don't think it would be a great less in readability.
Not really advocating "it", but neither against it. No pun intended.

(David, can't see your message in the newsgroup, so I'll reply with this one)

Hi --

Wicked :slight_smile: I can confirm that seems to work in 1.8 (though I had to make one change manually because the source is slightly different of course). I guessed it'd be something that would be reasonably easy (when you know how ;)) from the C side.

FWIW +1 for inclusion in a future Ruby.

You can submit it as an RCR if you wish, at http://www.rcrchive.net.
(I'll vote "Strongly opposed", but don't let that stop you :slight_smile:

Hmm, I might put together a bit of a proposal and do that. I hope you'll comment when you vote no, I'd be interested in your perspective on this :slight_smile:

(Replying to Devin's message)

For what it's worth, I'll probably only vote "neutral" for the lack of readability it encourages (not naming the things). It's not as if people name their variables "it" a lot... :slight_smile:

Yeah, readability is a downside but I think with a name like 'it' it would mostly be pretty self evident, and of course it shouldn't preclude doing it the current way (declaring the argument).

That was the reason I didn't mention another idea, about making $_ the implicit block arg so you could do:

  ['one','two','three'].select { ~/t[a-z]*/ }

(I don't actually advocate that but it occured while I was playing with the 'it' thing).

···

On Tue, 03 Jan 2006 13:52:03 -0000, Devin Mullins <twifkak@comcast.net> wrote:

dblack@wobblini.net wrote:

On Tue, 3 Jan 2006, Ross Bamford wrote:

--
Ross Bamford - rosco@roscopeco.remove.co.uk

gabriele renzi wrote:

Devin Mullins ha scritto:

For what it's worth, I'll probably only vote "neutral" for the lack of readability it encourages (not naming the things). It's not as if people name their variables "it" a lot... :slight_smile:

True, but considering how often people write
each {|x| stuff(x)}
I don't think it would be a great less in readability.
Not really advocating "it", but neither against it. No pun intended.

AGH! NOT THAT WORD!

- Knights of Ni

Hi --

(David, can't see your message in the newsgroup, so I'll reply with this one)

Hi --

Wicked :slight_smile: I can confirm that seems to work in 1.8 (though I had to make one change manually because the source is slightly different of course). I guessed it'd be something that would be reasonably easy (when you know how ;)) from the C side.

FWIW +1 for inclusion in a future Ruby.

You can submit it as an RCR if you wish, at http://www.rcrchive.net.
(I'll vote "Strongly opposed", but don't let that stop you :slight_smile:

Hmm, I might put together a bit of a proposal and do that. I hope you'll comment when you vote no, I'd be interested in your perspective on this :slight_smile:

I don't like it. I've never felt there was a problem to solve in this
area, since it's so easy to specify an argument list. Having a magic
variable ("it" or $_ or whatever) seems like a step backwards, in
terms of clarity and consistency.

I can't come up with a technical argument against it, since obviously
it can be done (as witness Perl and other languages). It just strikes
me as needless, and very afterthought-like (in the sense that the fact
that blocks have named arguments always seemed to me to be what
happens *instead* of $_/it and @_ and so forth).

David

···

On Wed, 4 Jan 2006, Ross Bamford wrote:

On Tue, 03 Jan 2006 13:52:03 -0000, Devin Mullins <twifkak@comcast.net> > wrote:

dblack@wobblini.net wrote:

On Tue, 3 Jan 2006, Ross Bamford wrote:

--
David A. Black
dblack@wobblini.net

"Ruby for Rails", from Manning Publications, coming April 2006!