#508 It-Block Add

brian Mon 6 Apr 2009

I've gotten most of the code base switched from with-blocks to it-blocks. However I am at a bit of a roadblock regarding how to handle the implicit add inside of with-blocks. There is a ton of code using this feature, so it isn't easy to work past.

Previously any expression which wasn't an assignment was assumed to be either a call on the with-block target or an implicit add. That worked ok because with-blocks weren't actually closures, and had a very limited internal grammar.

Now it-blocks are general purpose closures and can contain any statement. So we can't just implicitly assume any expression with a non-Void result should be blindly added to the it parameter.

So I think it is a requirement that add is somehow explicitly declared. The way we have talked about this in the past is using the comma as a postfix operator.

I propose that comma is treated as syntax sugar for it.add:

a,     =>  it.add(a)
a,b    =>  it.add(b).add(b)
a,b,   =>  same as above
a,b,c  =>  it.add(b).add(b).add(c)

Note that a comma separated list of expressions is parsed as a single expression by chaining the add call. That simplifies the compiler and management of the stack.

It isn't the greatest solution because it requires you add a weird trailing comma:

GridPane { Label { text="hi" }, }

But it does give you the syntactic power to create custom collection literals. So seems like a reasonable trade-off.

andy Mon 6 Apr 2009

I'm not crazy about it, and seems like an common mistake to leave off. But to avoid the method call, you would have to have some type of prefix/suffix, so the comma probably makes the most sense. I could live with it unless someone floats a better solution, which we really haven't been able to come up with yet.

jodastephen Mon 6 Apr 2009

My preference has been a general append operator, as seen in other languages:

list.add(a).add(b)

list << a << b

In general, I wouldn't expect to see this have too wide a use. However, it-blocks are just a special case then:

GridPane { << Label { text="hi" } }

Or, you could just go with the method call:

GridPane { add Label { text="hi" } }

Whatever the choice, I think the comma suffix is way too easy to forget, and far too subtle to read.

brian Mon 6 Apr 2009

Whatever the choice, I think the comma suffix is way too easy to forget, and far too subtle to read.

Remember that any syntax we choose for the language will be mimicked in the serialization syntax. While I don't love the comma, the more verbose syntaxes take away Fan's clean JSON-like serialization syntax.

JohnDG Mon 6 Apr 2009

But it does give you the syntactic power to create custom collection literals. So seems like a reasonable trade-off.

I like the comma. It's a single character and it's already used for list construction in nearly all languages. Plus, like you say, it allows custom collections.

brian Tue 7 Apr 2009

One of the subtle changes I made related to this feature is that now I report a stand alone constructor call as a "Not a statement" error. This will allow the compiler to catch the common case when you forget a comma. The only reason to allow constructors to be stand alone statements is if your ctor has side effects (which seems like something to prevent anyhow).

I also added a compiler check for when you attempt to assign the same variable to itself. This catches the other case it-blocks reveal:

x := 5
Foo { x = x }     // now illegal
Foo { it.x = x }  // required syntax if locals hide this/it

That is actually a really nice error - I've definitely hit that in Java where I do something like this:

// self assignment b/c of typo on param name
Foo(int someVarx) { this.someVar = someVar } 

cheeser Tue 7 Apr 2009

what about

y := 5
Foo { x = y }

Is that still legal without the it qualifier?

tactics Tue 7 Apr 2009

I think a prefix operator might be a good idea. Maybe * instead of <<, which makes it look like a bulleted list.

GridPane 
{ 
  * Label { text="hi" } 
  * Text {}  
}

For multiple add statements on a single line, you could use a single bullet with commas:

GridPane 
{ 
  * Label { text="hi" }, Text {}  
}

brian Tue 7 Apr 2009

Is that still legal without the it qualifier?

The it qualifier is only required in the same circumstances as this - only when a local variable hides a slot name. So if your case, assuming y was neither a slot on this nor it, then no qualifiers are required. The twist from Java is really that you implicitly scope the slots on both it and this.

I think a prefix operator might be a good idea. Maybe * instead of <<, which makes it look like a bulleted list

I have already implemented using the comma - it actually looks pretty good.

Login or Signup to reply.