第一回社内 scala 勉強会(一部抜粋)その 2

23
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/ Scala の言語機能 継承による実装 実装継承 実装のために行う継承(情報量増えてないゾ) 実装詳細を持つクラスを、利用したいクラスが継承 親クラスのように振る舞いたいわけではない! Confidential

Upload: lyricallogical

Post on 29-Nov-2014

957 views

Category:

Documents


3 download

DESCRIPTION

 

TRANSCRIPT

Page 1: 第一回社内 Scala 勉強会(一部抜粋)その 2

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 継承による実装

実装継承

実装のために行う継承(情報量増えてないゾ)

実装詳細を持つクラスを、利用したいクラスが継承

親クラスのように振る舞いたいわけではない!

Confidential

Page 2: 第一回社内 Scala 勉強会(一部抜粋)その 2

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(); } }

Page 3: 第一回社内 Scala 勉強会(一部抜粋)その 2

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!

Page 4: 第一回社内 Scala 勉強会(一部抜粋)その 2

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!

Page 5: 第一回社内 Scala 勉強会(一部抜粋)その 2

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 ??? // さてはて…

Page 6: 第一回社内 Scala 勉強会(一部抜粋)その 2

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(); } };

Page 7: 第一回社内 Scala 勉強会(一部抜粋)その 2

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!

Page 8: 第一回社内 Scala 勉強会(一部抜粋)その 2

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 継承による実装

C++ の private/protected 継承

実装詳細は外部に公開されない

意図しない polymorphism は発生しない

複数の実装詳細を扱える…が、取扱注意

Confidential

Page 9: 第一回社内 Scala 勉強会(一部抜粋)その 2

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 継承による実装

C++ の private/protected 継承

問題点:too complex!!!

解決:Java と同様、所有(composition)を利用する

C++ の良いところは、良く考えられていることであり

C++ の悪いところは、良く考えられ過ぎていることである

詠み人知らず

Confidential

Page 10: 第一回社内 Scala 勉強会(一部抜粋)その 2

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(); } }

Page 11: 第一回社内 Scala 勉強会(一部抜粋)その 2

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

Page 12: 第一回社内 Scala 勉強会(一部抜粋)その 2

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 継承による実装

他の言語

Eiffel とか Python とか Common Lisp(CLOS) とか

色々な言語毎に、解決方法と問題点がある

このプレゼンはそれを書くにはなんかが少なすぎる

そもそもオブジェクト指向と呼ばれる物が多すぎる!

まとめたら論文にできそう

なんならもうありそう

Confidential

Page 13: 第一回社内 Scala 勉強会(一部抜粋)その 2

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 }

Page 14: 第一回社内 Scala 勉強会(一部抜粋)その 2

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 }

Page 15: 第一回社内 Scala 勉強会(一部抜粋)その 2

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!

Page 16: 第一回社内 Scala 勉強会(一部抜粋)その 2

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()

Page 17: 第一回社内 Scala 勉強会(一部抜粋)その 2

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 => … }

Page 18: 第一回社内 Scala 勉強会(一部抜粋)その 2

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

Page 19: 第一回社内 Scala 勉強会(一部抜粋)その 2

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! }

Page 20: 第一回社内 Scala 勉強会(一部抜粋)その 2

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!

Page 21: 第一回社内 Scala 勉強会(一部抜粋)その 2

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

Page 22: 第一回社内 Scala 勉強会(一部抜粋)その 2

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

Page 23: 第一回社内 Scala 勉強会(一部抜粋)その 2

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