RedHatからやってきたAltJava/AltJS言語 Ceylon

Ceylon 1.0.0がリリースされました。 米Red Hat、新言語「Ceylon 1.0」発表、初のプロダクションリリースに | SourceForge.JP Magazine

RedHadがCeylonって言語を作っていることはどこかで読んで知っていました。でも、JVMをターゲットにした言語だし、ウェブサイトトップに載せられているコード例みてもあんまり特徴よくわかんないし、まあありきたりな言語なんじゃないのかな、とか先入観持っていてスルーしてたんですよね……

でもまあ実際仕様見てみると印象変わるもんで、色々な言語から面白い機能取り込んでいて、それを馴染みのある文法で提供してくれているのがよい。

キーワード

キーワードには略語を使わない主義なのがいいですね。IDEとか使っていたら略語を使って短くする理由も薄いし、略語のセンスの差が出ますからね。functionが略されてfuncだとかfunだとかfnだとかになっているの見るとぎょっとしますからね。

Principal typing と union型・intersection型

Principal typing, union types, and intersection types

CeylonはPrincipal typingをやります。

value stuff = { "hello", "world", 1.0, -1 };
value joinedStuff = concatenate({"hello", "world"}, {1.0, 2.0}, {});
          
print(stuff);
print(joinedStuff);

stuffの型は Iterable<String|Float|Integer> という型に、joinedStuffはSequential<String|Float>という型になります。緩いですね。

String|Float|Integerというのはunion型で、StringかFloatかIntegerってことです。で、intersection型はIdentifiable&List<String>みたいな型で、IdentifiableかつList<String>な型ですね。実用言語でこういう型システム持つ今まであっても良かったと思うんだけど、なんでなかったんだろう? 僕が知らないだけかもしれないけど。詳しい人おしえてください。

伝統のC風型記法

型が、C風の記法なんですよ。今どきの若い言語はC離れが進んでいて、HaxeもGoもRustもKotlinもTypeScriptもまあ識別子と型を分離して書くようになりました。そう書くのは実際は変で、本当のところはCが変だっただけで、ようやっとみんなPascalとかMLみたいにちゃんと型は型で別に書くようになりました、マトモになりましたって感じになっているのだけれども、そういう
潮流気にせず、C風の記法なんです。

今のナウい尖端プログラマーは今更Cの型記法はないっしょーとか思うんだろうけど、Principal typingみたいなのを導入していて、それでもC風型記法使うのは、実際のところC風の型記法はそれほど悪くないってことなんじゃなかろうかと思います。C++JavaC#やってきたプログラマーは安心して使えますしね。

でも、C風記法をずっと自然に、一貫性のある形で拡張した感じに見えます。すごい。例えば、関数*1を引数にとる関数はこう書けます。

String find(Boolean where(String string)) {
  ...
}

whereはBoolean where(String string)の形の関数なんですね。まあ今までのC風記法にはなかった表現でしょうけれども。あとは、関数を返す関数。

Boolean greaterThan<Element>(Element val)(Element element)
        given Element satisfies Comparable<Element> =>
                element>val;

これでも別にいいんじゃないですか? 識別子と型を分離して書いちゃうと、識別子と型の対応を追うのが大変になってしまいますし、識別子と型をまぜて書くC風記法もなかなか合理的に思えてきませんか?

デフォルト引数

デフォルト引数も、こんなになってます。

(Product product, Integer quantity=1, Price pricing(Product p) => p.price)

Integer quantity=1ってのはまあ他の言語でもよくあるデフォルト引数ですね。じゃあ、Price pricing(Product p) => p.priceの方、これは見ての通りデフォルト関数です。

この "=" Expression という Specifier と "=>" Expression という LazySpecifier なんですけど、言語の他の部分でもでてきて、型エイリアスの定義も LazySpecifier の方を使うんですけど、使い分けの基準は左辺の識別子が右辺のスコープに入るかどうかみたいです。

ほかにも

なんかまあ仕様をざっと見ただけで全然拾いきれてない。C#のいい文法とか取り入れている部分とかもありますが、他にも面白そうなのありますね。そういう部分もあとでもっと詳しく触れたいです。

*1:Callableインターフェース型の値を便宜的にこう呼びますね。