3

Consider the following code, derived from the metascala project:

object Units {
  case class Quantity[M <: MInt, T: Numeric](value: T) {
    type This = Quantity[M, T]

    def *[M2 <: MInt](m: Quantity[M2, T]) = 
      Quantity[M + M2, T](numeric[T].times(value, m.value))
    def /[M2 <: MInt](m: Quantity[M2, T]) = 
      Quantity[M - M2, T](numeric[T].div(value, m.value))
    def apply(v: T) = Quantity[M, T](numeric[T].times(v, value))
  }

  implicit def measure[T: Numeric](v: T) = Quantity[_0, T](v)

  implicit def numericToQuantity[T: Numeric](v: T) = 
    new QuantityConstructor[T](v)

  class QuantityConstructor[T: Numeric](v: T) {
    def m = Quantity[_1, T](v)
  }
}

(the MInt is basically the implementation of peano numbers where _0, _1 are concrete "values" from metascala. Tell me if you need additional code, I just didn't want to paste everything in here.)

I want to support code where some existing Quantity can be multiplied by a simple number, e. g.

import Units._

val length1 = 5  * (5 m) //doesn't work <-----
val length2 = (5 m) * 5  // works

Why is the implicit method measure not considered in the first line of code as I have assumed?

Instead I get this error message:

overloaded method value * with alternatives:
   (x: Double)Double <and>
   (x: Float)Float <and>
   (x: Long)Long <and>
   (x: Int)Int <and>
   (x: Char)Int <and>
   (x: Short)Int <and>
   (x: Byte)Int  cannot be applied to 
(scalax.units.Units3.Quantity[scalax.units.Integers._1,Int])

I'm using Scala 2.10-trunk.

This is actually the follow up to How does ‘1 * BigInt(1)’ work and how can I do the same?.

Community
  • 1
  • 1
soc
  • 27,310
  • 18
  • 99
  • 209
  • Where are you defining `implicit def measure`? What version of Scala? For this to work, the definition of `measure` must be in either the local scope or the implicit scope, and according to [retronym's answer](http://stackoverflow.com/questions/7647835/how-does-1-bigint1-work-and-how-can-i-do-the-same/7648364#7648364) to your previous question, the rules for implicit scope will soon become more powerful. For more details about implicits, I highly recommend [Daniel Sobral's tutorial](http://stackoverflow.com/questions/5598085/where-does-scala-look-for-implicits). – Kipton Barros Oct 04 '11 at 14:40
  • I clarified the code. The first blok of code is in one object, which is imported in the second block of code. – soc Oct 04 '11 at 14:50

1 Answers1

4

To get things started, here's a stand-alone example that gives the same problem,

object Units {
  case class Quantity[T: Numeric](value: T) {
    def *[M](m: Quantity[T]) =           // type M can't be inferred below
      Quantity[T](implicitly[Numeric[T]].times(value, m.value))
  }
  implicit def measure[T: Numeric](v: T) = Quantity[T](v)

  val length0 = measure(5) * Quantity(5) // works
  val length1 = 5  * Quantity(5)         // doesn't work
}

For some reason, the conversion measure isn't being found because of the type parameter M on the method *. If the type parameter is removed from *, things compile fine. Maybe someone else can explain why?

Edit. This is looking like a limitation of the Scala compiler, since renaming * to something like *** resolves the problem. Perhaps the existence of Int.* (without a type parameter) is precluding the implicit conversion for use of Quantity.*[M] (with a type parameter). This reminds me of the requirement that overridden methods must have the same exact type parameters.

Community
  • 1
  • 1
Kipton Barros
  • 20,144
  • 3
  • 63
  • 77
  • Yes, I would appreciate that! – soc Oct 04 '11 at 16:30
  • The weird thing that the type parameter is given in my example `Quantity[_0, T]` and it still doesn't work. I also tried adding an explicit return type to the `implicit` but it didn't help :-( – soc Oct 04 '11 at 17:36
  • Yes I know that I could use different names, but I would reatty prefer having the same. Btw, did you mean overridden? – soc Oct 04 '11 at 19:10