hoodwink.d enhanced
RSS
2.0
XHTML
1.0

RedHanded

Block and Lambda #

by babie in inspect

This entry is a loose summary of Matz blog : 2005-06-30 , 2005-07-01 , 2005-07-21 , 2005-07-22 . And this entry is related to Ruby 2.0 block local variable and Function Call .

Matz has been thinking about new syntax of block paremter and lambda expression. As it stands, we can’t use same syntax in block parameter as in method parameter. So he has some ideas, but he is not satisfied with these ideas.

We can write block parameters like this now:
hash.each { |k,v| v ||= "none"; ... }
Following examples mean the same.

1. Anonymous function like Perl6

This syntax came from Perl6:
for list -> x { ... }
Perl6 has a near cultural sphere to Ruby, so he think it’s well to refer Perl6. But he worry whether Perl6 will be released or not and whether this syntax will be adopted in Perl6 or not.
hash.each -> (k,v="none") { ... }
This syntax is so-so in block because It reminds him of a substitution. But when in lambda expression:
proc = -> (x, y) { ... }
Hmmm, it doesn’t look like a function.

2. Other sign

hash.each \(k,v="none") { ... }
In Haskell, back-slash sign means lambda because of form likeness. A matter is a back-slash sign displays as yen-sign by font environment. In lambda case:
proc = \(x, y) { ... }
In Ruby, it look like a parenthesis escaped.

3. Double back-slash

hash.each \\(k,v="none") { ... }
It’s lack of visual hint.
proc = \\(x, y) { ... }
He thinks better than one back-slash case. He is worried by the same reason of font as one back-slash, too. He thinks he should lays special emphasis on lambda expression, because main dissatisfaction was an inconsistency that a syntax of lambda’s parameters is different from syntax method’s parameter in the begining.

Though he will not choice below ideas probably, I introduce.

4. New keyword

hash.each { using k,v="none"; ... }

5. Extend lambda

hash.each(&lambda(k,v="none") { ... })

He leaned toward an example like Perl6 and had done at his local repository, but he wavers yet. He wants a good idea which fulfill below condition:

  • It’s able to express anonymous function.
  • It puts in front of paraemters.
  • It’s good mix of sign which have not been used until now.
  • Many people feel comfortable (if possible).

What do you think?

said on 27 Jul 2005 at 16:56

I mean, we all want to write

hash.each { |k,v="none"| ... }

don’t we? Is it really not possible to prefer the block-variable-| over the bit-or-| in parsing? Maybe there are other difficulties, but the only thing I see is that with this syntax you couldn’t write

hash.each { | k, v = k|0 | ... }

so bitwise-or wouldn’t be available in block variables or something. (After the =, an expression should be allowed, including method calls, class definitions and, of course, bitwise or.)

But where’s the problem? If you really come across such a thing, just write

hash.each { | k, v = (k|0) | ... }

and the parser should be happy. You have to do this often in Ruby to make things clearer to the parser. This is also compatible to today’s syntax, doesn’t change much, and seems intuitive to me.

Maybe I don’t understand the real problem – could someone please explain? (Or translate matz’ blog for me – WHY did I learn French in school instad of Japanese??? 9_9)

Another idea, because I like keywords: extended do-end:

hash.each with k, v="none" do ... end

So weird things are only allowed in with … do … end.

said on 27 Jul 2005 at 17:09

Oh, I just discovered that in with…do…end, the do could become optional: You could use with like you use def:

  # normal function
  def print2 k, v = 'none'
    p '%10s: %p' % [k, v]
  end

  # anonymous block
  hash.each with k, v = 'none'
    p '%10s: %p' % [k, v]
  end

  # lambda
  printer = lambda with k, v = 'none'
    p '%10s: %p' % [k, v]
  end

If you worry about one-liners now, just use do as you did before:

  # as one-liner
  hash.each with k, v = 'none' do p [k, v] end

What about leaving {...} as it is, and extending do…end to with…do…end?

said on 27 Jul 2005 at 17:38
I have to say, I’m not particularly keen on any of the 5 options. Like murphy said, what we all really wish we could have is:
hash.each { |k,v="none"| ... }
So… my vote is for whatever it takes to get us the syntax we want in the first place. If the only obstruction is that bitwise-or operations need to be clarified with parens, then I think that’s a small price to pay for the nicer aesthetics…
said on 27 Jul 2005 at 17:41
Oh, and if that weren’t bad enough, I even prefer
hash.each { |k,v| v ||= "none"; ... }
over any of the other 5 options suggested.

Although admittedly, the fifth wouldn’t bother me nearly as much as the previous four.

said on 27 Jul 2005 at 19:09
I agree with murphy, we want to have:

hash.each { |k,v="none"| ... }

If you want to do an OR inside of the goal posts ’| |’ you need to surround it with ‘(’ and ‘)’ – I don’t see this as being a big problem. It seems to be the least disruptive approach.

If I have to pick one of the five options above, I prefer #5. However, what would that mean for anonymous code blocks? (I’m guessing it would look like the Perl6 example, but without the ’->‘).

Why is the extra arrow needed in the Perl6ish-way shown in #1? If you get rid of the arrow wouldn’t you essentially have the same thing as #5?

said on 27 Jul 2005 at 19:43

Totally agree with sporkmonger. I’d much prefer to have the syntax we actually want, and if it’s not possible, the current way.

said on 27 Jul 2005 at 19:50

1+ for keeping the current goal post syntax.

said on 27 Jul 2005 at 22:24

Dear murphy,

No, we don’t. Leave it alone. It doesn’t look any better or clearer to me. In fact it looks worse.

And, if your object doesn’t already have a default value, or the capability of having a default value, then you’ve probably screwed up long before you reach this point.

I’m not sure how Matz got it in his head that block parameters and method parameters should work the same. They’re different, mmkay?

Note to Ruby community: stop obsessing over blocks and procs. I don’t want the syntax wrecked over some misguided notion of block/lambda/method unification.

P.S. Hash.new(“none”)

said on 27 Jul 2005 at 22:39
I’m with you guys on this syntax, it looks great to me:

hash.each { |k,v="none"| ... }

Is the whole problem really the ambiguity with the bit-wise or? Seems like a lot of trouble to change a common case (blocks) to save a rare case (bit-wise or). There must be something else that matz is trying to step around…must be… But if matz is really considering all those other ways, here are some more crazy ideas (some not-so-serious):

proc = <k,v="none">  { ... } # hmmmm...won't work
proc = &(k,v="none") { ... } # maybe...
proc = ~(k,v="none") { ... } # we lose bit-wise not, boo-hoo, big deal
proc = (k,v="none")  { ... } # I'm sure there's some reason we can't to this one
proc = |k,v="none"|  { ... } # Same problem as the current favorite

I’m all out.

said on 27 Jul 2005 at 22:44

Those < and > looked great in the preview…sorry everyone. Hey _why, something to look at: < and > in the preview don’t show up, but they do when the post is committed.

said on 27 Jul 2005 at 23:41

You are all tied up into being comfortable by avoiding change. Change is good. It keeps you on your toes to perform your best. I personally like the \() syntax.

said on 27 Jul 2005 at 23:43

I feel like this is trying to solve a problem that doesn’t (or barely) exist.

Both of these options look and feel like Ruby:


hash.each { |k,v| v ||= "none"; ... }
hash.each { |k,v="none"| ... }

The rest feel (as the parent post notes their origins) like other languages entirely. The syntax of Ruby should to continue to adhere to POLS .

said on 27 Jul 2005 at 23:50

Hi, all! Matz said that it’s too difficult to write a ”|” operator in present block because of parser(yacc).

Hi Dan. There is samples used various characters at Sasada’s diary .

said on 28 Jul 2005 at 00:51

yep. I don’t want to introduce new syntax if we could implement optional arguments in the goal posts. I’m waiting for some super YACC guru.

hmm, “goal posts”, I like the name.

said on 28 Jul 2005 at 00:58

Along the Perl6 line of thought this seems simpler:

method(x,y) { a,b="none" -> ... }

But the one that seems most intuitive to me is:

method(x,y) { (a,b="none") ... }

But that might have some parsing problems itself, does it? Of course one could just use backslash in place of pipes.

method(x,y) { \a,b="none"\ ... }

That should work without ambiguity. On the otherhand I find the last notation using the lambda interesting. Might we not just drop the word “lambda” and use only the & to do:

method(x,y) &(a,b="none"){ ... }

2c.

said on 28 Jul 2005 at 01:38

Matz: Maybe it’s because it’s not a currently available feature, but I don’t think I’ve ever needed a default-valued argument for a block. What is the problem we’re trying to solve with the proposed changes?

said on 28 Jul 2005 at 05:48

My knowledge of lex/yacc is very poor, but I know the problem of ambiguous symbols. A solution is, for example: Ruby scans a ”+” either as plus or as tUPLUS, depending on some lex_state.

To parse | correctly, we need a stack, because a block can contain expressions with |-op, but also more blocks that contain |-ops etc. Maybe it is enough to keep track of all opened parentheses to decide about ”|”:
  • if the last was a “{”, it is a block parameters delimiter
  • if it was a “(” or none, it is bit-or.

So it could be solved one the lexer level.

Has someone described the parsing problem in English yet? Where it lies exactly?

Another idea is maybe to use the semicolon:

array.map { |foo = 15; foo * 2 }

But that would interfere with the new block variables section.

said on 28 Jul 2005 at 06:02

I’m not much of a YACC /LEX guru. But doing the nice syntax one would require infinite lookahead no? I don’t see how that could be done with YACC . Isn’t it possible to switch to a more sophisticated parser with backtracking, infinite lookahead or something like that? I think (not sure) there are some free ones that have that and are based on YACC .

The proposed syntaxes do like kind of weird… Number four seems clean to me but loses the brevity Ruby has on this right now.

said on 28 Jul 2005 at 06:06

Here at the TU-Berlin we have opal , and they define lambdas with \\x,y. or \\_ .

Jut my 0.2 Cent

said on 28 Jul 2005 at 06:50

I don’t like the proposed syntaxes either. I guess adding a lot of syntax to the language for a feature that I’m not sure I’ll even use doesn’t seem like a good tradeoff that way. That way lies madness. And perl.

said on 28 Jul 2005 at 06:54

phil: I know, I was wondering that myself. To be honest, even if the current syntax were maintained, I can’t think of any good reason I would want or need to use optional parameters in a block. So I have to ask, is the point of all of this just to blur the line between blocks and methods for the sake of it, or do we have some more practical purpose for all of this?

said on 28 Jul 2005 at 07:10

I just noticed something else that’s nice about this notation:

method(x,y) &(a,b="none"){ ... }

It slips right into the parameter list:

method(x,y,&(a,b="none"){ ... })

That’s a plus.

said on 28 Jul 2005 at 07:16

On the otherhand, why not deprecate the | operator in favor of ^? Double-bar || could remain b/c it would be unambigious.

said on 28 Jul 2005 at 07:29

On the otherhand, why not deprecate the | operator in favor of ^? Double-bar || could remain b/c it would be unambigious.

And deprecate ^ in favor of what then?

said on 28 Jul 2005 at 08:00

If anyone actually reads this far down, I advocate the conservative approach of leaving well enough alone unless we get |k,v='none'|.

I’d rather write v ||= 'none' on the next line and keep my backwards compatibility than rewrite my existing code so I can have a different syntax for functionality that I rarely use (or have seen others use for that matter).

Wouldn’t you like to be able to use Ruby 2.0 right away? :)

said on 28 Jul 2005 at 09:13

Here is a syntax which is a mix between substitution syntax and the one in point 5:

list.each((x,y)->{...}) and proc = ((x,y)->{...})

’# Can double parns signify a block or/and lambda without parsing problems?

said on 28 Jul 2005 at 09:29

There is information in the FAQ about weird results with puts caused by the parser which baffles new users. We now have this. There have been other issues (I forget what) which have been constrained by the parser. I would suggest that serious thought should be given to re-working the parser before re-working the syntax. YACC is fairly old technology now, there are GLR parsers, and probably other things I am unaware of. [Disclaimer, my ability to write parsers has proved particularly weak, so I claim no expertise]. Surely There’s A Better Way To Do It, isn’t there?

said on 28 Jul 2005 at 09:51

For what it’s worth, I like the current syntax because it’s clear where those variables go. They are inside the block, which makes sense to me. If we really have to change it. I guess I would prever the (x,y)->{...} because it gives the notion of x and y injecting into the block. (x,y){...} in all it’s forms just doesn’t flow to me, it’s a lot more effort for me to parse it. Does anyone else feel the same?

said on 28 Jul 2005 at 11:01

I like murphy’s with…do…end idea, but I think I’m the only one. Of all the options, it’s the only one that makes the sense at-a-glance about what’s going on.

Then again, I never really liked the goal posts – they always strike me as a quirky hack.

said on 28 Jul 2005 at 11:25

And deprecate ^ in favor of what then?

Well, given how rare it is, #xor would probably do, but never fear ^^ is here.

(P.S. Ironically I was looking a MathWorld site and ^ is more akin to symbol used for AND . Go figure!)

said on 28 Jul 2005 at 11:53

For what it’s worth, I agree with you, Dave. I like with (arg=0) do … end.

Especially because it can be used in semantic analogy to def. I am a little curious about how it would work in terms of zero argument blocks.
array.each with do 
  count+=1
end
looks a little weird.

On the other hand, I’ve come to love the goal posts as a quirk of Ruby. I suspect that, the same way that, by convention, one line procs are {} and multi lines are do…end, mutlilines will become with () end, and oneliners will become {|| }.

said on 28 Jul 2005 at 12:34

with … do is my favorite next to goalposts. I imagine with zero-argument blocks you’d omit the with. No arguments to do it with after all.

with … do really is the best of the alternatives; I hope matz is following the thread…

said on 28 Jul 2005 at 16:22

The haskell lambda example given is for a uncurried (tupled) anonymous function. It is not required that the anonymous function be written that way.

\x y → x + y

which is just shorthand for

\x → \y → x + y

said on 28 Jul 2005 at 23:36

It didn’t take me too long to extend RubyLexer to get default parameters in blocks working the in murphy’s preferred way. I don’t really speak yacc, and the algorithm isn’t a simple one to implement by itself, since the right-hand-side of the default parameter needs to be able to be (almost) any ruby expression.

said on 28 Jul 2005 at 23:44

Matz, what are the chances of using RubyLexer in the ruby interpreter? ;)

said on 29 Jul 2005 at 05:00

some examples are here: http://pub.cozmixng.org/~the-rwiki/rw-cgi.rb?cmd=view;name=Ruby2.0BlockParameterNotation

said on 30 Jul 2005 at 18:23

I like the pascaliness in with … do but that’s just the little Wirth in me

said on 31 Jul 2005 at 06:01

I really like Trans’ first example:

f = { x, y → x + 2 * y }

f[1, 2] # => 5

g = { → :constant }

g[] # => :constant

h = { → }

h[] # => nil

It looks almost like the mathematical way to define functions. It should be easy to parse this with YACC , or do I miss something?

said on 31 Jul 2005 at 12:56

I too see limited usage of default variables in block arguments, but if we MUST have them, I agree with Murphy: rewrite the parser until something like

hash.each { |k, v = (k|0)| ... }

is possible.

All of the proposed syntax changes are ugly and involve too much typing for something that SHOULD be as simple as possible. Ruby has got this right and no other language does—let’s not break that now.

said on 03 Aug 2005 at 01:25

Can we have our lambdas with curry… please???

said on 03 Aug 2005 at 11:26

What stands in the way of

hash.each { (k, v = 12) ... }

which is nicely similar to

def name(k, v=12)
end
with
  • def → {
  • name → theres none, its anonymous
  • (k, v=12) → (k, v=12)
  • end → }

PS: I’m, sure I missed something

said on 04 Aug 2005 at 11:50

I like murphy’s suggestions as well, including the with keyword. I don’t think I’ve done enough ruby to know how useful default params in blocks would be… but it seems like a reasonable compramise to keep the goalposts as is, and force those who need defaults to use the with form.

I don’t like the way any of the 5 proposals look. Assuming it’s a rarely used syntax, like the generally delimited input, I don’t see how it would hurt anything to use the double slash though.

said on 04 Aug 2005 at 11:58

I like the with [do] end syntax … but I think this would be a good place for list comprehensions like python

why not just turn #each into

for k,v=None in hash
  # do stuff
end

or

for key in hash.keys
  # do stuff
end

then they add some cool optional conditionals … very cool stuff.

for k,v in hash if k != "blah" 
  # do stuff.
end
said on 05 Aug 2005 at 03:19

@Matz: A YACC alternative is www.antlr.org & xpa.sf.net. BTW , the best compiler technology available is OCAML ; see www.ocaml-tutorial.org and for an example mtasc.org. The Perl 6 VM is based on Haskell, cf. www.pugscode.org.

said on 05 Aug 2005 at 12:22

@Jo: Pugs is “only” a bootstrap compiler for Perl 6. The final compiler will be written in either Perl 6 or a subset of it aimed specifically at compiler production. That’s the plan, anyway.

What does that have to do with OCaml, anyway? :)

I’ve always hated the goalposts in Ruby, in addition to the complete lack of English similarity.

foo.each do |elem| ... end

That simply does not read naturally to an English reader (which I’m not, incidentally, but close enough to feel the syntax odd.)

for foo -> elem do ... end

That’s my preferred syntax, but it really is rather unrubyish, I guess. But then again, I don’t like the Ruby idiom of .each in the first place.

I prefer list -> elem over elem in list because I consider the list to be more important than the iterator element.

said on 05 Aug 2005 at 14:21

@wolverian: Pugs 6.2.8 ff. is intended to become a full-fledged Perl6 compiler. I’ve even read that Pugs might one day even be capable of producing Perl6 code. – Haskell is a very good compiler language . . . and so is www.ocaml.org. Would be cool to know if Autrijus also took a deeper look into the alternative!

said on 06 Aug 2005 at 00:55

@Jo: Yes, but it’s not meant to become the reference implementation. Sorry, this is OT discussion, really. :)

said on 06 Aug 2005 at 08:27

For those interested in more information on Perl6 issues & discussions see: www.sidhe.org/~dan/blog/ (Dan Sugalski, developer of Parrot) and the Periodic Table of the Perl6 Operators over at www.ozonehouse.com/mark/blog/. To compare code in terms of readability you also might want to ckeck out such sites as pleac.sf.not or www.talkaboutprogramming.com. In Perl5, e.g., you have the foreach-loop pattern that first names the iterator and then the list: foreach $variable (@array) ...

said on 06 Aug 2005 at 10:31

@sam12: Dan Sugalski is not a Parrot (lead or otherwise) developer anymore, he gave off the hat to Chip Salzenberg. He was never a Perl6 developer, although certainly Parrot and Perl6 are related.

said on 07 Aug 2005 at 15:39

But what about the block problem?

said on 09 Aug 2005 at 02:53

I dunno – while my experience with Ruby is very (very!) limited, and while the “goalpost” notation still feels wierd, both of murphy’s suggestions seem to feel consistant. Personally, I like the verbosity of with..[do]..end, but I can see the reason in the “extended goalpost” notation. The other options just felt wrong. That’s all I can say.

said on 09 Aug 2005 at 08:25

Maybe it’s better to talk here: comp.lang.ruby

By the way, the whole thing is just for lambdas; matz won’t change normal block syntax.

said on 10 Aug 2005 at 04:10

An improved parser may do the trick: allow more code syntax options, protect against ambiguities, ... (see above). However, I’m wondering if a preprocessor could do the trick as well (cf. man perlfilter; for a Ruby preprocessor example see rubystuff.org). @wolverian: perl6.concat(parrot); parrot.concat(perl6), ... or just understand Perl6 as an umbrella word for both Perl6- and Parrot-related issues!

said on 12 Aug 2005 at 23:11

@sam12: You mean “perl6” ~ “parrot”, right? ;) Anyway, thanks for the clarification. Being involved in the process makes me differentiate between these things more than the someone outside, I guess.

said on 05 Sep 2005 at 08:10

A full C parser written in OCaml that modifies the lexer while parsing is the C Intermediate Language (manju.cs.berkeley.edu/cil/). Would be cool to have such a thing for Ruby as well (in addition see rockit.sf.net and merd.sf.net for Ruby; and the OCaml preprocessor by martin.jambom.free.fr/ocaml.html).

said on 05 Sep 2005 at 11:09

Jo, you’ve overlooked this one: nekovm.org

Comments are closed for this entry.