7

On my scala code, I want to be able to instantiate a new class. For instance, supose I have the code below:

class Foo { def foo=10 }
trait Bar { val bar=20 }

Ideally, I want to be able to do something like:

def newInstance[A <: Foo] = { new A with Bar }
newInstance[Foo]

But, of course this doesn't work. I tried to use reflection to instantiate a class, but it seems that I'm only able to instantiate a new class (and not mix-in with a trait). I think it would be possible to make this work using Macros, but I'm not sure even where to start.

What I'm trying to do is like the following Ruby code:

class SomeClass
  def create
    self.class.new
  end
end

class Other < SomeClass
end

Other.new.create # <- this returns a new Other instance

Is it possible?

1 Answer 1

11

With a macro:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object MacroExample {
  def newInstance[A <: Foo]: A with Bar = macro newInstance_impl[A]

  def newInstance_impl[A <: Foo](c: Context)(implicit A: c.WeakTypeTag[A]) = {
    import c.universe._

    c.Expr[A with Bar](q"new $A with Bar")
  }
}

This will work as expected, and will fail at compile time if you try to instantiate a class that doesn't have a no-argument constructor.

I've used quasiquotes here for the sake of clarity, but you could build the tree manually with a little more work. There's not really any good reason to, though, now that quasiquotes are available as a plugin for Scala 2.10.

Sign up to request clarification or add additional context in comments.

5 Comments

Is it possible to overcome erasure on this solution, for example: "class NewClass[A] { MacroExample.newInstance[A] }" doesn't work...
Other thing, I didn't found a way to replicate the "Ruby" behavior of extending SomeClass with Other and instantiating the "Other" class in the subclass...
@MaurícioSzabo: About your first question: the problem isn't exactly erasure—it's that A (even with the <: Foo constraint) isn't known to be a class type. If you want a nicer error message you can check that weakTypeOf[A].typeSymbol is a ClassSymbol.
@MaurícioSzabo: If SomeClass and Other are both classes, there's no way to inherit from both of them in Scala (even with macros).
I know there is no way to inherit from both of them. What I wanted is to make a "clone-like" method like the one I showed in Ruby: define a "clone" method on a superclass and subclasses automatically understands that they need to return the Subclass, not the Superclass (provided, of course, that the class implements a no-arguments constructor)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.