当你使用Ruby语法,添加静态类型,并在JVM上运行时,发生了什么?Charles Nutter,JRuby的设计师为我们做了展示:
我们很快将有Java 7,支持API的动态调用和改进。我们有很多编程语言可供选择- 一些静态类型,一些是动态类型,...- 这提供了他们自己的独特优势。
我们甚至发现Java本身的一些“小变化“,比如文字列表和字符串开关。我们有任何受管理的Runtime的最大、最强的生态系统,数以百万计的开发者。
但是,缺少了什么东西。没有语言看起来能够取代Java本身。或者说,没有可以充当Java替身。
从Java中学习
让我们看一看标准,我相信我们必须满足替换Java的标准。下面是我的观点,他们都基于大量的使Java获得成功的指导原则。
同等代码下,性能等同于Java
如果我们使用新语言开始写核心库,以及系统级别的代码,它必须像Java做的那样执行准确。我们当然可以尝试更好的表现,但是“等同Java”绝对是最低限度。
没有语言强加的Runtime库
如果使用当前的替代语言的最大的障碍是它们强加于你它们的“锁链”-Runtime库。没有5,10,甚至20M的Jar文件,你写不出"Hello, world" 。复杂的部署,小配置的应用更复杂。甚至更糟糕的,有些语言带有很大的初始化消耗,在加载他们的Runtime的类文件,和/或初始化Runtime状态时。
不要比Java复杂
Java的成功很大程度归功于它的简单。任何语言试图替代它,都要考虑这一点,当然这并不意味着不能比Java强大。
优雅
考虑到所有的积极特征,Java也并不是一个特别美丽的语言。有大量的“仪式“,最简单的程序。类型必须在每个地方声明。少于80个字符根本写不出“Hello,world”,而其他语言可在用20个以下的字符做到。
JVM库的完美整合
取代Java的任何语言必须满足Java的使用案例。这意味着能够定义真正的类,真正的静态方法,真正的数组。从我们的语言到Java,需要被直接调用,使用相同的字节码,并且相比Java编写的同样的调用要更有效率。我们现在使用Java的地方,我们需要使用自己的语言,如果我们不能-我们永远需要堆栈某个地方存在Java。
拓展
现在的语言竞争,要看谁能最简单的设计DSL,谁有最简单的扩展点。扩展Java基本上受限于你可以做什么,用注释和注释处理器。而忘记了有一个灵活的语法 - Java看起来像Java。我们假设的语言需要易于扩展,它需要可以很容易地实验新功能。
是否有可能满足所有这些要求?我相信是的,那就是叫做Mirah的语言。
Mirah 编程语言
Mirah 满足了我的愿望,执行JRuby,对于非Java开发者,更平易近人。让我们面对现实吧,Java并不是特别难学,但有很多细节需要时间来习惯。它不是一个复杂的语言,但它可以吓跑门外汉。Mirah,我想使语言满足我的标准,让我和其他人替换一直想替换的Java。
用代码来解释Mirah更容易理解,看看下面的代码吧!
安装 Mirah
下载最新的zip文件,Mirah Github 下载页面。
你可以在里面找到mirah-complete.jar,一些bin脚本for "mirah" 、"mirahc,",一组案例、说明、协议等。
准备开始
Mirah 有清晰、简单的语法。一些非常美丽,你也会发现它非常接近Ruby。
- puts "Hello, world!"
我们第一个Mriah程序,利用Mirah命令运行。
- ~/projects/mirah_play → mirah -e 'puts "Hello, world!"'
- Hello, world!
这里我们使用-e flag执行一行脚本,也可以放入文件中。
- ~/projects/mirah_play → echo 'puts "Hello, world!"' > hello.mirah
- ~/projects/mirah_play → mirah hello.mirah
- Hello, world!
当然我提到Mirah也是一个编译器。在上面的例子,它在执行前快速编译已有脚本。没有runtime库意味着没有解释,所以所有东西在执行前作为JVM字符码结束。我们使用mirah命令生成类文件:
- ~/projects/mirah_play → mirahc hello.mirah
- ~/projects/mirah_play → ls -l Hello.class
- -rw-r--h;r-- 1 headius staff 505 Mar 19 18:49 Hello.class
- ~/projects/mirah_play → java Hello
- Hello, world!
这个例子可能最重要。不仅是Mirah为一段代码产生了类文件,而且类文件完全独立。最终的java命令不需要jar文件或类路径。你决定什么依赖来引入到你的程序。
让我们浏览一下Mirah的基本语法。
基础语法
Mirah是静态类型,像Java或Scala一样,但你仅是观察也许不知道。这是因为Mirah采用了一种叫做“local type inference(本地类型推断)“的技术。简单来说,通常可以从Mirah的上下文推断对象,变量和方法调用的类型。像Scala和C#中,您仍然必须声明方法参数; Mirah只是在本地范围内推断出类型。
让我们看看在Java中定义一个简单的方法,并对比Mirah。首先,是Java:
- public static String hello(String name) {
- return "Hello, " + name + "!";
- }
Mirah如下:
- def hello(name:String)
- "Hello, #{name}!"
- end
这里我们声明了name变量,作为String。因为仅是一行代码是一String,我们知道返回类型一定是String。
如果我们将它放入一个文件,会得到与使用javac同样的结果。
- ~/projects/mirah_play → cat HelloJava.java
- public class HelloJava {
- public static void main(String[] args) {
- System.out.println(hello("world"));
- }
- public static String hello(String name) {
- return "Hello, " + name + "!";
- }
- }
- ~/projects/mirah_play → cat hello_mirah.mirah
- def hello(name:String)
- "Hello, #{name}!"
- end
- puts hello("world")
- ~/projects/mirah_play → javac HelloJava.java
- ~/projects/mirah_play → mirahc hello_mirah.mirah
- ~/projects/mirah_play → javap HelloJava
- Compiled from "HelloJava.java"
- public class HelloJava extends java.lang.Object{
- public HelloJava();
- public static void main(java.lang.String[]);
- public static java.lang.String hello(java.lang.String);
- }
- ~/projects/mirah_play → javap HelloMirah
- Compiled from "hello_mirah.mirah"
- public class HelloMirah extends java.lang.Object{
- public static void main(java.lang.String[]);
- public static java.lang.String hello(java.lang.String);
- public HelloMirah();
- }
Mirah将脚本顶层作为它的“main”主体,定义的方法转变为同样类的静态方法。这允许你有非常轻型的脚本,很干净,并没有runtime依赖。
使用Java库
一个简单的Swing应用
- import javax.swing.JFrame
- import javax.swing.JButton
- class SwingMirah
- def initialize(title:String, w:int, h:int)
- @title = title
- @width = w
- @height = h
- end
- def run
- frame = JFrame.new @title
- frame.setSize @width, @height
- button = JButton.new "Press me"
- frame.add button
- button.addActionListener do |event|
- JButton(event.getSource).setText "Mirah rocks!"
- end
- frame.setVisible true
- end
- end
- sm = SwingMirah.new("Welcome!", 300, 200)
- sm.run
性能
Mirah与Java的性能对比,使用fibonacci。确实说明两件事:方法调用的性能和整数运算性能- 这都是很难在动态语言进行优化。
- def fib(a:int):int
- if a < 2
- a
- else
- fib(a - 1) + fib(a - 2)
- end
- end
- def bench(n:int)
- n.times do
- timeStart = System.currentTimeMillis
- puts "fib(40): #{fib(40)}\nTotal time: #{System.currentTimeMillis - timeStart}"
- end
- end
- bench 3
最终调用fib(40),打印结果,使用插补字符串,与Java对比如何呢?
- ~/projects/mirah_play → java FibJava
- fib(40): 102334155
- Total time: 883
- fib(40): 102334155
- Total time: 876
- fib(40): 102334155
- Total time: 875
- ~/projects/mirah_play → mirah fib.mirah
- fib(40): 102334155
- Total time: 882
- fib(40): 102334155
- Total time: 876
- fib(40): 102334155
- Total time: 878
Mirah与Java的表现完全一致。
更多来自Java的功能
界面定义:
- import java.util.List
- interface Printer do
- def printAll(a:List)
- returns void
- end
- end
我们执行这个界面与Java类似,使用implements 关键字,然而在Mirah, implements在类的body中。
- class MyPrinter
- implements Printer
- def printAll(a)
- a.each {|element| puts element}
- end
- end
- list = ['foo', 'bar', 'baz']
- p = Printer(MyPrinter.new)
- p.printAll(list)
文字列表和地图使用[] 和{} 语法。
- list = [1,2,3,4]
- list.each {|x| puts x} # prints "1\n2\n3\n4\n"
- map = {'foo' => 'bar'}
- puts map['foo'] # prints "bar"
Mirah,仍然在开发中。但是已经有很多的用户在使用。在Java兼容性方面考虑很有意义。现在Mirah类似于Java 0.9。. 没有泛型或枚举,最小的注释支持,而且大多基本语言功能...但是你有一些封闭的支持,更多的文字量,局部类型推断,等等。我们正在 稳步推进Mirah到1.0版本 ,至少相当于Java 5。我们还将继续改善Mirah的宏观体制和元编程能力,同时认真的从其他的语言中吸取最酷的功能。