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