I was wondering if something like this would be possible to implement in Scala:
def f[B <: AnyRef]()(implicit ct: ClassTag[B]): B = {
new B {
override def equals(o: Any) = ...
override def hashcode(o: Any) = ...
}
}
My intuition is that even with the ClassTag
it should not be possible to instantiate an arbitrary B
, as we don't know if it even has a no-args parameter.
But the actual error I'm getting is:
class type required but B found
My current use case is: I want to be able to redefine the equals/hashcode of arbitrary objects that are given to me (I can't really get away from that as I'll have then to deliver the objects to some faulty framework that will use those objects' equals / hashcodes, so I have no control over that). The obvious way to do that would be through inheritance. Is there some way of doing this?
When declaring a class in Scala, we can specify type parameters. We use square brackets to surround these type parameters. For example, we can declare class Foo [A]. The placeholder A can then be used in the body of the class to refer to the type. When the generic class is used, the code will specify which type to use in each case.
A class in Scala is a 'blueprint' of a class instance. An instance contains the state and behavior as defined by that class. To declare a class: class MyClass {} // curly braces are optional here as class body is empty
Inheritance is an important pillar of OOP (Object Oriented Programming). It is the mechanism in Scala by which one class is allowed to inherit the features (fields and methods) of another class. Super Class: The class whose features are inherited is known as superclass (or a base class or a parent class).
As it turns out, the upper bound type in Scala generics will do this for us: With the “T <: Ordered [T]” syntax we indicate that Ordered [T] is the supertype of type parameter T. That is, each element in the xs list should be a subtype of Ordered [T].
It's definitely impossible in the general case.
Supposed I passed a final
type for B
, such as String
. There would be no way to subclass that. So, you can't do it for arbitrary B
.
Depending on how this other framework works, you might be able to pass it an AnyRef
instead. Otherwise, you might be able to pull something off with macros, but more information is needed to determine this.
Brian answers the question in the title (you can also consider that B
can have abstract methods you wouldn't know to define). But
I want to be able to redefine the equals/hashcode of arbitrary objects that are given to me
suggests a different signature:
def f[B <: AnyRef](x: B): B = ...
and this one is doable. With limitations, of course. If B
is an interface, you can use dynamic proxies from Java standard library,
and for classes you need a library like CGLIB. Approximately (untested):
def f[B <: AnyRef](x: B): B = {
val enhancer = new Enhancer()
enhancer.setSuperclass(x.getClass)
val interceptor: MethodInterceptor = (obj, method, args, proxy) =>
method.getName match {
case "equals" => // your equals impl
case "hashCode" => // your hashCode impl
case _ => proxy.invokeSuper(obj, args)
}
enhancer.setCallback(interceptor)
enhancer.create() as B
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With