prafulfillment
prafulfillment

Reputation: 911

Retaining mixin traits with returned value in Scala

We have a Selenium WebElement we're getting from the Java API but we've created a Scala class, Element, and mixin more specific traits (e.g. Clickable, Submittable, etc.).

Our method looks like:

toScalaElement(e : WebElement) = {
   e.type match { 
      case Input => new Element(e) with Submittable
      case Link  => new Element(e) with Clickable
      ...
      case _ => new Element
   }
}

The return type is always Element as that's the root class of all the cases. However, we would like to retain the mixin traits when it is returned.

It was advised to look at builders in Scala's Collections API but we're unsure how that relates to this particular application. Obviously, if there's a better way than traits mixins that solution will be appreciated.

Update: I changed the case to match against sub-types instead of Strings, but essence of question remains unchanged.

Upvotes: 1

Views: 270

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170815

I don't think it's doable. The method as a whole needs to have a single return type. In case of builders, this return type is generic and so can be different between method calls, but the compilers needs arguments to have different types to choose the builder. It looks like this:

case class WebElementConverter[T1, T2](f: T1 => T2) {
  def convert(e: T1) = f(e)
}

object WebElementConverter {
  implicit val inputConverter = WebElementConverter[Input, Element with Submittable](x => new Element(x) with Submittable)
  // other converters
}

def toScalaElement[T1 <: WebElement, T2 <: Element](e : T1)(implicit b: WebElementConverter[T1, T2]) = b.convert(e)

And now you can get desired result here

val i = new Input // same as val i: Input = new Input
toScalaElement(i)

but not here:

val i: Element = new Input
toScalaElement(i) // looks for an implicit WebElementConverter[Element, <some type>]

So if the static type of e is just WebElement, builders don't help.

Upvotes: 2

Luigi Plinge
Luigi Plinge

Reputation: 51109

type is a Scala keyword and although I don't know anything about Selenium, a google of its API shows that there is no type method on WebElement returning a String. So it looks like you're misunderstanding both what the type keyword does, and how pattern matching works. You should look these up, but briefly, if you had a class Input that is a subclass of WebElement, you could match on type with

def toScalaElement(e: WebElement) = e match { 
  case x: Input => new Element(x) with Submittable
  // etc

Upvotes: 0

Related Questions