Why does the Scala compiler disallow overloaded methods with default arguments? - scala

While there might be valid cases where such method overloadings could become ambiguous, why does the compiler disallow code which is neither ambiguous at compile time nor at run time?
Example:
// This fails:
def foo(a: String)(b: Int = 42) = a + b
def foo(a: Int) (b: Int = 42) = a + b
// This fails, too. Even if there is no position in the argument list,
// where the types are the same.
def foo(a: Int) (b: Int = 42) = a + b
def foo(a: String)(b: String = "Foo") = a + b
// This is OK:
def foo(a: String)(b: Int) = a + b
def foo(a: Int) (b: Int = 42) = a + b
// Even this is OK.
def foo(a: Int)(b: Int) = a + b
def foo(a: Int)(b: String = "Foo") = a + b
val bar = foo(42)_ // This complains obviously ...
Are there any reasons why these restrictions can't be loosened a bit?
Especially when converting heavily overloaded Java code to Scala default arguments are a very important and it isn't nice to find out after replacing plenty of Java methods by one Scala methods that the spec/compiler imposes arbitrary restrictions.

I'd like to cite Lukas Rytz (from here):
The reason is that we wanted a deterministic naming-scheme for the
generated methods which return default arguments. If you write
def f(a: Int = 1)
the compiler generates
def f$default$1 = 1
If you have two overloads with defaults on the same parameter
position, we would need a different naming scheme. But we want to keep
the generated byte-code stable over multiple compiler runs.
A solution for future Scala version could be to incorporate type names of the non-default arguments (those at the beginning of a method, which disambiguate overloaded versions) into the naming schema, e.g. in this case:
def foo(a: String)(b: Int = 42) = a + b
def foo(a: Int) (b: Int = 42) = a + b
it would be something like:
def foo$String$default$2 = 42
def foo$Int$default$2 = 42
Someone willing to write a SIP proposal?

It would be very hard to get a readable and precise spec for the interactions of overloading resolution with default arguments. Of course, for many individual cases, like the one presented here, it's easy to say what should happen. But that is not enough. We'd need a spec that decides all possible corner cases. Overloading resolution is already very hard to specify. Adding default arguments in the mix would make it harder still. That's why we have opted to separate the two.

I can't answer your question, but here is a workaround:
implicit def left2Either[A,B](a:A):Either[A,B] = Left(a)
implicit def right2Either[A,B](b:B):Either[A,B] = Right(b)
def foo(a: Either[Int, String], b: Int = 42) = a match {
case Left(i) => i + b
case Right(s) => s + b
}
If you have two very long arg lists which differ in only one arg, it might be worth the trouble...

What worked for me is to redefine (Java-style) the overloading methods.
def foo(a: Int, b: Int) = a + b
def foo(a: Int, b: String) = a + b
def foo(a: Int) = a + "42"
def foo(a: String) = a + "42"
This ensures the compiler what resolution you want according to the present parameters.

Here is a generalization of #Landei answer:
What you really want:
def pretty(tree: Tree, showFields: Boolean = false): String = // ...
def pretty(tree: List[Tree], showFields: Boolean = false): String = // ...
def pretty(tree: Option[Tree], showFields: Boolean = false): String = // ...
Workarround
def pretty(input: CanPretty, showFields: Boolean = false): String = {
input match {
case TreeCanPretty(tree) => prettyTree(tree, showFields)
case ListTreeCanPretty(tree) => prettyList(tree, showFields)
case OptionTreeCanPretty(tree) => prettyOption(tree, showFields)
}
}
sealed trait CanPretty
case class TreeCanPretty(tree: Tree) extends CanPretty
case class ListTreeCanPretty(tree: List[Tree]) extends CanPretty
case class OptionTreeCanPretty(tree: Option[Tree]) extends CanPretty
import scala.language.implicitConversions
implicit def treeCanPretty(tree: Tree): CanPretty = TreeCanPretty(tree)
implicit def listTreeCanPretty(tree: List[Tree]): CanPretty = ListTreeCanPretty(tree)
implicit def optionTreeCanPretty(tree: Option[Tree]): CanPretty = OptionTreeCanPretty(tree)
private def prettyTree(tree: Tree, showFields: Boolean): String = "fun ..."
private def prettyList(tree: List[Tree], showFields: Boolean): String = "fun ..."
private def prettyOption(tree: Option[Tree], showFields: Boolean): String = "fun ..."

One of the possible scenario is
def foo(a: Int)(b: Int = 10)(c: String = "10") = a + b + c
def foo(a: Int)(b: String = "10")(c: Int = 10) = a + b + c
The compiler will be confused about which one to call. In prevention of other possible dangers, the compiler would allow at most one overloaded method has default arguments.
Just my guess:-)

My understanding is that there can be name collisions in the compiled classes with default argument values. I've seen something along these lines mentioned in several threads.
The named argument spec is here:
http://www.scala-lang.org/sites/default/files/sids/rytz/Mon,%202009-11-09,%2017:29/named-args.pdf
It states:
Overloading If there are multiple overloaded alternatives of a method, at most one is
allowed to specify default arguments.
So, for the time being at any rate, it's not going to work.
You could do something like what you might do in Java, eg:
def foo(a: String)(b: Int) = a + (if (b > 0) b else 42)

Related

Infinite curryable add function

I was wondering how one would implement an infinite curried add function, for the case of explanation i would stick to scala.
I know how to prepare a simple curry like
def add(a: Int): Int => Int = {
def iadd(b: Int): Int = {
a + b
}
iadd
}
add(4)(5) // 9
How would i got about implementing add(5)(4)(x1)(x2)..(xn)
The Smart Way
The question is the comments is well-posed: when do you stop the currying and produce a result?
One solution is to stop the recursion by calling the function with zero arguments. Scala's overloading with let us do this.
add(1)(2)(3)(4)() // The () indicates that we're done currying
This is relatively straightforward. We just need a class with an apply that returns a new instance of itself
// A class with an apply method is callable like a function
class Adder(val acc: Int) {
def apply(a: Int): Adder =
new Adder(acc + a)
def apply(): Int =
acc
}
def add: Adder = new Adder(0)
println(add(1)(2)(3)(4)()) // 10
If you ever had a real reason to do this, this would be the way I would recommend. It's simple, easy to read, and adds very little boilerplate on top of the currying.
The Slightly Unhinged Way
But what fun is simple and logical? Let's get rid of those silly parentheses at the end, eh? We can do it with Scala's implicit conversions. First, we'll need to import the feature, so that Scala will stop warning us that what we're doing is silly and not a good idea.
import scala.language.implicitConversions
Then we make it so that Adder can be converted to Int
// Don't do this in real code
implicit def adderToInt(adder: Adder): Int =
adder()
Now, we don't need those parentheses at the end. We do, however, need to indicate to the type system that we want an Int.
val result: Int = add(1)(2)(3)(4)
println(result) // 10
Passing the result to a function which takes an Int, for instance, would also suffice.
Comments
Since you mentioned functional programming in general, I will note that you can do similar tricks in Haskell, using typeclasses. You can see this in action in the standard library with Text.PrintF. Note that since Haskell functions always take one argument, you'll need to have a sentinel value to indicate the "end" of the arguments (() may suffice, depending on how generic your argument types are).
If you want to reinterpret every integer n as function n.+, then just do it:
implicit class Add(val x: Int) extends AnyVal { def apply(i: Int) = x + i }
val add = 0
or even shorter (with implicit conversions):
implicit def asAdd(n: Int): Int => Int = n.+
val add = 0
Example:
add(1)(2)(3)(4) // res1: Int = 10
There is no such thing as "infinitely curryable", it's not a meaningful notion.
Well, this is not exactly infinite currying, but it gives you the something similar.
final class InfiniteCurrying[A, B] private (acc: A, op: (A, B) => A) {
final val run: A = acc
final def apply(b: B): InfiniteCurrying[A, B] =
new InfiniteCurrying(
acc = op(acc, b),
op,
)
}
object InfiniteCurrying {
def add(initial: Int): InfiniteCurrying[Int, Int] =
new InfiniteCurrying(
acc = initial,
op = (acc, b) => acc + b
)
}
import InfiniteCurrying._
val r = add(10)(20)(30)
r.run // res: Int = 60

How to define a function that works on unrelated types in Scala?

I'd like to define a function that applies * 2 to its argument, that works for all types where it's meaningful. I tried using structural types:
import scala.language.reflectiveCalls
def double[T](x: Any{def * (arg0: Int): T}) = x * 2
It works for strings:
scala> double("a")
res85: String = aa
But not for numbers:
scala> double(4)
java.lang.NoSuchMethodException: java.lang.Integer.$times(int)
at java.lang.Class.getMethod(Class.java:1778)
at .reflMethod$Method1(<console>:18)
at .double(<console>:18)
... 32 elided
Why do I get this error message?
Is it possible to do what I want using structural types?
Is it possible to do it in some other way?
Edit: By "do what I want" I mean working for already existing types, such as numbers and strings, not just for classes that I define myself.
* is translated to $times, structural type checks existence of * method, but (I suppose that's a bug) calls it's internal ($times) representations). That works for String, because there is $times for them.
This approach should work for methods with names that only contain letters.
```
import scala.language.reflectiveCalls
def double[T](x: Any{def test (arg0: Int): T}) = x.test(2)
class A { def test(i: Int) = i * 10 }
class B { def test(i: Int) = i * 20 }
scala> double(new A)
res0: Int = 20
scala> double(new B)
res1: Int = 40
Yes, idiomatic answer is typeclasses. You choose what exactly "meaningfulness" is. And they can be applied to any already existing class:
```
trait Multiply[A]{
def times(a: A, x: Int): A
}
implicit val MultString = new Multiply[String] { def times(a: String, x: Int) = a * x }
implicit val MultInt = new Multiply[Int] { def times(a: Int, x: Int) = a * x }
def double[T](t: T)(implicit mult: Multiply[T]) = mult.times(t, 2)
scala> double("aaaa")
res0: String = aaaaaaaa
scala> double(111)
res1: Int = 222
Also note that structural typing uses reflection => is quite slow.
You could always just overload the method. To make it work in the REPL you have to :paste it in as a block.
def double(s:String):String = s * 2
def double[N](n:N)(implicit ev: Numeric[N]):N = {
import Numeric.Implicits._
n * ev.fromInt(2)
}
double("this") // result: String = thisthis
double(3L) // result: Long = 6
One more possibility I've found is to use macros. As of Scala 2.11.8 they are still experimental and, according to Martin Odersky, won't survive in this form. The current synax is clumsy, but so far it is the only method that is completely DRY (* 2 is written only once, and the function works on all types that support this operation).
Regardless of whether this is the best solution, I'm posting it for the sake of completeness:
import reflect.macros.Context
def doubleImpl[T](c: Context)(x: c.Expr[T]): c.Expr[T] = {
import c.universe._
c.Expr(q"${x.tree} * 2")
}
def double[T](x: T): T = macro doubleImpl[T]

Writing function parameters before function to be applied in Scala

Is it possible to have syntax like (parameter1, parameter2) applied myFunction. Here myFunction would be applied to the given parameters. Concrete example: val myFunction = (a:String) => a+a+"there"; "hello" applied myFunction should output "hellohellothere".
I know it's possible to do (parameter1, parameter2) match {case myFunctionWrittenOut}, so the above would become "hello" match {case a:String => a+a+"there"} but here you have to write out the function: you can't use a reference.
I don't think it's possible with standard scala. But you can write some helper methods that would make something like this available:
implicit class Applied1[T](val t: T) extends AnyVal {
def applied[R](f: T => R): R = f(t)
}
implicit class Applied2[T1, T2](val t: (T1, T2)) extends AnyVal {
def applied[R](f: (T1, T2) => R): R = f(t._1, t._2)
}
implicit class Applied3[T1, T2, T3](val t: (T1, T2, T3)) extends AnyVal {
def applied[R](f: (T1, T2, T3) => R): R = f(t._1, t._2, t._3)
}
// ... and 19 more implicit classes: Applied4 to Applied22
And then you can use it like this:
def minus(a: Int): Int = -a
def plus(a: Int, b: Int): Int = a + b
def plus(a: Int, b: Int, c: Int): Int = a + b + c
scala> 5 applied minus
res0: Int = -5
scala> (1, 2) applied plus
res1: Int = 3
scala> (1, 2, 3) applied plus
res2: Int = 6
But this may be a bit more complex to use with generic functions, or functions with implicit arguments:
def mul[T : Numeric](a: T, b: T): T = {
import Numeric.Implicits._
a * b
}
scala> (1.5, 2.5) applied (mul(_, _))
res3: Double = 3.75
Implicit classes can be used to achieve something which which seems to be similar to what you are looking for.
An implicit class with only one constructor argument can be used as a pattern to add methods to the a given type. One example is DurationInt which "adds" methods to integers to enable converting them to durations. It is imported into scope using import scala.concurrent.duration._
A simplified version of DurationInt could be defined as follows:
implicit class DurationInt(n: Int) {
def seconds: FiniteDuration = Duration(n, TimeUnit.SECONDS)
}
This enables use of the seconds method on all integers
2.seconds // Returns a duration object
For functions with multiple arguments you can use a tuple argument for the implicit class:
implicit class TupleConcat(tuple: (String, String)) {
def concat: String = tuple._1 + tuple._2
}
// enables the following syntax
("aa", "bb").concat
It is common for implicit classes such as these to extend AnyVal, this allows some compiler optimizations which avoid actually having to instantiate the implicit class in many cases.
implicit final class DurationInt(val n: Int) extends AnyVal { /* implementation */ }
In Scala, the parameter list of a function is always written before the function:
val fn = (a: Int, b: Int) => a + b
// ^ parameters ^ ^ function

Scala can't overload two methods [duplicate]

While there might be valid cases where such method overloadings could become ambiguous, why does the compiler disallow code which is neither ambiguous at compile time nor at run time?
Example:
// This fails:
def foo(a: String)(b: Int = 42) = a + b
def foo(a: Int) (b: Int = 42) = a + b
// This fails, too. Even if there is no position in the argument list,
// where the types are the same.
def foo(a: Int) (b: Int = 42) = a + b
def foo(a: String)(b: String = "Foo") = a + b
// This is OK:
def foo(a: String)(b: Int) = a + b
def foo(a: Int) (b: Int = 42) = a + b
// Even this is OK.
def foo(a: Int)(b: Int) = a + b
def foo(a: Int)(b: String = "Foo") = a + b
val bar = foo(42)_ // This complains obviously ...
Are there any reasons why these restrictions can't be loosened a bit?
Especially when converting heavily overloaded Java code to Scala default arguments are a very important and it isn't nice to find out after replacing plenty of Java methods by one Scala methods that the spec/compiler imposes arbitrary restrictions.
I'd like to cite Lukas Rytz (from here):
The reason is that we wanted a deterministic naming-scheme for the
generated methods which return default arguments. If you write
def f(a: Int = 1)
the compiler generates
def f$default$1 = 1
If you have two overloads with defaults on the same parameter
position, we would need a different naming scheme. But we want to keep
the generated byte-code stable over multiple compiler runs.
A solution for future Scala version could be to incorporate type names of the non-default arguments (those at the beginning of a method, which disambiguate overloaded versions) into the naming schema, e.g. in this case:
def foo(a: String)(b: Int = 42) = a + b
def foo(a: Int) (b: Int = 42) = a + b
it would be something like:
def foo$String$default$2 = 42
def foo$Int$default$2 = 42
Someone willing to write a SIP proposal?
It would be very hard to get a readable and precise spec for the interactions of overloading resolution with default arguments. Of course, for many individual cases, like the one presented here, it's easy to say what should happen. But that is not enough. We'd need a spec that decides all possible corner cases. Overloading resolution is already very hard to specify. Adding default arguments in the mix would make it harder still. That's why we have opted to separate the two.
I can't answer your question, but here is a workaround:
implicit def left2Either[A,B](a:A):Either[A,B] = Left(a)
implicit def right2Either[A,B](b:B):Either[A,B] = Right(b)
def foo(a: Either[Int, String], b: Int = 42) = a match {
case Left(i) => i + b
case Right(s) => s + b
}
If you have two very long arg lists which differ in only one arg, it might be worth the trouble...
What worked for me is to redefine (Java-style) the overloading methods.
def foo(a: Int, b: Int) = a + b
def foo(a: Int, b: String) = a + b
def foo(a: Int) = a + "42"
def foo(a: String) = a + "42"
This ensures the compiler what resolution you want according to the present parameters.
Here is a generalization of #Landei answer:
What you really want:
def pretty(tree: Tree, showFields: Boolean = false): String = // ...
def pretty(tree: List[Tree], showFields: Boolean = false): String = // ...
def pretty(tree: Option[Tree], showFields: Boolean = false): String = // ...
Workarround
def pretty(input: CanPretty, showFields: Boolean = false): String = {
input match {
case TreeCanPretty(tree) => prettyTree(tree, showFields)
case ListTreeCanPretty(tree) => prettyList(tree, showFields)
case OptionTreeCanPretty(tree) => prettyOption(tree, showFields)
}
}
sealed trait CanPretty
case class TreeCanPretty(tree: Tree) extends CanPretty
case class ListTreeCanPretty(tree: List[Tree]) extends CanPretty
case class OptionTreeCanPretty(tree: Option[Tree]) extends CanPretty
import scala.language.implicitConversions
implicit def treeCanPretty(tree: Tree): CanPretty = TreeCanPretty(tree)
implicit def listTreeCanPretty(tree: List[Tree]): CanPretty = ListTreeCanPretty(tree)
implicit def optionTreeCanPretty(tree: Option[Tree]): CanPretty = OptionTreeCanPretty(tree)
private def prettyTree(tree: Tree, showFields: Boolean): String = "fun ..."
private def prettyList(tree: List[Tree], showFields: Boolean): String = "fun ..."
private def prettyOption(tree: Option[Tree], showFields: Boolean): String = "fun ..."
One of the possible scenario is
def foo(a: Int)(b: Int = 10)(c: String = "10") = a + b + c
def foo(a: Int)(b: String = "10")(c: Int = 10) = a + b + c
The compiler will be confused about which one to call. In prevention of other possible dangers, the compiler would allow at most one overloaded method has default arguments.
Just my guess:-)
My understanding is that there can be name collisions in the compiled classes with default argument values. I've seen something along these lines mentioned in several threads.
The named argument spec is here:
http://www.scala-lang.org/sites/default/files/sids/rytz/Mon,%202009-11-09,%2017:29/named-args.pdf
It states:
Overloading If there are multiple overloaded alternatives of a method, at most one is
allowed to specify default arguments.
So, for the time being at any rate, it's not going to work.
You could do something like what you might do in Java, eg:
def foo(a: String)(b: Int) = a + (if (b > 0) b else 42)

How can one provide manually specialized implementations with Scala specialization?

Specialization promises to provide high-efficiency implmentations for primitive types
with minimal extra boilerplate. But specialization seems to be too eager for its own good.
If I want to specialize a class or method,
def foo[#specialized(Byte) A](a: A): String = ???
class Bar[#specialized(Int) B] {
var b: B = ???
def baz: B = ???
}
then I am required to write a single implementation that covers both the specialized and the generic cases.
What if those cases are really different from each other, such that the implementations do not overlap?
For example, if I wanted to perform math on bytes, I would need to insert a bunch of & 0xFFs into the
logic.
I could possibly write a specialized type-class to do the math right, but doesn't that just push the same
problem back one level? How do I write my specialized + method for that type class in a way that doesn't
conflict with a more general implementation?
class Adder[#specialized(Byte) A] {
def +(a1: A, a2: A): A = ???
}
Also, once I do create a type-class this way, how do I make sure the correct type class is used for my specialized methods
instead of the general version (which, if it is truly general, should probably compile and certainly would run, except that it isn't what I want)?
Is there a way to do this without macros? Is it easier with macros?
This is my best attempt so far. It works but the implementation isn't pretty (even if the results are). Improvements are welcome!
There is a macro-free way to do this, both at the class and method level, and it does involve type classes--quite a lot of
them! And the answer is not exactly the same for classes and methods. So bear with me.
Manually Specialized Classes
You manually specialize classes the same way that you manually provide any kind of different implementation for classes:
your superclass is abstract (or is a trait), and the subclasses provide the implementation details.
abstract class Bippy[#specialized(Int) B] {
def b: B
def next: Bippy[B]
}
class BippyInt(initial: Int) extends Bippy[Int] {
private var myB: Int = initial
def b: Int = myB
def next = { myB += 1; this }
}
class BippyObject(initial: Object) extends Bippy[Object] {
private var myB: Object = initial
def b: B = myB
def next = { myB = myB.toString; this }
}
Now, if only we had a specialized method to pick out the right implementations, we'd be done:
object Bippy{
def apply[#specialized(Int) B](initial: B) = ??? // Now what?
}
So we've converted our problem of providing custom specialized classes and methods into just
needing to provide custom specialized methods.
Manually Specialized Methods
Manually specializing a method requires a way to write one implementation that can nonetheless
select which implementation you want (at compile time). Type classes are great at this. Suppose
we already had type classes that implemented all of our functionality, and that the compiler would
select the right one. Then we could just write
def foo[#specialized(Int) A: SpecializedFooImpl](a: A): String =
implicitly[SpecializedFooImpl[A]](a)
...or we could if implicitly was guaranteed to preserve specialization and if we only
ever wanted a single type parameter. In general these things are not true, so we'll write
our type class out as an implicit parameter rather than relying on the A: TC syntactic sugar.
def foo[#specialized(Int) A](a: A)(implicit impl: SpecializedFooImpl[A]): String =
impl(a)
(Actually, that's less boilerplate anyway.)
So we've converted our problem of providing custom specialized methods into just needing
to write specialized typeclasses and getting the compiler to fill in the correct ones.
Manually Specialized Type Classes
Type classes are just classes, and now we have to write specialized classes again, but
there's a critical difference. The user isn't the one asking for arbitrary instances.
This gives us just enough extra flexibility for it to work.
For foo, we need an Int version and a fully generic version.
trait SpecFooImpl[#specialized (Int), A] {
def apply(param: A): String
}
final class SpecFooImplAny[A] extends SpecFooImpl[A] {
def apply(param: A) = param.toString
}
final class SpecFooImplInt extends SpecFooImpl[Int] {
def apply(param: Int) = "!" * math.max(0, param)
}
Now we could create implicits to supply those type classes like so
implicit def specFooAsAny[A] = new SpecFooImplAny[A]
implicit val specFooAsInt = new SpecFooImplInt
except we have a problem: if we actually try to call foo: Int, both implicits will apply.
So if we just had a way to prioritize which type class we chose, we'd be all set.
Selection of type classes (and implicits in general)
One of the secret ingredients the compiler uses to determine the right implicit to use
is inheritance. If implicits come from A via B extends A, but B
declares its own that also could apply, those in B win if all else is equal.
So we put the ones we want to win deeper in the inheritance hierarchy.
Also, since you're free to define implicits in traits, you can mix them in anywhere.
So the last piece of our puzzle is to pop our type class implicits into a chain
of traits that extend each other, with the more generic ones appearing earlier.
trait LowPriorityFooSpecializers {
implicit def specializeFooAsAny[A] = new SpecializedFooImplAny[A]
}
trait FooSpecializers extends LowPriorityFooSpecializers {
implicit val specializeFooAsInt = new SpecializedFooImplInt
}
Mix in the highest-priority trait to wherever the implicits are needed, and the
type classes will be picked as desired.
Note that the type classes will be as specialized as you make them even if the
specialized annotation is not used. So you can do without specialized at all,
as long as you know the type precisely enough, unless you want to use specialized
functions or interoperate with other specialized classes. (And you probably do.)
A complete example
Let's suppose we want to make a two-parameter specialized bippy function that
will do apply the following transformation:
bippy(a, b) -> b
bippy(a, b: Int) -> b+1
bippy(a: Int, b) -> b
bippy(a: Int, b: Int) -> a+b
We should be able to achieve this with three type classes and a single specialized
method. Let's try, first the method:
def bippy[#specialized(Int) A, #specialized(Int) B](a: A, b: B)(implicit impl: SpecBippy[A, B]) =
impl(a, b)
Then the type classes:
trait SpecBippy[#specialized(Int) A, #specialized(Int) B] {
def apply(a: A, b: B): B
}
final class SpecBippyAny[A, B] extends SpecBippy[A, B] {
def apply(a: A, b: B) = b
}
final class SpecBippyAnyInt[A] extends SpecBippy[A, Int] {
def apply(a: A, b: Int) = b + 1
}
final class SpecBippyIntInt extends SpecBippy[Int, Int] {
def apply(a: Int, b: Int) = a + b
}
Then the implicits in chained traits:
trait LowerPriorityBippySpeccer {
// Trick to avoid allocation since generic case is erased anyway!
private val mySpecBippyAny = new SpecBippyAny[AnyRef, AnyRef]
implicit def specBippyAny[A, B] = mySpecBippyAny.asInstanceOf[SpecBippyAny[A, B]]
}
trait LowPriorityBippySpeccer extends LowerPriorityBippySpeccer {
private val mySpecBippyAnyInt = new SpecBippyAnyInt[AnyRef]
implicit def specBippyAnyInt[A] = mySpecBippyAnyInt.asInstanceOf[SpecBippyAnyInt[A]]
}
// Make this last one an object so we can import the contents
object BippySpeccer extends LowPriorityBippySpeccer {
implicit val specBippyIntInt = new SpecBippyIntInt
}
and finally we'll try it out (after pasting everything in together in :paste in the REPL):
scala> import Speccer._
import Speccer._
scala> bippy(Some(true), "cod")
res0: String = cod
scala> bippy(1, "salmon")
res1: String = salmon
scala> bippy(None, 3)
res2: Int = 4
scala> bippy(4, 5)
res3: Int = 9
It works--our custom implementations are enabled. Just to check that we can use
any type, but we don't leak into the wrong implementation:
scala> bippy(4, 5: Short)
res4: Short = 5
scala> bippy(4, 5: Double)
res5: Double = 5.0
scala> bippy(3: Byte, 2)
res6: Int = 3
And finally, to verify that we have actually avoided boxing, we'll time bippy at
summing a bunch of integers:
scala> val th = new ichi.bench.Thyme
th: ichi.bench.Thyme = ichi.bench.Thyme#1130520d
scala> val adder = (i: Int, j: Int) => i + j
adder: (Int, Int) => Int = <function2>
scala> var a = Array.fill(1024)(util.Random.nextInt)
a: Array[Int] = Array(-698116967, 2090538085, -266092213, ...
scala> th.pbenchOff(){
var i, s = 0
while (i < 1024) { s = adder(a(i), s); i += 1 }
s
}{
var i, s = 0
while (i < 1024) { s = bippy(a(i), s); i += 1 }
s
}
Benchmark comparison (in 1.026 s)
Not significantly different (p ~= 0.2795)
Time ratio: 0.99424 95% CI 0.98375 - 1.00473 (n=30)
First 330.7 ns 95% CI 328.2 ns - 333.1 ns
Second 328.8 ns 95% CI 326.3 ns - 331.2 ns
So we can see that our specialized bippy-adder achieves the same kind of performance
as specialized Function2 does (about 3 adds per ns, which is about right for a modern
machine).
Summary
To write custom specialized code using the #specialized annotation,
Make the specialized class abstract and manually supply concrete implementations
Make specialized methods (including generators for a specialized class) take typeclasses that do the real work
Make the base typeclass trait #specialized and provide concrete implementations
Provide implicit vals or defs in an inheritance-hierarchy of traits so the correct one is selected
It's a lot of boilerplate, but at the end of it all you get a seamless custom-specialized experience.
This is an answer from the scala internals mailing list:
With miniboxing specialization, you can use the reflection feature:
import MbReflection._
import MbReflection.SimpleType._
import MbReflection.SimpleConv._
object Test {
def bippy[#miniboxed A, #miniboxed B](a: A, b: B): B =
(reifiedType[A], reifiedType[B]) match {
case (`int`, `int`) => (a.as[Int] + b.as[Int]).as[B]
case ( _ , `int`) => (b.as[Int] + 1).as[B]
case (`int`, _ ) => b
case ( _ , _ ) => b
}
def main(args: Array[String]): Unit = {
def x = 1.0
assert(bippy(3,4) == 7)
assert(bippy(x,4) == 5)
assert(bippy(3,x) == x)
assert(bippy(x,x) == x)
}
}
This way, you can choose the exact behavior of the bippy method based on the type arguments without defining any implicit classes.
I know it's quite old, but I bumped at it looking for something else and maybe it'll prove useful. I had a similar motivation, and answered it in how to check I'm inside a specialized function or class
I used a reverse lookup table - SpecializedKey is a specialized class which equals all other instances with the same specialization, so I can perform a check like this
def onlyBytes[#specialized E](arg :E) :Option[E] =
if (specializationFor[E]==specializationFor[Byte]) Some(arg)
else None
Of course, there's no performance benefit when working with individual primitive values, but with collections, especially iterators, it becomes useful.
final val AllButUnit = new Specializable.Group((Byte, Short, Int, Long, Char, Float, Double, Boolean, AnyRef))
def specializationFor[#specialized(AllButUnit) E] :ResolvedSpecialization[E] =
Specializations(new SpecializedKey[E]).asInstanceOf[ResolvedSpecialization[E]]
private val Specializations = Seq(
resolve[Byte],
resolve[Short],
resolve[Int],
resolve[Long],
resolve[Char],
resolve[Float],
resolve[Double],
resolve[Boolean],
resolve[Unit],
resolve[AnyRef]
).map(
spec => spec.key -> spec :(SpecializedKey[_], ResolvedSpecialization[_])
).toMap.withDefaultValue(resolve[AnyRef])
private def resolve[#specialized(AllButUnit) E :ClassTag] :ResolvedSpecialization[E] =
new ResolvedSpecialization[E](new SpecializedKey[E], new Array[E](0))
class ResolvedSpecialization[#specialized(AllButUnit) E] private[SpecializedCompanion]
(val array :Array[E], val elementType :Class[E], val classTag :ClassTag[E], private[SpecializedCompanion] val key :SpecializedKey[E]) {
private[SpecializedCompanion] def this(key :SpecializedKey[E], array :Array[E]) =
this(array, array.getClass.getComponentType.asInstanceOf[Class[E]], ClassTag(array.getClass.getComponentType.asInstanceOf[Class[E]]), key)
override def toString = s"#specialized($elementType)"
override def equals(that :Any) = that match {
case r :ResolvedSpecialization[_] => r.elementType==elementType
case _ => false
}
override def hashCode = elementType.hashCode
}
private class SpecializedKey[#specialized(AllButUnit) E] {
override def equals(that :Any) = that.getClass==getClass
override def hashCode = getClass.hashCode
def className = getClass.getName
override def toString = className.substring(className.indexOf("$")+1)
}