核心的JRuby开发者及书籍Practical JRuby on Rails Projects的作者Ola Bini为JVM开发了一种名为Ioke的新语言。这种强类型、动态、基于原型的面向对象语言的目标在于给予开发者Lisp与Ruby的力量,同时其拥有优雅、小巧及规则的语法。
\Ola解释了Ioke的基本特性:
\Ioke是一个强类型、动态、基于原型的面向对象语言。它很容易理解并且内置了对几种宏的支持。对Ioke产生重要影响的语言有 Io、 Smalltalk、 Self、 Ruby及 Lisp(尤其是 Common Lisp)。\\Ioke目前构建在JVM上,但我现在正考虑将其编译为JavaScript并在V8上运行它。
\对于Ioke,我有几个目标,但最明确的一个是创建一种能将Ruby和Lisp中我所喜欢的那些特性组合起来的语言。结果我发现Io已经实现了我所期望的大多数特性,但有些地方实现的还不完美。我还需要一种适合表达内部DSLs的语言。我想要一种不会妨碍我,反而会助我完成工作的语言。根据以上几点,我设计出了一个宏系统,有些人可能会觉得这个系统很差劲。
就Ioke的设计InfoQ向Ola Bini提出了几个问题:
\InfoQ:看起来Ioke的关键特性之一就是它使用了基于原型的继承。相比于占主导地位的基于类的继承,你认为这种继承方式更强大么?
\是的,这是Ioke的一个特性,但我不确定它是否是一个关键特性。它在很大程度上改变了一些东西的设计。我对此感到很满意,我认为它实际上比基于类的系统要好,既然开发Ioke的主要目的是为了我自己的使用,那么我的感觉当然就很重要了。\\在Ruby中,你可以使用单例类实现基于原型的OO,同时我发现可以用这种方式清晰地对一些算法建模。从功能上来说这没有什么明显的问题,只要你想,你总可以根据规约实现基于类的OO。
\Ioke的一个主要指导原则是我所采取的决定并不是为了获得大家的认可。仅仅因为基于类的OO占据着主导地位我就要使用它么? 不一定吧。确实有很多原因要求我们使用基于类的OO,然而历史已经证明对很多应用来说这样做的意义并不大。因此在Ioke的开发过程中我尝试了各种可能。
InfoQ:因为在主流的语言中只有JavaScript采取了基于原型的继承,你认为这种形式会被大家所理解并应用到实践中么?
\实际上我认为基于原型的OO要比基于类的OO更自然,也更容易理解。我觉得基于类的OO是需要学习的,而大多数人都会发现基于原型的OO更加直观,前提是他们并没有被人灌输基于类的OO的所谓优点。当然,JavaScript可能并不是最好的参照物,因为语言的基于原型的本质很容易被掩盖在该语言模型的边边角角之下,这意味着大多数开发者实际上并不知道如何以正确的方式使用语言的这些特性。\
InfoQ:看起来Ioke从一开始就被设计成一种JVM语言。你认为在最近一段时期内这会成为新语言的必经之路么?
\我现在的想法是没必要从头构建一个新的虚拟机。例如,大多数新语言都带垃圾回收,但我不理解为什么创建这些新语言的人要编写自己的GC呢。这需要花费数月的时间,而它只是一项重复的工作而已。看看Ruby GC的那些问题吧。显然这种想法对很多其他的事情也适用——尤其是库。因此Ioke是一个JVM语言(但是Ioke的大部分内容是不依赖于JVM的。你可以在另一个平台上重新实现这些内容,这很简单。核心内容非常小)。我认为面向JVM、CLR、Parrott及LLVM的语言都应该这样。从头构建一个新的虚拟机几乎没有任何意义。\
InfoQ:你为Ioke实现的条件(Condition)系统看起来与Java的异常处理系统很相似,但更灵活。你能否提供几个例子来更好的说明其价值呢?
\你可以认为异常所具有的功能是条件系统的一个子集。有两点区别:其一是从协议和抽象的角度来看。异常所处理的东西不见得非得是异常或是错误,警告也行。大多数动态语言都有基于ad-hoc日志的警告系统。但是如果你想做其他事情呢?在Ruby中,你可以改变warn方法以抛出一个异常。然而这仍然表示警告和异常的处理方式存在着分歧。要么采取系统拦截、要么采取线程拦截。所有这一切仅仅是表面上的不同而已,本质上是一回事。\\条件可以将这一切统一起来。他们为上面提到的那些事情提供了一致的协议。
\条件所提供的功能是双重的。首先就是restart,它实际上几乎是完全独立的。
\所谓restart就是可以注册到块中的一些东西。它基本上就是调用restart时所执行的一些代码块。然后有一些方法会去调用命名的restart,找到所有活动的restart。restart几乎可以看作是一种异常机制。从范围上来说它是动态的。
\凭借条件我们可以为某些可能发生的事情注册处理器。当条件发生时,处理器可以选择去处理它或是把它交给下一个处理器处理。然而这并不是堆栈展开(unwinding the stack)(至少现在不是)。如果某个处理器想去处理某个条件(处理器也是一块代码),处理器上下文中相应的代码就会被执行,执行的位置是动态的,就在条件第一次发生的地方。这意味着几个方法从某个条件发生的地方所调用的处理器实际上可以在相应的上下文中进行叠加。
\这没什么好奇怪的,你可以在纯Ruby环境下完成这件事。但如果标准库没有提供相应的支持,那效果就要大打折扣了。
\在Common Lisp中,这非常强大。当你以交互的方式使用Common Lisp时,条件的默认处理器会将你带到调试器中。该调试器运行在错误发生的上下文中,同时它可以完成处理器所能完成的事情——包括为变量提供新的值等等。该调试器无需做任何特别的事情,实际上它只是条件系统一个具体的用例而已。
\这实在是太强大了。
InfoQ:你认为Ioke符合维护和重构的标准么?它是动态的,又具有强类型,你是怎么看的?
\这很难说。既然它很简洁,同时又为这种简洁性提供了强大的特性,那么它应该很容易维护。同样的原因,自动化的重构现在还不完善。\\就像Lisp一样,Ioke提供了语法抽象。有两种形式,第一种是宏,它就像是具有延迟参数的方法调用一样,这些参数可用特殊的方式计算出来。另一种是语法,它与Common Lisp的defmacro差不多。这两种方式为创建新的控制结构和定义新的抽象提供了可能。语言本身是足够强大的,你可以用其创建自己的方法类型。如果你不喜欢关键字参数,你可以定义一种新的不包含关键字参数的方法类型。当前Ioke中的DefaultMethod可以用纯Ioke实现出来,使用宏就行。
InfoQ:对于Ioke的语法来说,你遵循了Lisp和Smalltalk的方式,例如,space的使用。一些人可能会觉得这么做会令那些熟悉C语言代码风格的开发者敬而远之。你觉得是这样的么?
\很早以前我就已经是一个C、C++及Java开发者了,我并没有觉得哪里不舒服。Ioke的语法确实很麻烦,之前有很多人都觉得这对于强大的抽象来说是个绊脚石。当你有一个像以上那些语言的AST时,你会发现要想实现语法宏是多么的不方便。语法占很大的比重,因为他们很不统一。\因此大家可能在一开始会觉得它不那么自然,但我真的很喜欢它,我相信你也会的。比如我发现Ioke的可读性就非常好,而Java就不行了。Ioke中没有太多的标点字符妨碍我们阅读。下面对Java、Ruby及Ioke进行了一下比较:\
\Arrays.asList(\"foo\