I have a trait Modifier[-A] extends (A => Unit)
.
However, Scala 2.12 magic SAM syntax silently converts any lambda literal like el => foo into a Modifier because Modifier qualifies as a SAM type (rules for applicability of this syntax are here).
I don't want such conversion to apply to my Modifier trait because it interferes with my library's syntax. In short, I have an implicit conversion from A => Modifier[A]
to Modifier[A]
. With 2.12, that conversion is not triggered for lambda literals (e.g. thisNode => someModifier(thisNode, otherParam)
) because Scala magicks the A => Modifier[A]
lambda into a Modifier[A]
all by itself, but not into a correct one.
There are a couple ways to solve this problem that I know of:
1) Modifier trait should not extend Function1, and should instead define its own abstract def apply[X](element: El): Unit
method. SAM syntax is not applied due to the phantom type param X.
2) Add a meaningless abstract protected[this] def foo
to Modifier trait. This will make SAM syntax inapplicable, and if I'm understanding Scala.js dead code elimination correctly, this bogus method will be eliminated from runtime.
I'm leaning towards Option 1 as it seems like less burden for implementers of Modifier, as well as more obvious that it will not affect runtime performance.
But it still seems hacky, and I don't like that the useless phantom type will leak into the API of my library. Isn't there a better way?
Thanks for any advice.
As you can see from the documentation of Scala 2.12 Sam Conversions precedes implicits : the documentation also discuss potential solutions to override this behaviour.
If you need the conversion to occur automatically, both approaches are reasonable:
If you extend your own custom MyFunction1
you might lose composition benefits of the standard library
If you add a meaningless method, you will fall back to a standard Function1 as soon as you perform combinatorial operations using the methods defined on Function1
In your case, I guess both approach are fine because your Modifier apply
is returning Unit and you are not going to pipe or wire the operations together.