Fantom是如何出现支持多个后端(.net,JavaScript)的创意的?“在过去的生涯中,我们使用Java构建产品,但是有许多想要将解决方案卖到.NET商店中的问题。因此我们设计了Fantom来同时针对两个生态系统。 而当我们开始开发现在的产品时,我们将Fantom转入一个新的方向,目标是我们运行在JVM上的后端使用一种语言和代码库,而我们的前端运行在 HTML5浏览器上面。多年来,这在目前已经成为了一个非常成功的策略。” Brian Frank, Fantom创始人 标准库/EleganceFantom的身份不仅仅只是基于JVM平台(或者事实上是任何其它的平台)上的一种语言,而它自身更像就是处在JVM之上的一个平台。平台提供了API,而Fantom确保了API的精彩和优雅。在最基础的层面上它提供了几种文法,像下面这样的: - Duration d := 5s
- Uri uri := `http://google.com`
- Map map := [1:"one", 2:"two"]
拥有一个周期文法( duration literal)是它的一个微不足道的小细节,但是当你想要设置一个延时操作的时候,你就能感觉到好像已经有人帮你考虑到了这个场景。IO的API涉及到一些基础的类,如Buf、File、In/OutStreams,它们使用起来令人很愉悦。网络互通功能也提供 了,还有JSON的支持,DOM操作和图形库。重要的东西都为你而存在着。Util这个pod也包含了一些很有用的东西。代替一个拥有main方法的类, 文件服务器扩展了AbstractMain类,并且能自由的传递参数、设置日志。另一个使用起来令人很愉悦的API是Fantom的并发框架,但我们将只 用几分钟来谈论一下它。 互操作(Interop)所有构建于JVM平台之上的语言都提供了一些与原生Java代码协同工作的能力。这对于利用Java的庞大生态系统起到了关键作用。也就是说,要创建一个 比Java好的语言很容易,而创建一个比Java提供的相当得体的互操作更好的语言就难了。那部分归因于对集合的处理(它有点了老旧且平淡,而且有时候使 用起来有点儿痛苦)。 Fantom提供了一个Interop类,它有一个toFan方法和一个toJava方法,用于来回转换类型。 - // socket is java.net.socket
- InStream in := Interop.toFan(socket.getInputStream)
- OutStream out := Interop.toFan(socket.getOutputStream)
这里你可以发现我们有了原生的Java Socket,它自然的为我们提供了Java的Input和OutputStream。 使用Interop将他们转换成与Fantom地位相同,并且稍后就使用它们。 静态和动态类型?另一个任何语言都要审查的主题是这个语言是否提供静态/动态类型的支持。 Fantom在这一点处在中庸的位置,并且我们很喜欢这一点。属性域(Field)和方法带有强静态了性的特性。但是对于本地变量,类型就是被推断出来的。这导致了一种直观的混合,方法约束是被拼凑出来的,但是你也并不需要给每一样事物都赋上类型。 自然的,在Fantom中有两种方法调用操作。点(.)调用需要通过编译器检查并且是强类型的,箭头(->)调用操作则不是。这就从一个动态类型的语言中获得了鸭式类型(duck-typing)还有你想要的任何东西。 不可变性(Immutability)&并发(Concurrency)Fantom提供了一个演员(Actor)框架来处理并发。消息传递和链式异步调用很容纳入代码中。为了创建一个演员(它将由某一种ActorPool支 持,而后通过一个线程池获得),你需要扩展一个Actor类,并且重写(奇怪的是你必须明明白白的给override关键词框定类型)receive方 法。 请注意避免在线程之间分享状态,Fantom将坚持要你只传递不可变的消息给actor。不可变性在设计时就构建到了语言之中,因此你可以构建所有的属性域都是常量的类。编译器将验证为actor准备的消息事实上是不可变的,否则将抛出一个异常。 比较酷,而且难于发现的一点就是,如果你真心需要一个可变的对象,你可以把它封装到一个Unsafe中(不,这不是那个不安全的概念,而是Fantom中的Unsafe). while(true) {
socket := serverSocket.accept
a := ServerActor(actorPool)
//wrap a mutable socket to sign that we know what are we doing a.send(Unsafe(socket))
} 稍后你可以把原来的对象再取回来. override Obj? receive(Obj? msg) {
while(true) {
socket := serverSocket.accept
a := ServerActor(actorPool, socket)
a.send(“handleRequest”)
} // Unsafe is just a wrapper, get the socket
log.info("Accepted a socket: $DateTime.now")
Socket socket := ((Unsafe) msg).val
...
} "你应该考虑吧Unsafe作为最后的杀手锏——因为它会侵蚀Fantom中的整个并发模型.如果你需要传递可变的状态 b/w Actor——你应该使用序列化——它是一个内建的特性: http://fantom.org/ doc/docLang/Actors.html#messages" Andy Frank, Fantom创始人 这意味着,适当的解决方案在这里就会像这样: while(true) {
socket := serverSocket.accept
a := ServerActor(actorPool, socket)
a.send(“handleRequest”)
}
|