With my wife and kids away this week, I had the most intense week of coding in my life. The result is the latest build with full support for it-blocks and closure type inference.
It-Blocks
It-blocks have been implemented pretty much exactly like the original proposal. If you have existing code using with-blocks, they will need to be turned into it-blocks...
If you were using with-blocks to shadow local variables or slots on this, you will need disambiguate them. If you receive a "Self Assignment" compiler error you most likely have this situation:
// old code which used to work
text := "hello"
Label { text = text }
// new code
Label { it.text = text }
If you receive an "Ambiguous slot on both this and it" error you most likely have this situation:
Label { text = text } // old code implicitly bound rhs to this
Label { it.text = this.text } // need to make it explicit
With the new changes, add is not implicit anymore. Instead you have to use the comma operator. If you were using adds with a constructor you will receive a "Not a statement" compiler error. Otherwise you will have to manually track it down:
// old code
GridPane
{
Label { text = "Sarah" }
Label { text = "Connor" }
}
// new code
GridPane
{
Label { text = "Sarah" },
Label { text = "Connor" }, // trailing comma is optional
}
If you were using with-blocks to set const fields on your own classes, you will need to add a constructor to your class which takes an it-block. It-blocks may set const fields on it, but there are checks at runtime. You will know if you have this problem if you see ConstErrs being thrown at runtime.
It-blocks are now first class closures so you can pass them as true functions. See the following updated documentation:
As part of the it-block refactoring, I added support for closure type inference. Closures can now be declared with only their parameter names, and have the types inferred from the method being called:
list := ["Jack", "Sayid", "Ben"]
list.each |Str v, Int i| { echo("$i: $v") } // old verbose syntax
list.each |v, i| { echo("$i: $v") } // closure type inference
list.each { echo(it) } // it-block
You can also use closure type inference either with a return type or have the return type inferred:
list.sort |Str a, Str b->Int| { a.size <=> b.size } // old verbose syntax
list.sort |a, b->Int| { a.size <=> b.size } // inference with return type
list.sort |a, b| { a.size <=> b.size } // inferred return type
This is a really sweet feature because it lets you remove a lot of noise from your code. See docLang for the details.
Other Breaking Changes
There are a couple of other associated breaking changes - see change log below.
Change Log
Build 1.0.41 (11 Apr 09)
It-Blocks
Comma operator for it.add
Closure type inference
Require return expr to be on same line
Duration: minVal, maxVal
Move jfan to sys/java; nfan to sys/dotnet
Change exclusive range from "..." to "..<"
Disallow it-block: Point, Size, Rect, Insets, Hints
Require it-block: Font
Rename def => defVal: Point, Size, Rect, Insets, Hints, Pen
Rename Locale.with => use
tompalmerSat 11 Apr 2009
Very nice.
JohnDGSun 12 Apr 2009
Great stuff. Especially love the new closure type inference!
wangzaixiangSun 12 Apr 2009
Very interesting features!
tacticsSun 12 Apr 2009
I found a small bug. In a static context, the compiler can flag an expression as ambiguous, even though there is never a this in a static context.
This code under the latest release fails with a this-vs-it ambiguity error, even though i ought to be inferred as it.i.
class Acme
{
Int i
static Void main()
{
test := Acme { i = 0 }
echo(test.i)
}
}
I threw this patch together and ran the test suite. Everything came out fine, save for a single Flux test, FindInFilesTest, which was failing before I made this change.
diff -r c8746a4f8376 src/compiler/fan/util/CallResolver.fan
--- a/src/compiler/fan/util/CallResolver.fan Sat Apr 11 10:09:07 2009 -0400
+++ b/src/compiler/fan/util/CallResolver.fan Sun Apr 12 15:49:58 2009 -0500
@@ -221,6 +221,14 @@
private Bool isAmbiguous(CSlot? a, CSlot? b)
{
+ // if we're in a static context, we use 'it'
+ if (curType.isClosure)
+ {
+ closure := curType.closure
+ if (closure.enclosingSlot.isStatic)
+ return false
+ }
+
// unless we found on both base and baseIt, it is not ambiguous
if (a == null || b == null) return false
And here is a test for this corner case.
diff -r c8746a4f8376 src/testCompiler/fan/ItBlockTest.fan
--- a/src/testCompiler/fan/ItBlockTest.fan Sat Apr 11 10:09:07 2009 -0400
+++ b/src/testCompiler/fan/ItBlockTest.fan Sun Apr 12 14:34:18 2009 -0500
@@ -376,6 +376,27 @@
}
//////////////////////////////////////////////////////////////////////////
+// Distinguishing 'it' vs 'this' in a closure in a static method
+//////////////////////////////////////////////////////////////////////////
+
+ Void testDistinguishInStatic()
+ {
+ compile(
+ "class Acme
+ {
+ Int i
+ static Void main()
+ {
+ test := Acme { i = 0 }
+ }
+ }"
+ )
+
+ obj := pod.types.first.make { it->i = 0 }
+ verifyEq(obj->i, 0)
+ }
+
+//////////////////////////////////////////////////////////////////////////
// ConstErr
//////////////////////////////////////////////////////////////////////////
brianSun 12 Apr 2009
I found a small bug. In a static context, the compiler can flag an expression as ambiguous, even though there is never a this in a static context.
Thanks much - I think that seems right, I'll take a look at getting your patch integrated - but it probably won't be until next week - I am traveling this week.
brian Sat 11 Apr 2009
With my wife and kids away this week, I had the most intense week of coding in my life. The result is the latest build with full support for it-blocks and closure type inference.
It-Blocks
It-blocks have been implemented pretty much exactly like the original proposal. If you have existing code using with-blocks, they will need to be turned into it-blocks...
If you were using with-blocks to shadow local variables or slots on
this
, you will need disambiguate them. If you receive a "Self Assignment" compiler error you most likely have this situation:If you receive an "Ambiguous slot on both this and it" error you most likely have this situation:
With the new changes, add is not implicit anymore. Instead you have to use the comma operator. If you were using adds with a constructor you will receive a "Not a statement" compiler error. Otherwise you will have to manually track it down:
If you were using with-blocks to set const fields on your own classes, you will need to add a constructor to your class which takes an it-block. It-blocks may set const fields on
it
, but there are checks at runtime. You will know if you have this problem if you see ConstErrs being thrown at runtime.It-blocks are now first class closures so you can pass them as true functions. See the following updated documentation:
|This|
to indicate where an it-block is expectedObj.with
Closure Type Inference
As part of the it-block refactoring, I added support for closure type inference. Closures can now be declared with only their parameter names, and have the types inferred from the method being called:
You can also use closure type inference either with a return type or have the return type inferred:
This is a really sweet feature because it lets you remove a lot of noise from your code. See docLang for the details.
Other Breaking Changes
There are a couple of other associated breaking changes - see change log below.
Change Log
Build 1.0.41 (11 Apr 09)
tompalmer Sat 11 Apr 2009
Very nice.
JohnDG Sun 12 Apr 2009
Great stuff. Especially love the new closure type inference!
wangzaixiang Sun 12 Apr 2009
Very interesting features!
tactics Sun 12 Apr 2009
I found a small bug. In a static context, the compiler can flag an expression as ambiguous, even though there is never a
this
in a static context.This code under the latest release fails with a this-vs-it ambiguity error, even though
i
ought to be inferred asit.i
.I threw this patch together and ran the test suite. Everything came out fine, save for a single Flux test, FindInFilesTest, which was failing before I made this change.
And here is a test for this corner case.
brian Sun 12 Apr 2009
Thanks much - I think that seems right, I'll take a look at getting your patch integrated - but it probably won't be until next week - I am traveling this week.