It does introduce noise (note: in 2.10, in 2.11 and beyond you just declare the val private). You don't always want to. But that's the way it is for now.
You can't get around the problem by following the private-value-class pattern because the compiler can't actually see that it's a value class at the end of it, so it goes through the generic route. Here's the bytecode:
12: invokevirtual #24;
//Method Definition$.IntOps:(I)LDefinition$IntOps;
15: invokeinterface #30, 1;
//InterfaceMethod Definition$IntOps.squared:()I
See how the first one returns a copy of the class Definition$IntOps
? It's boxed.
But these two patterns work, sort of:
(1) Common name pattern.
implicit class RichInt(val repr: Int) extends AnyVal { ... }
implicit class RichInt(val underlying: Int) extends AnyVal { ... }
Use one of these. Adding i
as a method is annoying. Adding underlying
when there is nothing underlying is not nearly so bad--you'll only hit it if you're trying to get the underlying value anyway. And if you keep using the same name over and over:
implicit class RicherInt(val repr: Int) extends AnyVal { def sq = repr * repr }
implicit class RichestInt(val repr: Int) extends AnyVal { def cu = repr * repr * repr }
scala> scala> 3.cu
res5: Int = 27
scala> 3.repr
<console>:10: error: type mismatch;
found : Int(3)
required: ?{def repr: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method RicherInt of type (repr: Int)RicherInt
and method RichestInt of type (repr: Int)RichestInt
the name collision sorta takes care of your problem anyway. If you really want to, you can create an empty value class that exists only to collide with repr
.
(2) Explicit implicit pattern
Sometimes you internally want your value to be named something shorter or more mnemonic than repr
or underlying
without making it available on the original type. One option is to create a forwarding implicit like so:
class IntWithPowers(val i: Int) extends AnyVal {
def sq = i*i
def cu = i*i*i
}
implicit class EnableIntPowers(val repr: Int) extends AnyVal {
def pow = new IntWithPowers(repr)
}
Now you have to call 3.pow.sq
instead of 3.sq
--which may be a good way to carve up your namespace!--and you don't have to worry about the namespace pollution beyond the original repr
.
private
or lose the qualifier, but apparently that's not allowed for value classes. So I guess the answer is: you can't. – Kalli4.i.i.i.i.i.i
– Plutus