Quick introductionの邦訳その2です。
ミックスイン継承
javaと同じように、Ceylon にはクラスとインターフェースがあります。クラスは単一のスーパークラスと任意の数のインターフェースを継承できます。インターフェースは任意の数の他のインターフェースを継承でき、Object 以外の、クラスを拡張することはできません。Java とは異なり、インターフェースは具象メンバを定義することができます。つまり、Ceylon はミックスイン継承(mixin inheritance)と呼ぶ、制限された多重継承をサポートするということになります。
interface Sized {
 
    shared formal Integer size;
 
    shared Boolean empty {
        return size==0;
    }
}
 
interface Printable {
 
    shared void printIt() {
        print(this);
    }
}
 
object empty satisfies Sized & Printable {
 
    shared actual Integer size {
        return 0;
    }
}
Ceylon において、インターフェースとクラスの違いは、インターフェースが状態を持たないことです。つまり、インターフェースは他のオブジェクトの参照を直接持ことはありません。これは、初期化ロジックを持たず、直接インスタンス化されることがないということになります。Ceylon はどんな種類のスーパータイプの「線形化」の実行する必要性を避けています。
多様属性(Polymorphic attributes)
Ceylon には、伝統的な感覚で言うフィールドを持っていません。その代わり属性は多様的で、オブジェクト指向言語におけるメソッソのように、サブクラスにて派生されます。
属性が単純な値である場合は
String name = firstName + " " + lastName;
ゲッターの場合は
String name {
    return firstName + " " + lastName;
}
また、ゲッターとセッターのペアの場合は
String name {
    return fullName;
}
 
assign name {
    fullName := name;
}のようになります。
Ceylon ではクラスの状態は、常にクラスのクライアントから完全に抽象化されるため、つまらないゲッターとセッターを書く必要はありません。
型安全な null と安全な型縮小
Ceylon では NullPointerException やそれに類するものはありません。Ceylon は null と成りうる値やメソッドが null を戻す場合には明示的に宣言することを要求します。例えば、name が null となる場合があれば、次のように宣言しなければなりません。
String? name = ...
この記述は、実際には以下の省略系です。
String|Nothing name = ...
String? 型の属性は、実際にはStringのインスタンスか、null値(Nothing クラスのインスタンスのみ)を要求します。Ceylon は、特別な if (exists ...) 構成を使い、null 値をチェックすることなしには String? 型の値を使うことができません。、
void hello(String? name) {
    if (exists name) {
        print("Hello, " name "!");
    }
    else {
        print("Hello, world!");
    }
}
同様に、Ceylon には ClassCastException もありません。その替りに if (is ...) と case (is ...) により1手順で型の確認と型の縮小化が行えます。実際、前述のコードは、以下の記述のショートカットでもあります。
void hello(String? name) {
    if (is String name) {
        print("Hello, " name "!");
    }
    else {
        print("Hello, world!");
    }
}
列挙サブタイプ(Enumerated subtypes)
オブジェクト指向プログラミングにおいて、型の全てのサブタイプを扱うような長い switch ステートメントを書くことは、たいてい良くない慣習とされています。これは拡張性に欠けてしまうのです。新しいサブタイプを加えると、たちまち switch ステートメントが壊れてしまいます。そのためオブジェクト指向のコードでは、しばしばサブクラスで派生できるように、親クラスに抽象メソッドを使うようにリファクタリングされます。
しかしながら、この種のリファクタリングが適さない種類の問題があります。大抵のオブジェクト指向言語では、この種の問題は visitor パターンを使うことで解決しています。不幸なことに、visitor クラスは switch より冗長であり、クラスの拡張性も犠牲になっています。一方で visitor パターンには大きな優位性があるのも事実であり、新しいサブタイプを加え、visitor に反映を忘れた場合にはコンパイルエラーとして検知できます。
Ceylon はこの2つのジレンマを解消します。親型を定義する時に、サブ型のリストを列挙して指定することができます。
abstract class Node() of Leaf | Branch {}
そして我々は、全ての列挙サブ型を扱う switch文 を書くことができます。
Node node = ... ;
switch (node)
case (is Leaf) { ... }
case (is Branch) { .... }
ここで、Node のサブ型を加えた場合、我々は Node の定義条件を追加しなければならず、新しいサブ型を処理しない全ての switch 文についてエラーを報告します。
blog1.mammb.com
に続く...
