2013-01-05 6 views
6

私は抽象基底クラス(Base)にいくつかのスタッキング特性が定義されています(StackingTrait)。スカラ:抽象基底クラスを持つTrait Mixin

trait Base { 
    def foo 
} 
trait StackingTrait extends Base { 
    abstract override def foo { super.foo } 
} 

次の構文を使用してサブクラスを実装するのに非常に便利であるが、コンパイラは、fooが、その後overrideとして宣言する必要があると言うので、これは動作しないため、無効である再コンパイル、上abstract overrideImplはクラスです。

class Impl extends Base with StackingTrait { 
    def foo {} 
} 

私は、このような構文が禁止されるだろう正当な理由を考えることができません。 fooは論理的にImplで定義されているため、概念的にスタッキングが発生する順序付けは同じです。

注: この回避策は効果的に私が望むのと同じことを実行するとわかりましたが、ヘルパークラスが必要なため、より良い解決策が必要になります。

class ImplHelper extends Base { 
    def foo {} 
} 
class Impl extends ImplHelper with StackingTrait 

なぜ、目的の構文がコンパイルされず、優雅な解決策がありますか?

答えて

4

私の理解では、エラーメッセージが混乱する可能性がありますが、動作は正しいです。 fooStackingTraitabstract overrideとして宣言され、従って、StackingTraitを混合する任意の具象クラスで(線形順序に対して)StackingTraitfooの具体(abstractとしてマークされていない)の実装が存在しなければなりません。これは、superが線形化の順序で直前の特性を参照しているため、具体的な実装がfooであることが前提であり、StackingTraitが混在する前に間違いがあります。これを行うと

: - StackingTrait <からImpl

class Impl extends Base with StackingTrait { 
    def foo {} 
} 

線形順序はBase <です。 StackingTraitの前の唯一の特性は、fooの具体的な実装を定義していません。BaseBaseです。

しかし、ときにこの操作を行います。

traitImplHelper extends Base { 
    def foo {} 
} 
class Impl extends ImplHelper with StackingTrait 

線形順序は次のようになります。Base <からImplHelper <からStackingTrait <からImpl ここImplHelperfooの具体的な定義が含まれており、間違いなくStackingTraitです。

StackingTraitclass Impl extends StackingTrait with ImplHelperのように)の後にImplHelperを混在させると、同じ問題が発生し、コンパイルに失敗します。

だから、これは私にとってかなり一貫しています。 私はあなたが意図したとおりにコンパイルする方法を知らない。しかし、BaseまたはStackingTraitを書きやすくするよりも、Implを書きやすく(別のクラス/特性を必要とせずにfooを定義することができます)、さらにこれを行うことができれば、これでも構いません。

trait Base { 
    protected def fooImpl 
    def foo { fooImpl } 
} 
trait StackingTrait extends Base { 
    abstract override def foo { super.foo } 
} 

class Impl extends Base with StackingTrait { 
    protected def fooImpl {} 
} 

元のバージョンと同じように、具体的なクラスごとにfoofooImplの形式)を実装し、今度はコンパイルします。 ここでの欠点は、fooImplsuper.fooを呼んではいけませんが(意味がなく、無限ループに入ります)、コンパイラは警告しません。

+0

偉大な答え!このまさにこのシナリオについての質問を投稿しようとしていました。ありがとう! –

+0

私もこの問題に遭遇しました。線形化はこれについて最終的には正しいですが、私は、形質を積み重ねるという現実世界の目的がこれであることを認識しました:共通の抽象クラス/形質の既存の具体的な実装にのみスタッキング特性を変更することができます。つまり'抽象クラスList'と' Mod Mod extends List'を持っています。あなたは単に 'class Foo extends Mod with List'を書くことはできません。まず 'class LinkedList extends List'のように具体的なListを持たなければならないので、' Class Bar extends Moded with LinkedList'を書くことができます。希望は意味をなさない。 –

+0

忘れてしまいましたが、これは 'abstract override'メソッドの特徴だけが明確であることに関係しているということを忘れてしまいました。そのような方法がなければ、形質を自由に混在させることができるようです。 –

関連する問題