Is there any way of calling scala method (having type parameter ) with infix notation

138 views Asked by At

I have a piece of code in implicit class -

implicit class Path(bSONValue: BSONValue) {
      def |<[S, T <:{def value:S}] = {
        bSONValue.asInstanceOf[T].value
      }

} 

The problem is if I want to call |< method after BSONValue I need to call with . . e.g

(doc/"_id").|<[String,BSONString]

The problem is without . scala raises error because it does not allow type parameter method with infix notation. So always I have to wrap doc/"_id" portion with (). Is their any way of using type parameter method without . eg

doc/"_id"|<[String,BSONString]
1

There are 1 answers

0
Andrey Tyukin On BEST ANSWER

All types T that you want to get out of BSONValues will probably have a companion object with the same name. You could use that companion object as an intuitive placeholder for the type that you actually want to get. Something along these lines:

trait Extract[A, BComp, B] {
  def extractValue(a: A): B
}

implicit class Extractable[A](a: A) {
  def |<[BC, B]
    (companion: BC)
    (implicit e: Extract[A, BC, B])
  : B = e.extractValue(a)
}

implicit def extractIntFromString
  : Extract[String, Int.type, Int] = _.toInt

implicit def extractDoubleFromString
  : Extract[String, Double.type, Double] = _.toDouble

val answer = "42" |< Int
val bnswer = "42.1" |< Double

This allows you to use infix syntax, because all those things are ordinary values.


Still, only because it's possible, it doesn't mean that you have to do it. For instance, I wouldn't know what to expect from a |<-operator. Many other people also wouldn't know what to do with it. They'd have to go and look it up. Then they would see this signature:

def |<[BC, B](companion: BC)(implicit e: Extract[A, BC, B]): B

I can imagine that the vast majority of people (myself in one week included) would not be immediately enlightened by this signature.

Maybe you could consider something more lightweight:

type BSONValue = String

trait Extract[B] {
  def extractValue(bsonValue: BSONValue): B
}


def extract[B](bson: BSONValue)(implicit efb: Extract[B])
  : B = efb.extractValue(bson)

implicit def extractIntFromString
  : Extract[Int] = _.toInt

implicit def extractDoubleFromString
  : Extract[Double] = _.toDouble

val answer = extract[Int]("42")
val bnswer = extract[Double]("42.1")

println(answer)
println(bnswer)

It seems to do roughly the same as the |< operator, but with much less magic going on.