Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
実装継承
実装のために行う継承(情報量増えてないゾ)
実装詳細を持つクラスを、利用したいクラスが継承
親クラスのように振る舞いたいわけではない!
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Java による素朴な例
Confidential
public class Counter { private int counter; public void addCounter() { counter++; } public int getCounter() { return counter; } } public class VisitorsCounter extends Counter { public void visit() { addCounter(); } public int getVisitorsNum() { return getCounter(); } }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Java による素朴な例
問題点 1:実装詳細が外部に公開されてしまう
Confidential
VisitorCounter visitorCounter = new VisitorCounter(); visitorCounter.visit(); visitorCounter.addCounter(); // oops!
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Java による素朴な例
問題点 1:実装詳細が外部に公開されてしまう
問題点 2:意図しない polymorphism
Counter のように振る舞いたいわけではない
Confidential
Counter counter = new Counter(); // ok counter = new VisitorCounter(); // oops!
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Java による素朴な例
問題点 1:実装詳細が外部に公開されてしまう
問題点 2:意図しない polymorphism
問題点 3:複数の実装詳細を同時に扱えない
Java は単一継承のみ、多重継承はない
Confidential
public class Timer { … } public class Counter { … } public class VisitorCounter extends ??? // さてはて…
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
C++ の private/protected 継承
Confidential
class Counter { int counter_ = 0; // C++11 の member initialization public: void add() { counter_++; } int get_counter() const { return counter_; } }; class VisitorsCounter : private Counter { public: void visit() { add(); } int get_visitors_num() const { return get_counter(); } };
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
C++ の private/protected 継承
実装詳細は外部に公開されない
意図しない polymorphism は発生しない
Confidential
VisitorCounter* visitor_counter = new VisitorCounter(); visitor_counter->visit(); // visitor_counter->add(); // error! // Counter* counter = visitor_counter; // error!
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
C++ の private/protected 継承
実装詳細は外部に公開されない
意図しない polymorphism は発生しない
複数の実装詳細を扱える…が、取扱注意
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
C++ の private/protected 継承
問題点:too complex!!!
解決:Java と同様、所有(composition)を利用する
C++ の良いところは、良く考えられていることであり
C++ の悪いところは、良く考えられ過ぎていることである
詠み人知らず
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
実装継承、よりも…
一般的には所有(composition)が望ましい
問題点 1:書くのが面倒…
Confidential
public class Foo { private ImplA implA; private ImplB implB; public Foo() { implA = new ImplA(); implB = new ImplB(); } public void implementedByA() { implA.something(); } public void implementedByB() { implB.something(); } public void implementedByAandB() { implA.something(); implB.something(); } }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
実装継承、よりも…
一般的には所有(composition)が望ましい
問題点 1:書くのが面倒…
問題点 2:実装詳細がカスタマイザブルでない
解決: Dependency Injection(DI)
問題点:書くのが面倒…(二度目)
解決: DI Container
問題点 1: 書くのが面倒(三度目)だし仰々しすぎ
問題点 2: Java 以外であまり流行ってない
結論: Java ダメだこれ
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
他の言語
Eiffel とか Python とか Common Lisp(CLOS) とか
色々な言語毎に、解決方法と問題点がある
このプレゼンはそれを書くにはなんかが少なすぎる
そもそもオブジェクト指向と呼ばれる物が多すぎる!
まとめたら論文にできそう
なんならもうありそう
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotations と trait/mixin
Confidential
trait Counter { private var c: Int = 0 def add() { c += 1 } def get: Int = c } class VisitorsCounter { self: Counter => def visit() { add() } def getVisitors = get }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotations と trait/mixin
trait/mixin とは…?
trait はざっくりいうと実装を持てる Java の interface
abstract class ではないので、複数の trait を継承可能
trait の継承を mixin と呼んだりする
Confidential
trait Counter { private var c: Int = 0 def add() { c += 1 } def get: Int = c }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotation と trait/mixin
self type annotation とは…?
その型の具象的な値に対する型注釈
VisitorsCounter は Counter を継承しなければならない
Confidential
class VisitorsCounter { self: Counter => // this class is `implemented by` Counter! def visit() { add() } def getVisitors = get } // val counter = new VisitorsCounter // error!
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotation と trait/mixin
お節介な型推論に御用心
型推論の方でもちょろっと触れます
Confidential
val counter = new VisitorsCounter with Counter // mixin! ok! …? counter.add() // oops! why is this valid? // counter type is “VisitorsCounter with Counter” // we should annotate type explicitly! val annotated: VisitorsCounter = new VisitorsCounter with Counter // ok! // annotated.add() // error! annotated.visit()
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotation と trait/mixin
複数の class を指定することも可能
正確には高々一つの class と任意個の trait
より正確には class linearization の結(省略されました)
Confidential
class VisitorsCounter { self: Counter with Timer => … }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotation と trait/mixin
とか不要で interface extraction でいいんじゃ?
Java でも解決だよね?
Confidential
trait VisitorsCounter { … } trait Counter { … } trait Timer { … } class VisitorsCounterImpl extends VisitorsCounter with Counter with Timer { … } val counter: VisitorCounter = new VisitorsCounterImpl
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotation と trait/mixin
とか不要で interface extraction でいいんじゃ?
問題点:実装詳細が変わるたびにコードの重複が発生
Confidential
trait PreciseTimer extends Timer { … } class VisitorsCounterImpl extends VisitorsCounter with Counter with Timer { … // implementation } class PreciseVisitorsCounterImpl extends VisitorsCounter with Counter with PreciseTimer { … // code duplication! }
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotation と trait/mixin
trait/mixin なら実装詳細を簡単に変更可能
コードの重複は発生しない
Confidential
class VisitorsCounter { self: Counter with Timer => … } trait PreciseTimer extends Timer { … } class PreciseVisitorsCounter extends VisitorsCounter with Counter with PreciseTimer // no code duplication!
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotation と trait/mixin
実装持ってるもの多重継承して問題ないの?
Class linearization により継承ツリーは linearize される
結果、多重継承のように見えていたものは単一継承になる
Confidential
abstract class AbsIterator { … } trait RichIterator extends AbsIterator { … } class StringIterator extends AbsIterator { … } class Iter extends StringIterator with RichIterator { … } // Iter の継承ツリーは以下のように linearize される // Iter -> RichIterator -> StringIterator -> AbsIterator
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
Scala の self type annotation と trait/mixin
trait は強力な言語機能、他にも色々有用
リッチインターフェースの提供
stackable な open recursion の実現
abstract override なんてニッチなものも…
強力さ故の代償も
Separate Compiliation 的には困った機能
詳細は javap –c すれば分かります。手前味噌ですが参考
Confidential
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/
Scala の言語機能 – 継承による実装
まとめ
Scala では以下の機能により
self type annotation による implemented by の表明
trait/mixin による柔軟な実装の提供
設計意図が伝わり安く、使い安い設計が可能
Java ほど貧弱でなく、C++ ほど複雑でなく
他の言語機能と組み合わせればもっと良くなるよ!
Confidential