0

I am trying to use Scala's cake pattern with generic interceptors with multiple groups (layers) of those. When end of one layer needs another layer I try to express that using self type. But it fails with Illegal inheritance. The general context of the task is I have a document model on which I am trying to do chain of validations. Toy example follows with each layer represented by just one trait.

trait Element trait Leaf extends Element trait Composed extends Element trait Validator [A] {def validate (element : A) : String} //second layer trait LeafValidator extends Validator[Leaf]{ override def validate (element : Leaf) : String = "leaf"} //first layer trait ElementValidator extends Validator[Element]{ self : Validator[Leaf] => override def validate (element : Element) : String = element match { case leaf : Leaf => super.validate(leaf) case _ => "other" } } case class Concrete extends LeafValidator with ElementValidator 

The error is on the instantiation line

illegal inheritance; self-type apltauer.david.util.Concrete does not conform to apltauer.david.util.ElementValidator's selftype apltauer.david.util.ElementValidator with apltauer.david.util.Validator[apltauer.david.util.Leaf] Main.scala /Dependency/src/apltauer/david/util line 56 Scala Problem

Contravariance supresses the error but does not solve the problem as the self type is useless then.

7
  • This is not a cake pattern, your just using self-type annotation. I would recommend using composition here instead. Commented Mar 24, 2013 at 21:02
  • It will be cake pattern as soon as I expand those layers into multiple traits. Maybe the information about the cake pattern is not so important actually. I appreciate different design proposals but I would still like to resolve the mystery. Commented Mar 24, 2013 at 21:07
  • 2
    A given class can not implements a (non-variant) interface parameterized with two different type: Foo can not extend Bar[A] and Bar[B] at the same time. Commented Mar 24, 2013 at 21:29
  • But Foo can include two different Bar, Foo { val barA: Bar[A]; val barB: Bar[B] } <-- this is composition Commented Mar 24, 2013 at 21:30
  • I am not sure what the actual question is. Commented Mar 24, 2013 at 21:35

1 Answer 1

0

I had the same problem. The use of two variants of features breaks the (otherwise, nice and useful) cake pattern.

So I developed an enhancement, which, concerning my problem, allowed me to keep the cake pattern intact, and which I call the Feature Pattern. In your case:

trait element_validator extends validator[Element] { final override val element_validator = this } trait feature_element_validator { val element_validator : element_validator } /* Analogous for “Leaf” */ trait validator[element_type] { final override val validator = this /* Feature code here: */ def validate(element: element_type) = /* … */ } trait feature_validator[element_type] { val validator : validator[element_type] } 

So now one could say:

object component extends element_validator with leaf_validator with other_cake_feature_1 with other_cake_feature_2 with other_cake_feature_3 /* etc. */ 

Inside component one would distinguish the two kinds of validator:

element_validator.validate(…) leaf_validator.validate(…) 

If only one requires, then import (which has the same effect as using the self-type-annotation for availability of names):

import element_validator._ validate(…) 

I know, it is quite some boilerplate. I didn't, however, see any other solution for that than to combine cake with composition (whenever composition would be necessary).

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.