The metrics-scala project got a pull-request that suggests to change:
class Meter {
def exceptionMarker: new AnyRef() {
def apply[A](f: => A): A = ???
}
}
to the much nicer:
class Meter {
object exceptionMarker { // only this line changed
def apply[A](f: => A): A = ???
}
}
However, I am afraid this causes binary incompatibility. Of course I checked with Mima. Mima does not complain.
So my question is: is Mima right, and is the proposed change really binary compatible?
In fact you can even implement/override a def with an object in a subclass.
trait Foo
trait A {
def foo: Foo
}
class B extends A {
object foo extends Foo
}
So yes, I am fairly sure it should be backwards binary compatible.
Related
I have a situation where I'd like to implement a given trait (CanBeString in the example below). I would like to have the option either to implement that trait using a newly created case class (NewImplementation in the example below), or to implement it by adding functionality to some pre-existing type (just Int in the example below), by using a type class. This is probably best illustrated by the below:
package example
// typeclass
trait ConvertsToString[A] {
def asString(value: A): String
}
// the trait I would like the typeclass to implement
trait CanBeString {
def asString: String
}
// this implementation approach taken from the scala with cats book
object ConvertsToStringInstances {
implicit val intConvertsToString: ConvertsToString[Int] =
new ConvertsToString[Int] {
def asString(value: Int): String = s"${value}"
}
}
object ConvertsToStringSyntax {
implicit class ConvertsToStringOps[A](value: A) {
def asString(implicit c: ConvertsToString[A]): String = c.asString(value)
}
}
object Test {
import ConvertsToStringInstances._
import ConvertsToStringSyntax._
def testAsFunc(c: CanBeString): String = c.asString
case class NewImplementation (f: Double) extends CanBeString {
def asString = s"{f}"
}
println(testAsFunc(NewImplementation(1.002))) // this works fine!
println(testAsFunc(1)) // this sadly does not.
}
Is anything like this possible? I'm only recently discovering the topic of typeclasses so I'm aware that what I'm asking for here may be possible but just unwise - if so please chime in and let me know what a better idiom might be.
Thanks in advance, and also afterwards!
For example you can have two overloaded versions of testAsFunc (OOP-style and typeclass-style)
object Test {
...
def testAsFunc(c: CanBeString): String = c.asString
def testAsFunc[C: ConvertsToString](c: C): String = c.asString
println(testAsFunc(NewImplementation(1.002))) // {f}
println(testAsFunc(1)) // 1
}
Or if you prefer to have the only testAsFunc then you can add instances of the type class for subtypes of the trait to be implemented
object ConvertsToStringInstances {
implicit val intConvertsToString: ConvertsToString[Int] = ...
implicit def canBeStringSubtypeConvertsToString[A <: CanBeString]: ConvertsToString[A] =
new ConvertsToString[A] {
override def asString(value: A): String = value.asString
}
}
object Test {
...
def testAsFunc[C: ConvertsToString](c: C): String = c.asString
println(testAsFunc(NewImplementation(1.002))) // {f}
println(testAsFunc(1)) // 1
}
Please notice that if for a c there are both OOP-ish c.asString and extension-method c.asString then only the first is actually called.
I'm using two Scala libraries that both rely on implicit parameters to supply codecs/marshallers for case classes (the libraries in question are msgpack4s and op-rabbit). A simplified example follows:
sealed abstract trait Event
case class SomeEvent(msg: String) extends Event
case class OtherEvent(code: String) extends Event
// Assume library1 needs Show and library2 needs Printer
trait Show[A] { def show(a: A): String }
trait Printer[A] { def printIt(a: A): Unit }
object ShowInstances {
implicit val showSomeEvent = new Show[SomeEvent] {
override def show(a: SomeEvent) =
s"SomeEvent: ${a.msg}"
}
implicit val showOtherEvent = new Show[OtherEvent] {
override def show(a: OtherEvent) =
s"OtherEvent: ${a.code}"
}
}
The Printer for the one library can be generic provided there's an implicit Show for the other library available:
object PrinterInstances {
implicit def somePrinter[A: Show]: Printer[A] = new Printer[A] {
override def printIt(a: A): Unit =
println(implicitly[Show[A]].show(a))
}
}
I want to provide an API that abstracts over the details of the underlying libraries - callers should only need to pass the case class, internally to the API implementation the relevant implicits should be summoned.
object EventHandler {
private def printEvent[A <: Event](a: A)(implicit printer: Printer[A]): Unit = {
print("Handling event: ")
printer.printIt(a)
}
def handle(a: Event): Unit = {
import ShowInstances._
import PrinterInstances._
// I'd like to do this:
//EventHandler.printEvent(a)
// but I have to do this
a match {
case s: SomeEvent => EventHandler.printEvent(s)
case o: OtherEvent => EventHandler.printEvent(o)
}
}
}
The comments in EventHandler.handle() method indicate my issue - is there a way to have the compiler select the right implicits for me?.
I suspect the answer is no because at compile time the compiler doesn't know which subclass of Event handle() will receive, but I wanted to see if there's another way. In my actual code, I control & can change the PrinterInstances code, but I can't change the signature of the printEvent method (that's provided by one of the libraries)
*EDIT: I think this is the same as Provide implicits for all subtypes of sealed type. The answer there is nearly 2 years old, I'm wondering if it's still the best approach?
You have to do the pattern matching somewhere. Do it in the Show instance:
implicit val showEvent = new Show[Event] {
def show(a: Event) = a match {
case SomeEvent(msg) => s"SomeEvent: $msg"
case OtherEvent(code) => s"OtherEvent: $code"
}
}
If you absolutely need individual instances for SomeEvent and OtherEvent, you can provide them in a different object so they can be imported separately.
If Show is defined to be contravariant (i.e. as trait Show[-A] { ... }, with a minus on the generic type) then everything works out of the box and a Show[Event] is usable as a Show[SomeEvent] (and as a Show[OtherEvent] for that matter).
If Show is unfortunately not written to be contravariant, then we might have to do a little bit more juggling on our end than we'd like. One thing we can do is declare all of our SomeEvent values as simply Events, vis a vis val fooEvent: Event = SomeEvent("foo"). Then fooEvent will be showable.
In a more extreme version of the above trick, we can actually hide our inheritance hierarchy:
sealed trait Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X
}
object Event {
private case class SomeEvent(msg: String) extends Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X = withSomeEvent(msg)
}
private case class OtherEvent(code: String) extends Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X = withOtherEvent(code)
}
def someEvent(msg: String): Event = SomeEvent(msg)
def otherEvent(code: String): Event = OtherEvent(code)
}
Event.someEvent and Event.otherEvent allow us to construct values, and fold allows us to pattern match.
I'm trying to find a workaround for bringing a user defined implicit into the call site of some library code. I have something like this
//library code
trait Fruit { def foo: Unit }
class Apple extends Fruit {
def foo: Unit = {
// a bunch of imperative code
}
}
class Pear extends Fruit // etc
I would like to augment that to something like this
// library code
trait Fruit { def foo[+A <: Fruit](implicit fi: FruitImplicit[A]): Unit }
class Apple extends Fruit {
def foo[Apple](implicit fi: FruitImplicit[Apple]): Unit = {
// a bunch of imperative code
fi.aReallyImportantMethod
}
}
class Pear extends Fruit // etc
trait FruitImplicits[+A <: Fruit]{
def mark: Unit = Unit // default implementation that normally would be used
}
// user code
implicit val appleImplicit: FruitImplicit[Apple] = new FruitImplicit[Apple] {
def mark: Unit = println("YOLO")
}
My thought on trying to bring this into scope would be something like this:
// library code
class Apple extends Fruit {
object FruitOps extends LowPriorityFruitImplicits with FruitImplicits[A] {}
import FruitOps._
def foo[Apple](implicit fi: FruitImplicit[Apple]): Unit = {
// a bunch of imperative code
fi.aReallyImportantMethod
}
}
I know I'm missing something ( this doesn't compile obviously ). Is there a way around this? I keep thinking that there is a way to turn FruitImplicits into FruitIMplicits[Apple] statically which would bring in the implicit for that specific type. However, that would require creating a type that itself is its subtype.
Or maybe I'm crazy and this is a terrible idea. Any thoughts?
I think this is a terrible idea, of course, but I also think that what you're trying to do is possible (if I understand correctly).
One issue is that the Apple type parameter for your foo in Apple is shadowing the type Apple. If you want to refer to the subtype in Fruit you'll need to use something like F-bounded polymorphism:
trait Fruit[F <: Fruit[F]] {
def foo()(implicit fi: FruitImplicit[F]): Unit
}
(I've added an extra set of parentheses in the interest of following best practices for side-effecting code, but they're not necessary.)
Your FruitImplicit would then look like this:
trait FruitImplicit[A <: Fruit[A]] {
def mark(): Unit
}
object FruitImplicit {
implicit def defaultAction[F <: Fruit[F]]: FruitImplicit[F] =
new FruitImplicit[F] {
def mark(): Unit = println("default")
}
}
Here we supply a default action that will be used if the user doesn't provide their own implicit for the type we're calling mark in.
Now your implementation would look like this:
class Apple extends Fruit[Apple] {
def foo()(implicit fi: FruitImplicit[Apple]): Unit = {
println("This is an apple")
fi.mark()
}
}
class Pear extends Fruit[Pear] {
def foo()(implicit fi: FruitImplicit[Pear]): Unit = {
println("This is a pear")
fi.mark()
}
}
And then:
scala> val apple = new Apple
apple: Apple = Apple#7bb35c46
scala> val pear = new Pear
pear: Pear = Pear#777bd4a2
scala> apple.foo()
This is an apple
default
scala> pear.foo()
This is a pear
default
But if the user provides an implicit…
scala> implicit val appleAction: FruitImplicit[Apple] =
| new FruitImplicit[Apple] {
| def mark(): Unit = println("YOLO")
| }
appleAction: FruitImplicit[Apple] = $anon$1#146578a5
scala> apple.foo()
This is an apple
YOLO
scala> pear.foo()
This is a pear
default
…it'll be used instead of the default for that type.
There are some cases in Scala when I need to use a cast, although I would say it is not strictly required. Consider the following program:
abstract class A {
type T <: F[T]
}
abstract class F[T <: F[T]] {
def me: String
}
class B extends A {
type T = TB
}
class TB extends F[TB] {
def me = "It's me"
def you = "It's you"
}
trait Operator[S <: A] extends Function[S#T,String]
object f1 extends Operator[A] {
def apply(x: A#T) = x.me
}
object f2 extends Operator[B] {
def apply(x: B#T) = x.you
}
object Driver {
def main(args: Array[String]) {
val bi = new TB()
println(f1(bi.asInstanceOf[A#T]))
println(f2(bi))
}
}
If I remove asInstanceOf[A#T] in the main method the code does not compile. However, I do not think the cast is really necessary. Actually, looking at the generated bytecode with javap, there is no occurrence of the checkcast instruction. Is this a limit of the Scala type-checker or there is something I am missing?
This is a limit of the type-checker, but it's a reasonable one. Consider what you're asking it to prove to show that TB <: A#T: that there's some subclass of A (let's call it C) for which TB <: C#T and C#T is concrete. Such a subclass exists (i.e., B), but would we necessarily want the compiler to search A's entire hierarchy to find it?
The specification is unsound; see https://issues.scala-lang.org/browse/SI-7278 among others.
I'm trying to implement a Scala trait that handles the details of interfacing with a Java library that requires us to create
What I want to do is something like:
trait SomeTrait[A] extends JavaAPI {
def foo = {
callApi(classOf[A])
}
override def bar = {
foo
}
}
Note that bar is actually overriding a method from a base class, so I can't change it's signature.
I've tried several variations with Manifests, etc., but can't quite get this to work. Is there a way to get the runtime class of a parameterized type?
This flavour should do the trick:
trait SomeTrait[A] {
def foo(implicit ev: Manifest[A]) = {
callApi(ev.erasure)
}
}
update At some point, the manifest must be injected via a method parameter. A constructor would be a good choice, if traits could have them.
Actually, they can! The trait has the constructor of whatever it's mixed-in to, so if you specify an abstract manifest that deriving classes must define...
trait SomeTrait {
def ev: Manifest[_] //abstract
def foo = println(ev.erasure)
}
//this `ev` provides the implementation, note that it MUST be a val, or var
class Concrete[T](implicit val ev: Manifest[T]) extends SomeTrait
And all is good again.
You have to get the manifest in there somehow, and traits have no constructor parameters. Only you can say what tradeoff you want to make. Here's another one.
trait SomeTrait[A] {
implicit def manifesto: Manifest[A]
def foo = println(manifest[A].erasure)
}
object SomeTrait {
def apply[A: Manifest] : SomeTrait[A] = new SomeTrait[A] { def manifesto = manifest[A] }
}
Due to type erasure, the compiler has no way to figure out what the type should be within the trait. Thus what you want can't be done. However, you could make it a class. That way the compiler can pass an evidence parameter when an instance is created.
class SomeTrait[A](implicit ev: Manifest[A]) extends JavaApi {
def foo = {
callApi(ev.erasure)
}
override def bar = {
foo
}
}
It might be a little inconvenient to do so in your code, but you can do this
trait SomeTrait[A] extends JavaAPI {
def objType: Class[A]
def foo = {
callApi(objType)
}
override def bar = {
foo
}
}
object SomeImplementation with SomeTrait[SomeObject] {
val objType: Class[SomeObject] = classOf[SomeObject]
}
I know it is a little wordy, but that's the way I solved this problem. I hope to find a better solution in the future, but this is what I'm using now. Let me know if that helps you.