Tutorial_7

「Tutorial_7」の編集履歴(バックアップ)一覧はこちら

Tutorial_7 - (2007/11/16 (金) 08:27:01) の1つ前との変更点

追加された行は緑色になります。

削除された行は赤色になります。

*7 Mixins Apart from inheriting code from a super-class, a Scala class can also import code from one or several mixins. Maybe the easiest way for a Java programmer to understand what mixins are is to view them as interfaces which can also contain code. In Scala, when a class inherits from a mixin, it implements that mixin’s interface, and inherits all the code contained in the mixin. To see the usefulness of mixins, let’s look at a classical example: ordered objects. It is often useful to be able to compare objects of a given class among themselves, for example to sort them. In Java, objects which are comparable implement the Comparable interface. In Scala, we can do a bit better than in Java by defining our equivalent of Comparable as amixin, which we will call Ord. When comparing objects, six different predicates can be useful: smaller, smaller or equal, equal, not equal, greater or equal, and greater. However, defining all of them is fastidious, especially since four out of these six can be expressed using the remaining two. That is, given the equal and smaller predicates (for example), one can express the other ones. In Scala, all these observations can be nicely captured by the following mixin declaration: trait Ord { def < (that: Any): boolean def <=(that: Any): boolean = (this < that) || (this == that) def > (that: Any): boolean = !(this <= that) def >=(that: Any): boolean = !(this < that) } This definition both creates a new type called Ord, which plays the same role as Java’s Comparable interface, and default implementations of three predicates in terms of a fourth, abstract one. The predicates for equality and inequality do not appear here since they are by default present in all objects. The type Any which is used above is the type which is a super-type of all other types in Scala. It can be seen as a more general version of Java’s Object type, since it is also a super-type of basic types like int, float, etc. To make objects of a class comparable, it is therefore sufficient to define the predicateswhich test equality and inferiority, and mix in the Ord class above. As an example, let’s define a Date class representing dates in the Gregorian calendar. Such dates are composed of a day, a month and a year, which we will all represent as integers. We therefore start the definition of the Date class as follows: class Date(y: int, m: int, d: int) extends Ord { def year = y def month = m def day = d override def toString(): String = year + "" + month + "" + day The important part here is the extends Ord declarationwhich follows the classname and parameters. It declares that the Date class inherits from the Ord class as amixin. Then, we redefine the equals method, inherited from Object, so that it correctly compares dates by comparing their individual fields. The default implementation of equals is not usable, because as in Java it compares object physically. We arrive at the following definition: override def equals(that: Any): boolean = that.isInstanceOf[Date] && { val o = that.asInstanceOf[Date] o.day == day && o.month == month && o.year == year } This methodmakes use of the predefined methods isInstanceOf and asInstanceOf. The first one, isInstanceOf, corresponds to Java’s instanceof operator, and returns true if and only if the object on which it is applied is an instance of the given type. The second one, asInstanceOf, corresponds to Java’s cast operator: If the object is an instance of the given type, it is viewed as such, otherwise a ClassCastException is thrown. Finally, the last method to define is the predicate which tests for inferiority, as follows. It makes use of another predefined method, error, which throws an exception with the given error message. def <(that: Any): boolean = { if (!that.isInstanceOf[Date]) error("cannot compare " + that + " and a Date") val o = that.asInstanceOf[Date] (year < o.year) || (year == o.year && (month < o.month || (month == o.month && day < o.day))) } This completes the definition of the Date class. Instances of this class can be seen either as dates or as comparable objects. Moreover, they all define the six comparison predicates mentioned above: equals and < because they appear directly in the definition of the Date class, and the others because they are inherited from the Ord mixin. Mixins are useful in other situations than the one shown here, of course, but discussing their applications in length is outside the scope of this document.
*7 Mixins 7 ミックスイン Apart from inheriting code from a super-class, a Scala class can also import code from one or several mixins. スーパークラスからコードを継承する以外にも、Scalaでは1つあるいは複数のミックスインでコードをインポートできます。 Maybe the easiest way for a Java programmer to understand what mixins are is to view them as interfaces which can also contain code. In Scala, when a class inherits from a mixin, it implements that mixin’s interface, and inherits all the code contained in the mixin. Javaプログラマにとってミックスインが何かを理解する一番簡単な方法は、コードを含むことも可能なインターフェイスと看做すことでしょう。Scalaでは、あるクラスがミックスインから継承した場合、そのミックスインのインターフェイスを実装し、そのミックスインのコードも全て継承します。 To see the usefulness of mixins, let’s look at a classical example: ordered objects. It is often useful to be able to compare objects of a given class among themselves, for example to sort them. In Java, objects which are comparable implement the Comparable interface. In Scala, we can do a bit better than in Java by defining our equivalent of Comparable as amixin, which we will call Ord. ミックスインの有用性を見る為に、古典的な例である、順序付きオブジェクトを見てみましょう。あるクラスのオブジェクト同士を比較することが出来ると、例えばソートしたりする場合など、しばしば役に立ちます。Javaでは、比較可能なオブジェクトはComparableインターフェイスを実装します。Scalaでは、Comparableの同等品をOrdと呼ぶミックスインを定義することで、Javaよりもう少しうまくやります。 When comparing objects, six different predicates can be useful: smaller, smaller or equal, equal, not equal, greater or equal, and greater. However, defining all of them is fastidious, especially since four out of these six can be expressed using the remaining two. That is, given the equal and smaller predicates (for example), one can express the other ones. In Scala, all these observations can be nicely captured by the following mixin declaration: オブジェクトを比較するには、6つの異なる述語、小さい・小さいか等しい・等しい・等しくない・大きいか等しい・大きい、があると便利です。しかしそれらの全てを定義するのは冗長に過ぎます。なぜなら6つのうちの2つを使って残りの4つは表せるのですから。例えば、等しいと小さいの2つの述語があれば、他を表すことが出来ます。Scalaでは、これらの事柄は次の様なミックスインを定義することで満たされます。 trait Ord { def < (that: Any): boolean def <=(that: Any): boolean = (this < that) || (this == that) def > (that: Any): boolean = !(this <= that) def >=(that: Any): boolean = !(this < that) } This definition both creates a new type called Ord, which plays the same role as Java’s Comparable interface, and default implementations of three predicates in terms of a fourth, abstract one. The predicates for equality and inequality do not appear here since they are by default present in all objects. この定義によって、JavaのComparableインターフェイスと同じ役割をするOrdと呼ばれる型を作ると共に、抽象的な述語1つを用いて3つの述語のデフォルト実装が行われます。等しい・等しくないという述語は、全てのオブジェクトにデフォルトで存在するため、ここには現れません。 The type Any which is used above is the type which is a super-type of all other types in Scala. It can be seen as a more general version of Java’s Object type, since it is also a super-type of basic types like int, float, etc. 上の例で使われているAny型はScalaの全ての型のスーパータイプの型です。JavaのObject型より更に一般的といえます。なぜならば、intやfloatといった基本型のスーパータイプでもあるからです。 To make objects of a class comparable, it is therefore sufficient to define the predicateswhich test equality and inferiority, and mix in the Ord class above. As an example, let’s define a Date class representing dates in the Gregorian calendar. Such dates are composed of a day, a month and a year, which we will all represent as integers. We therefore start the definition of the Date class as follows: 従って、比較可能なクラスのオブジェクトを作る為には、等しいことと小さいことを判定する述語を定義し、上で述べたOrdクラスをミックスインすれば充分です。例として、グレゴリア暦の日付を表すDateクラスを定義してみましょう。そのクラスは、全て整数値である日・月・年で構成されます。従ってDateクラスの定義は次の様になります。 class Date(y: int, m: int, d: int) extends Ord { def year = y def month = m def day = d override def toString(): String = year + "" + month + "" + day The important part here is the extends Ord declarationwhich follows the classname and parameters. It declares that the Date class inherits from the Ord class as amixin. ここで重要なことは、クラス名とパラメタに続くextends Ord宣言です。これによってDateクラスがOrdクラスをミックスインとして継承することが宣言されます。 Then, we redefine the equals method, inherited from Object, so that it correctly compares dates by comparing their individual fields. The default implementation of equals is not usable, because as in Java it compares object physically. We arrive at the following definition: そして、Objectから継承しているequalsメソッドを再定義し、個々のフィールドを比較することで正しく日付を比較する様にします。equalsのJavaでのデフォルト実装はオブジェクトを物理的に比較するため使えません。下記の様な定義になります。 override def equals(that: Any): boolean = that.isInstanceOf[Date] && { val o = that.asInstanceOf[Date] o.day == day && o.month == month && o.year == year } This methodmakes use of the predefined methods isInstanceOf and asInstanceOf. The first one, isInstanceOf, corresponds to Java’s instanceof operator, and returns true if and only if the object on which it is applied is an instance of the given type. The second one, asInstanceOf, corresponds to Java’s cast operator: If the object is an instance of the given type, it is viewed as such, otherwise a ClassCastException is thrown. このメソッドでは予め定義された、isInstanceOfとasInstanceOfというメソッドを使用しています。最初のisInstanceOfは、Javaのinstanceof演算子に対応しており、適用されたオブジェクトが与えられた型のインスタンスである場合にのみ真を返します。2つめのasInstanceOfは、Javaのキャスト演算子に対応します。もしオブジェクトが与えられた型のインスタンスであるならばそのように観られるようになり、さもなければClasscastExceptionが投げられます。 Finally, the last method to define is the predicate which tests for inferiority, as follows. It makes use of another predefined method, error, which throws an exception with the given error message. 最後に下記の様に、小さいことを判定する述語を定義します。別の予め定義されたメソッドであるerrorを使います。errorは与えられたエラーメッセージ付きの例外を投げるメソッドです。 def <(that: Any): boolean = { if (!that.isInstanceOf[Date]) error("cannot compare " + that + " and a Date") val o = that.asInstanceOf[Date] (year < o.year) || (year == o.year && (month < o.month || (month == o.month && day < o.day))) } This completes the definition of the Date class. Instances of this class can be seen either as dates or as comparable objects. Moreover, they all define the six comparison predicates mentioned above: equals and < because they appear directly in the definition of the Date class, and the others because they are inherited from the Ord mixin. これでDateクラスの定義が完了しました。このクラスのインスタンスは日付であり比較可能オブジェクトでもあります。更に、上で述べた6つの比較用の述語が定義されています。equalsと < はDateクラスの定義の中に直接現れており、他はOrdミックスインから継承しています。 Mixins are useful in other situations than the one shown here, of course, but discussing their applications in length is outside the scope of this document. ミックスインがここで示したよりも有用な状況があるのは勿論ですが、そういった例を長々と議論するのはこの文書の目的外から外れています。 ---- #comment()

表示オプション

横に並べて表示:
変化行の前後のみ表示:
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。