Fanx的闭包不是DSL

很多人看到这样的示例代码,以为是什么DSL。

using vaseGui

class HelloTest
{
  static Void main() {
    root := Frame {
      VBox {
          Label { text = "HelloWorld" },
          Button {
            text = "Press Me"
            onClick {
              Toast("Hello World").show(it)
            }
          },
      },
    }
    root.show
  }
}

事实上这不是DSL,而是标准的Fanx代码。

Fanx语言中写出上面的代码,使用了几个重要的技术:It块、尾缀闭包、with块、逗号操作符。这里的设计非常巧妙。比Kotlin用更少的复杂性和更少的代码,实现了类似的功能。

尾缀闭包

正常的Fanx闭包/lambda是这样的:

10.times( |Int x| { echo(x) } )

我们在函数最后一个参数为闭包时省略调圆括号,叫做尾缀闭包。写成这样:

10.times |Int x| { echo(x) }

It块

10.times |Int x->Void| { echo(x.isEven) }

当闭包参数少于一个时,我们省略函数参数,使用时用it关键字代替。变成了这样:

10.times { echo(it.isEven) }

it也可以省略,就像this一样的省略

10.times { echo(isEven) }

所以可以这样写

Button { it.text = "hi" }
Button { text = "hi" }

逗号操作符

我们的运算符重载大概是这样的语法糖

a + b       =>    a.plus(b)

加号都可以是运算符,逗号也类似。不过逗号运算符被设计为需要和It块配合。

a,b,c       =>    it.add(a).add(b).add(c)

With块

所有对象都有一个with方法。with定义在Obj中,Obj.with像这样:

virtual This with(|This| f)
{
  f(this)
  return this
}

使用with函数像这样

list := [,].with { fill("x", 3) 

我们可以省略with名称,写出这样:

list := [,] { fill("x", 3) }

揭晓谜底

VBox {
  Label { .. },
  Button { .. },
}

这样的代码大概相当于

VBox().with( |VBox v| {
  v.add( Label().with( |Label a| {
    ...  
  }))
  v.add( Button().with( |Button b| {
    ... 
  }))
})

可见编程语言对可读性的改善的重要性。

Fanx中的DSL

Fanx中也有DSL的术语,但指的是编译插件。例如正则表达式和SQL这种叫做DSL。正则表达式的DSL长这样

reg := Regex<|\(.*\)|>

这是一个编译器插件,可做内嵌语言的语法错误检测、IDE语法高亮。DSL中可以有任何字符,免去了字符串内部字符需要转意的麻烦。

更多关于Fanx的信息见:

你可能感兴趣的:(java,android)