Core_Dumped
Core_Dumped

Reputation: 4699

using apply methods in a Trait in Scala

Depending upon what type of object I pass in X, I need to use the apply methods.I can specify the modifier I want to use(Y or Z). I need to have a syntax of using the 'following' function like this:

(object of type B) following Y

or

(object of type C) following Z

The code looks like this:

trait A 
{
    def following(modifier: X) = modifier(this)
}
case class B() extends A{}
case class C() extends A{}
trait X {}
object Y extends X
{
    apply(obj: B):B = {}
    apply(obj: C):C = {}
}
object Z extends X
{
    apply(obj: B):B = {}
    apply(obj: C):C = {}
}

The compiler gives error in the line where I have implemented the 'following' function. What am I doing wrong?

Upvotes: 1

Views: 6148

Answers (2)

Piotr Kukielka
Piotr Kukielka

Reputation: 3872

I guess what you want is something like that:

    trait X {
        def apply[T](obj: T): T
    }

    trait A {
        def following(modifier: X) = modifier(this)
    }

    case class B() extends A
    case class C() extends A

    object Y extends X {
        override def apply[B](obj: B): B = { obj }
        override def apply[C](obj: C): C = { obj }
    }

    object Z extends X {
        override def apply[B](obj: B): B = { obj }
        override def apply[C](obj: C): C = { obj }
    }

Unlucky I don't think you can have two overrided apply methods and because of that it won't compile. If this is possible, then I will be happy to know as well. What you can do for now is to use one apply method with pattern matching:

    trait X {
        def apply[T](obj: T): T
    }

    trait A {
        def following(modifier: X) = modifier(this)
    }

    case class B() extends A
    case class C() extends A

    object Y extends X {
        override def apply[T](obj: T): T = {
            obj match {
                case o: B => obj
                case o: C => obj
            }
        }
    }

    object Z extends X {
        override def apply[T](obj: T): T = {
            obj match {
                case o: B => obj
                case o: C => obj
            }
        }
    }

You could also get exactly the same effect (including syntax) doing it other way around. In my opinion is much cleaner and easier to understand:

    sealed trait X
    case class Y() extends X
    case class Z() extends X

    trait A[T] {
        def following(modifier: X): T
    }

    case class B() extends A[B] {
        override def following(modifier: X) = modifier match {
            case o: Y => this
            case o: Z => this
        }
    }

    case class C() extends A[C] {
        override def following(modifier: X) = modifier match {
            case o: Y => this
            case o: Z => this
        }
    }

Upvotes: 3

wingedsubmariner
wingedsubmariner

Reputation: 13667

There are several things you are doing wrong:

  1. your apply defintions in Y and Z need to be have def.
  2. trait X needs to have the apply methods defined, though only as abstract methods.
  3. following needs to be overriden in B and C, so that the compiler will know which overloaded method in X to invoke.
  4. following needs to be abstract in A.

You are implementing the Visitor pattern. I suggest finding a copy of the gang of four book, and work from the examples in there.

Upvotes: 1

Related Questions