Beautiful Syntax, Faster Than Go
它和 Mirah, JRuby, Groovy 等等的区别是: 它不需要 JVM 这个平台, 没有字节码和解释器. 很容易在速度上超过这些 JVM 语言.
同样是编译成 LLVM IR 再到机器码, 和 Ruby Motion 的区别是: Ruby Motion 依赖 ObjC 运行时, 而 Crystal 不依赖
除了编译外, 和 Elixir 的区别还有: 它的语法和 Ruby 很相似, 所以 Crystal 编译器可以直接用 Crystal 和 Ruby 的交集写, 然后用 Ruby 执行编译自己, 就轻松完成了 bootstrap. 它的语法对熟悉 Ruby 的人更有亲和力, 所以 Matz 率先捐了 $500.
所以你看, 虽然现在还在 Alpha 阶段, 还是很有存在意义的.
Crystal 还有一些与众不同的特性:
面向对象类型推导
在一些静态类型系统上结合 FP 和面向对象的尝试中, 例如 Scala 中, 推导仅局限于方法内部. 而 Crystal 没有这个限制, 它会尽量修改类型定义以满足使用需要
举个栗子:
class Person
getter name
def initialize @name
end
end
daisy = Person.new "Daisy Johnson"
chappie = Person.new 22
puts daisy.inspect
puts chappie.inspect
使用 hierarchy 命令查看类图
$ crystal hierarchy person.cr
...
+- class Person (24 bytes)
| @name : (String | Int32) (16 bytes)
...
可以看到 Person 的 name 属性的类型自动变成了 String | Int32
if 表达式类型推导
和 Ruby 一样, Crystal 的 if 语句有返回值, 是表达式. 但 if 表达式在很多静态语言中的使用却不那么便利, 一个巨大问题就是编译器不能根据条件去做推断, 例如:
val a = if (args.length > 0) { "string" } else { 42 } // a 的类型是 Any
if (a.isInstanceOf[String]) {
println(a.length) // 编译错误, Any.length 没定义, 得手动强转
}
而 Crystal 的类型推断会考虑条件中的 is_a? 和 responds_to? 信息, 减少了繁琐的强制转换:
a = ARGV.size > 0 ? "string" : 42
if a.is_a? String
# 这里 a 的类型是 String
puts a.size
else
# 这里 a 的类型是 Int32
puts a / 2
end
Nil 的处理
在静态类型语言中, 有的编译器默认允许 nil/null, 那么就会抛出 NPE (NullPointerException), 有的编译器会在类型上禁止一些 nil/null 的存在, 并鼓励用 Maybe/Option 去装箱/拆箱. 前一种方法很容易出错, 后一种方法使用繁琐 (尤其在不支持 do notation 的语言中). 而 Crystal 结合数据流分析, 对 nil 值的处理更加简单优雅. 文档里的例子如下:
a = some_condition ? nil : 3
# a is Int32 or Nil
if a
# Since the only way to get here is if a is truthy,
# a can't be nil. So here a is Int32.
a.abs
end
不过为了线程安全, 非局部变量不推荐这么做
if @a
@a.abs # 如果编译器分析出 @a 可以赋值 nil, 就会出编译错误
end
上面的代码可以加锁, 或者改写成局部变量判断的方式
if a = @a
a.abs # 别的线程就改不了局部变量啦
end
和 Ruby 一样, 由于 Nil 上可以定义方法, 所有值都自然变成 Maybe Monad 了, 上面的代码也可以改成用 try 去处理
@a.try do |a|
a.abs
end
在 responds_to 的情形, 会出现这类代码 pattern
if (a = @a).responds_to? :size
a.size
end
不那么静态
从上面可以看到, 和一般的静态语言相比, Crystal 的一个局部变量的类型并不是固定的
a = 32 # 现在 a 的类型是 Int32
a.abs
a = "foo" # 现在 a 的类型是 String
a.length
在 while 循环中, 编译器会做更复杂的事情, 尽量不让类型成为阻碍编程的限制, 以下例子出自 Crystal 博客:
a = 1
while some_condition
a # here a is Int32 or String or Bool
if some_other_condition
a = "hello" # we next, so in the next iteration a can be String
next
end
a = false # here a is Bool
end
a # here a is Int32 or String or Bool
来自知乎
http://www.zhihu.com/question/33311554
--- (未完待续)