Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Scala allow for the arbitrary instantiation of generic objects? new B {}?

Tags:

scala

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?

like image 826
devoured elysium Avatar asked Jan 24 '19 04:01

devoured elysium


People also ask

How to declare a generic class in Scala?

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.

What is a class in Scala?

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

What is inheritance in Scala?

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).

What is the upper bound type in Scala generics?

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].


2 Answers

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.

like image 112
Brian McCutchon Avatar answered Oct 05 '22 14:10

Brian McCutchon


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
}
like image 33
Alexey Romanov Avatar answered Oct 05 '22 12:10

Alexey Romanov