Blog Post

#519 Build 1.0.41 (It-Blocks)

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:

// 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:

  • It-Blocks: overview of what it-blocks are
  • This Functions: using |This| to indicate where an it-block is expected
  • With-Blocks: explains how it-blocks are implicitly mapped to Obj.with
  • Const Fields: new rules for how const fields are set within an it-block
  • Collections: how the comma operator works

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:

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

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 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
 //////////////////////////////////////////////////////////////////////////

brian 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.

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.

Login or Signup to reply.