Specifying local and external block parameters (that old chestnut) 
Author Message
 Specifying local and external block parameters (that old chestnut)

I've {*filter*}ised discussion from the "Bugs" thread.  I hope it is a service to
the community to reopen this.  The poll on RubyGarden votes "make 'em all
local", closely followed by "leave it unchanged".  Yet the "problem" keeps
coming up, and the most sensible solution (in my mind) is not represented in
the poll.

I think it makes sense to explicitly mark *external* variables, as block-local
variables (parameters, in fact) would be the norm.

Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable,
then one could write

  collection.each do |a,:b,c|
    ...
  end

or

  collection.each do |a,b,c|
    external b
    ...
  end

I'm not sure which of the above I prefer.  One should optimise for the common
case.

I'd like to put a question to the audience :)  Does anyone actually have a need
to use non-local block parameters?  Ever?

Apologies if this can of worms is better left buried.

Cheers,
Gavin

--
Gavin Sinclair                                       Software Engineer
Sydney, Australia                            Soyabean Software Pty Ltd



Tue, 22 Mar 2005 09:58:07 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:

> I've {*filter*}ised discussion from the "Bugs" thread.  I hope it is a service to
> the community to reopen this.  The poll on RubyGarden votes "make 'em all
> local", closely followed by "leave it unchanged".  Yet the "problem" keeps
> coming up, and the most sensible solution (in my mind) is not represented in
> the poll.

> I think it makes sense to explicitly mark *external* variables, as block-local
> variables (parameters, in fact) would be the norm.

> Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable,
> then one could write

>   collection.each do |a,:b,c|
>     ...
>   end

> or

>   collection.each do |a,b,c|
>     external b
>     ...
>   end

> I'm not sure which of the above I prefer.  One should optimise for the common
> case.

> I'd like to put a question to the audience :)  Does anyone actually have a need
> to use non-local block parameters?  Ever?

I've asked this before but can't recall any answers. How would one
do the following without non-local block params:

a = [1.1, 3.14, 2.7, 5.15]
sum = 0.0
a.each { |elem| sum += a }

Personally, I like accessing external scope by default. C behaves similiarly:
#include <stdio.h>

int main()
{
        int a = 42;
        int b = 55;

        printf("a: %d b: %d\n", a, b );

        {
                int a = 33; /* define a as local scope to this block*/
                printf("a: %d b: %d\n", a, b );
        }

Quote:
}

Gives you
a: 42 b: 55
a: 33 b: 55

--
Alan Chen
Digikata LLC
http://www.*-*-*.com/



Tue, 22 Mar 2005 10:19:17 GMT  
 Specifying local and external block parameters (that old chestnut)
Hi,

In message "Specifying local and external block parameters (that old chestnut)"

|I've {*filter*}ised discussion from the "Bugs" thread.  I hope it is a service to
|the community to reopen this.  The poll on RubyGarden votes "make 'em all
|local", closely followed by "leave it unchanged".  Yet the "problem" keeps
|coming up, and the most sensible solution (in my mind) is not represented in
|the poll.

The "solution" changes time to time in my mind.  Currently I'm
thinking of the following:

  * variables assigned by ":=" should be local to the block (or
    possibly local to the nearest compound statements).

  * if ":=" assignee is already defined in outer scope, it should be
    warned (no -w needed, probably), and outer variable is shadowed
    hereafter.

  * all local variables in block parameters (e.g. var in |var|) should
    be treated as if they are assigned by ":=".  other types of
    variables in block parameter should be warned.

  * scope of local variables assigned by "=" will be a nearest "body"
    (method body, class body etc.) consistently.

This does not change the appearance of Ruby code much, unlke <var>
solution.  It is incompatible to the current syntax, for example,

   a = 5
   [1,2,3].each{|a| break if a % 2 == 0}
   p a

prints "2" now.  It will print "5" (with shadowing warning) if we
adopt the changes above.  Since it is not compatible, it will not be
available in the near future.  Perhaps you have to wait until Rite.

                                                        matz.



Tue, 22 Mar 2005 10:37:21 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:
----- Original Message -----


Sent: Thursday, October 03, 2002 8:58 PM
Subject: Specifying local and external block parameters (that old chestnut)

> I think it makes sense to explicitly mark *external* variables, as
block-local
> variables (parameters, in fact) would be the norm.

> Thus, if 'a' and 'c' are regular parameters and 'b' is an external
variable,
> then one could write

>   collection.each do |a,:b,c|
>     ...
>   end

> or

>   collection.each do |a,b,c|
>     external b
>     ...
>   end

> I'm not sure which of the above I prefer.  One should optimise for the
common
> case.

One problem is that it's not just a simple variable. It
can be anything that responds to assignment. For example,
an accessor:

  0.upto(99) {|frame.scroll| sleep 0.1}

Quote:
> I'd like to put a question to the audience :)  Does anyone actually have a
need
> to use non-local block parameters?  Ever?

The above is an example.

Also what if I want the last value(s) of a loop?

  x,i = nil
  myobj.each_with_index do |x,i|
    # process...
    break if some_condition
    # more processing...
  end

  last_obj = x
  last_index = i

Yes, I *could* save them off in different variables
right before I did the break:

  y,j = nil
  myobj.each do |x,i|
   #...
   if some_condition
     y,j = x,i
     break
   end
   #...
  end

  last_obj, last_index = y,j

Two more variables and much ugliness. No, thanks.

Hal



Tue, 22 Mar 2005 10:38:46 GMT  
 Specifying local and external block parameters (that old chestnut)


Quote:


> Sent: Thursday, October 03, 2002 8:58 PM
> Subject: Specifying local and external block parameters (that old chestnut)

> > I think it makes sense to explicitly mark *external* variables, as
> block-local
> > variables (parameters, in fact) would be the norm.

> > Thus, if 'a' and 'c' are regular parameters and 'b' is an external
> variable,
> > then one could write

> >   collection.each do |a,:b,c|
> >     ...
> >   end

> > or

> >   collection.each do |a,b,c|
> >     external b
> >     ...
> >   end

> > I'm not sure which of the above I prefer.  One should optimise for the
> common
> > case.

> One problem is that it's not just a simple variable. It
> can be anything that responds to assignment. For example,
> an accessor:

>   0.upto(99) {|frame.scroll| sleep 0.1}

So could
  0.upto(99) {|:frame.scroll| sleep 0.1}
work?

Look quite good, I think, since we are used to :: as a scoping operator.

Quote:
> > I'd like to put a question to the audience :)  Does anyone actually have a
> need
> > to use non-local block parameters?  Ever?

> The above is an example.

Quite a nice example too, IMO.

- Show quoted text -

Quote:
> Also what if I want the last value(s) of a loop?

>   x,i = nil
>   myobj.each_with_index do |x,i|
>     # process...
>     break if some_condition
>     # more processing...
>   end

>   last_obj = x
>   last_index = i

> Yes, I *could* save them off in different variables
> right before I did the break:
>   [...]
> Two more variables and much ugliness. No, thanks.

> Hal

I really dislike relying on finishing values like that, because:
 - you have to declare variables beforehand
 - code is harder to understand or be confident that it's right

Much better, IMO, is

  x, i = get_values(myobj)

  def get_values(obj)
    obj.each_with_index do |x, i|
      # process
      return x, i if some_condition
      # more processing
    end
  end

Gavin



Tue, 22 Mar 2005 13:10:48 GMT  
 Specifying local and external block parameters (that old chestnut)
Hi,

In message "Re: Specifying local and external block parameters (that old chestnut)"

|  0.upto(99) {|frame.scroll| sleep 0.1}

|  x,i = nil
|  myobj.each_with_index do |x,i|
|    # process...
|    break if some_condition
|    # more processing...
|  end
|
|  last_obj = x
|  last_index = i

Yes, they are problems.  With the "solution" described in [ruby-talk:52440],
you have to rewrite them as following respectively.

Quote:
>  0.upto(99) {|x| frame.scroll = x; sleep 0.1}
>  myobj.each_with_index do |x,i|
>    # process...
>    if some_condition    
>      last_obj = x
>      last_index = i
>      break
>    end
>    # more processing...
>  end

                                                        matz.


Tue, 22 Mar 2005 13:39:44 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:

> I've asked this before but can't recall any answers. How would one
> do the following without non-local block params:

> a = [1.1, 3.14, 2.7, 5.15]
> sum = 0.0
> a.each { |elem| sum += a }

Shouldn't it be
 a.each { |elem| sum += elem }

Anyway you aren't using (nor need) non-local block params at all!
You're simply accessing variables from an external scope, which is OK
(how would we get closures otherwise?) and isn't the issue we're to talk about.

The thing is after
 a.each { |elem| sum += elem }
elem will be 5.15 iff elem was already in the external scope, otherwise
it isn't defined.

Compare:
a = [1,2,3,4,5]                         a = [1,2,3,4,5]
sum = 0                                 sum = 0
l = 0                                  
a.each { |l| sum += l }                 a.each { |l| sum += 1 }
# here l == 5                           # l is undefined here!

With local block parameters, you'd get
a = [1,2,3,4,5]
sum = 0
l = "sdfsdfs"
a.each { |:l| sum += 1 }                # I claim this syntax as mine :-)
# l is unchanged here! l == "sdfsdfs"

Quote:
> Personally, I like accessing external scope by default. C behaves similiarly:
> #include <stdio.h>

> int main()
> {
>    int a = 42;
>    int b = 55;

>    printf("a: %d b: %d\n", a, b );

>    {
>            int a = 33; /* define a as local scope to this block*/
>            printf("a: %d b: %d\n", a, b );
>    }
> }

> Gives you
> a: 42 b: 55
> a: 33 b: 55

In C you can shadow external vars because you must declare them anyway.
In Ruby an assignment to a var creates a new one iff there isn't already
one with that name.

--
 _           _                            
| |__   __ _| |_ ___ _ __ ___   __ _ _ __  
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
        Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Absolutely nothing should be concluded from these figures except that
no conclusion can be drawn from them.
        -- Joseph L. Brothers, Linux/PowerPC Project)



Tue, 22 Mar 2005 14:46:26 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:

> I've {*filter*}ised discussion from the "Bugs" thread.  I hope it is a service to
> the community to reopen this.  The poll on RubyGarden votes "make 'em all
> local", closely followed by "leave it unchanged".  Yet the "problem" keeps
> coming up, and the most sensible solution (in my mind) is not represented in
> the poll.

> I think it makes sense to explicitly mark *external* variables, as block-local
> variables (parameters, in fact) would be the norm.

> Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable,
> then one could write

>   collection.each do |a,:b,c|
>     ...
>   end

I hereby claim authorship of any syntax derived from the use of
the ':' prefix to indicate the scope of block parameters, based on
[ruby-talk:52401]. All rights reserved.

:-)

Quote:
> or

>   collection.each do |a,b,c|
>     external b
>     ...
>   end

> I'm not sure which of the above I prefer.  One should optimise for the common
> case.

I'd head towards ':'. Reason: less typing.

just makes sense for me.

Local params would surely be more common, but marking them with ':'
instead of the external ones has the additional advantage of not
breaking any code out there. The transition could be made very easy if
the current scoping rules are mixed with ':' for a while.

So in
   blabla.aaaa do |a,:b|

   end

a is local if there's no variable named 'a' previously defined,
otherwise external

b is local even if there's already 'b' in the external scope

bottom line: nothing breaks, ':' forces local

Ruby can issue a warning iff there was no 'a' variable before, as this
code would break once the old scoping rules are thrown away and only the
presence or absence of ':' is significant.

Quote:
> I'd like to put a question to the audience :) Does anyone actually
> have a need to use non-local block parameters? Ever?

They are indeed needed sometimes.

--
 _           _                            
| |__   __ _| |_ ___ _ __ ___   __ _ _ __  
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
        Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Debian is like Suse with yast turned off, just better. :)
        -- Goswin Brederlow



Tue, 22 Mar 2005 15:20:45 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:

> I hereby claim authorship of any syntax derived from the use of
> the ':' prefix to indicate the scope of block parameters, based on
> [ruby-talk:52401]. All rights reserved.

Request denied. Previous work proves to be quite similar. Plagarist!
[ruby-talk:5555]

Quote:
> :-)

Please refrain from using : in smilies, as authorship has been contested
and await legal decision on the matter.

;-P

Quote:
> I'd head towards ':'. Reason: less typing.

> just makes sense for me.

I like it too, but aparently Matz doesn't. [ruby-talk:42295]

--
(\[ Kent Dahl ]/)_    _~_    __[ http://www.stud.ntnu.no/~kentda/ ]___/~
 ))\_student_/((  \__d L b__/  NTNU - graduate engineering - 5. year  )
( \__\_?|?_/__/ ) _)Industrial economics and technological management(
 \____/_?_\____/ (____engineering.discipline_=_Computer::Technology___)



Tue, 22 Mar 2005 15:40:05 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:
> > Thus, if 'a' and 'c' are regular parameters and 'b' is an external
variable,
> > then one could write

> >   collection.each do |a,:b,c|
> >     ...
> >   end

> I hereby claim authorship of any syntax derived from the use of
> the ':' prefix to indicate the scope of block parameters, based on
> [ruby-talk:52401]. All rights reserved.

> :-)

Fair enough.  Your royalty cheque is in the mail.

Quote:
> > or

> >   collection.each do |a,b,c|
> >     external b
> >     ...
> >   end

> > I'm not sure which of the above I prefer.  One should optimise for the
common
> > case.

> I'd head towards ':'. Reason: less typing.

> just makes sense for me.

Exactly.

Quote:
> Local params would surely be more common, but marking them with ':'
> instead of the external ones has the additional advantage of not
> breaking any code out there.

I disagree.  Marking the external ones rather than internal ones is SO much
more sensible.  Seeing a.each do |:x| everywhere is too ugly.  Changes have
been made that break code before.  How much code would it really break anyway?

Quote:
> The transition could be made very easy if
> the current scoping rules are mixed with ':' for a while.

> So in
>    blabla.aaaa do |a,:b|

>    end

> a is local if there's no variable named 'a' previously defined,
> otherwise external

This sort of confusion is exactly what we want to get away from.

Quote:
> b is local even if there's already 'b' in the external scope

> bottom line: nothing breaks, ':' forces local

> Ruby can issue a warning iff there was no 'a' variable before, as this
> code would break once the old scoping rules are thrown away and only the
> presence or absence of ':' is significant.

Gavin


Tue, 22 Mar 2005 15:44:17 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:

> The "solution" changes time to time in my mind.  Currently I'm
> thinking of the following:

>   * variables assigned by ":=" should be local to the block (or
>     possibly local to the nearest compound statements).

>   * if ":=" assignee is already defined in outer scope, it should be
>     warned (no -w needed, probably), and outer variable is shadowed
>     hereafter.

Then there must be a way to turn these warnings off, because shadowing
outer scope variables would be quite common IMHO.

Quote:
>   * all local variables in block parameters (e.g. var in |var|) should
>     be treated as if they are assigned by ":=".  other types of
>     variables in block parameter should be warned.

What about Hal's
  0.upto(99) {|frame.scroll| sleep 0.1}
example?

Accessors would have to be treated differently (introduces a "special
case" in the language).

Quote:
>   * scope of local variables assigned by "=" will be a nearest "body"
>     (method body, class body etc.) consistently.

> This does not change the appearance of Ruby code much, unlke <var>

It'd make me think of Pascal :-S
Just the thought of such a '{*filter*}-and-discipline" language could
sicken more than one Rubyist :) The "utterly dynamic" vs. "so static
it's useless" contrast would be too much.

:= does change the appearance more than the admittedly more restricted
':' prefix solution.

Quote:
> solution.  It is incompatible to the current syntax, for example,

>    a = 5
>    [1,2,3].each{|a| break if a % 2 == 0}
>    p a

> prints "2" now.  It will print "5" (with shadowing warning) if we
> adopt the changes above.  Since it is not compatible, it will not be
> available in the near future.  Perhaps you have to wait until Rite.

As you say, it also breaks code, which "':' to indicate local" doesn't.

--
 _           _                            
| |__   __ _| |_ ___ _ __ ___   __ _ _ __  
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
        Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Just go ahead and write your own multitasking multiuser os!
Worked for me all the times.
        -- Linus Torvalds



Tue, 22 Mar 2005 15:59:24 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:

> ----- Original Message -----

> > Thus, if 'a' and 'c' are regular parameters and 'b' is an external variable,
> > then one could write

> >   collection.each do |a,:b,c|
> >     ...
> >   end

See my note on this syntax in my original reply to Gavin :-)

Quote:

> One problem is that it's not just a simple variable. It
> can be anything that responds to assignment. For example,
> an accessor:

>   0.upto(99) {|frame.scroll| sleep 0.1}

This works unchanged if you accept ':' as a local scope indicator, only
to be used on variables (not on accesor methods, as it'd be
meaningless), so Ruby would {*filter*}on

  0.upto(99) {|:frame.scroll| sleep 0.1}

as anyway what you really want is

  0.upto(99) {|frame.scroll| sleep 0.1}

Quote:
> > I'd like to put a question to the audience :)  Does anyone actually have a
> need
> > to use non-local block parameters?  Ever?

> The above is an example.

> Also what if I want the last value(s) of a loop?

>   x,i = nil
>   myobj.each_with_index do |x,i|
>     # process...
>     break if some_condition
>     # more processing...
>   end

>   last_obj = x
>   last_index = i

> Yes, I *could* save them off in different variables
> right before I did the break:

>   y,j = nil
>   myobj.each do |x,i|
>    #...
>    if some_condition
>      y,j = x,i
>      break
>    end
>    #...
>   end

>   last_obj, last_index = y,j

> Two more variables and much ugliness. No, thanks.

One more reason to use ':' to indicate local, so the former code runs
unchanged.

--
 _           _                            
| |__   __ _| |_ ___ _ __ ___   __ _ _ __  
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
        Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Not only Guinness - Linux is good for you, too.
        -- Banzai on IRC



Tue, 22 Mar 2005 15:59:40 GMT  
 Specifying local and external block parameters (that old chestnut)

Quote:


> > I hereby claim authorship of any syntax derived from the use of
> > the ':' prefix to indicate the scope of block parameters, based on
> > [ruby-talk:52401]. All rights reserved.

> Request denied. Previous work proves to be quite similar. Plagarist!
> [ruby-talk:5555]

> > :-)

I'm just receiving my first royalty checks. Try to take them from me 8-)
BTW, you'll have a hard time crawling through Spain's judicial system
before you can get a single penny back.

Quote:
> Please refrain from using : in smilies, as authorship has been contested
> and await legal decision on the matter.

> ;-P

No problem. Clemens Hintze granted me long ago an exclusive, unlimited,
world-wide, royalty-free license to use ':'. Talk with your lawyer, for
I suspect *you* will soon receive a cease and desist letter. }:->

Anyway, I hereby claim authorship of the use of any single-character
prefix or suffix, for which no prior art exists, to indicate scoping in Ruby.

Quote:
> > I'd head towards ':'. Reason: less typing.

> > just makes sense for me.

> I like it too, but aparently Matz doesn't. [ruby-talk:42295]

I've just read it but I cannot understand why :-?

--
 _           _                            
| |__   __ _| |_ ___ _ __ ___   __ _ _ __  
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
        Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Less is more or less more
        -- Y_Plentyn on #LinuxGER



Tue, 22 Mar 2005 16:17:25 GMT  
 Specifying local and external block parameters (that old chestnut)
Hi,

In message "Re: Specifying local and external block parameters (that old chestnut)"

|>   * if ":=" assignee is already defined in outer scope, it should be
|>     warned (no -w needed, probably), and outer variable is shadowed
|>     hereafter.
|
|Then there must be a way to turn these warnings off, because shadowing
|outer scope variables would be quite common IMHO.

I'm afraid I won't give you a way to turn it off.  It is "quite
common" in other languages, but it does not mean Ruby must follow.
I believe local variable shadowing is a bad thing.

|>   * all local variables in block parameters (e.g. var in |var|) should
|>     be treated as if they are assigned by ":=".  other types of
|>     variables in block parameter should be warned.
|
|What about Hal's
|  0.upto(99) {|frame.scroll| sleep 0.1}
|example?
|
|Accessors would have to be treated differently (introduces a "special
|case" in the language).

If you read the rule again, you will find the answer.  Accessors are
not local variables, so that they will not be treated by ":=" anyway.
Instead, since they are "other types of variables", you will be warned.

|Just the thought of such a '{*filter*}-and-discipline" language could
|sicken more than one Rubyist :) The "utterly dynamic" vs. "so static
|it's useless" contrast would be too much.
|
|:= does change the appearance more than the admittedly more restricted
|':' prefix solution.

I'm not sure if I get your point.  It will surely change the
appearance. But it changes less than the "<var> solution".

|As you say, it also breaks code, which "':' to indicate local" doesn't.

Yes.  But I feel "':' to indicate local" is ugly.  Many (or most)
people want their block parameters "local to the block".  But "':' to
indicate local" requires additional mark for common case.  "':' to
indicate *external*" is better in this sense, but this also breaks
existing code.

                                                        matz.



Tue, 22 Mar 2005 16:19:50 GMT  
 Specifying local and external block parameters (that old chestnut)


Quote:

> Apologies if this can of worms is better left buried.

> Cheers,
> Gavin

Following up my own post, I now see that it has been discussed extensively in
the past, nothing has happened, Matz has some plans, and we won't see any
change until Rite.  I have no problem with any of that, so I'll let this
sleeping dog lie.

Gavin



Tue, 22 Mar 2005 16:27:10 GMT  
 
 [ 49 post ]  Go to page: [1] [2] [3] [4]

 Relevant Pages 

1. Specifying local and external block parameters (that old ches tnut)

2. Passing a parameter to a specify block ?

3. old 'chestnut' - bar codes on reports

4. A old chestnut? 5.3 v 5.2e

5. File handles - that hoary old chestnut

6. An old chestnut - Random numbers

7. Old chestnut: invariants, pre/post conditions

8. Old chestnut: invariants, pre/post conditions and so on

9. local variable and local variable in block behave differently

10. Specify block path delay statement

11. Need Help with specify block

12. Using parameterizable delays in specify blocks ???

 

 
Powered by phpBB® Forum Software