Skip to content

Classes defined in the REPL have no default constructor #12032

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
danielkroeni opened this issue Jun 9, 2020 · 7 comments
Open

Classes defined in the REPL have no default constructor #12032

danielkroeni opened this issue Jun 9, 2020 · 7 comments

Comments

@danielkroeni
Copy link

reproduction steps

using Scala 2.13.2, when defining a class in the REPL, no default constructor is generated. Instead there is only the constructor which expects the reference to the surrounding object.

Welcome to Scala 2.13.2 (OpenJDK 64-Bit Server VM, Java 13.0.1).
Type in expressions for evaluation. Or try :help.

scala> class A
class A

scala> classOf[A].getConstructors()
val res2: Array[java.lang.reflect.Constructor[_]] = Array(public A($iw))

This was different in 2.13.1:

Welcome to Scala 2.13.1 (OpenJDK 64-Bit Server VM, Java 13.0.1).
Type in expressions for evaluation. Or try :help.

scala> class A
defined class A

scala> classOf[A].getConstructors()
res0: Array[java.lang.reflect.Constructor[_]] = Array(public A())

problem

I used to show akka examples in the repl for a course I am teaching. With Scala 2.13.2 it does not work anymore. I guess Props[PrintActor] searches for the zero argument constructor of PrintActor to create an instance - and can not find it.

Welcome to Scala 2.13.2 (OpenJDK 64-Bit Server VM, Java 13.0.1).
Type in expressions for evaluation. Or try :help.

scala>  import akka.actor._
import akka.actor._

scala>  val as = ActorSystem("as")
val as: akka.actor.ActorSystem = akka://as

scala> class PrintActor extends Actor {
     | def receive = { case msg: Int => println(msg) }
     | }
class PrintActor

scala> val printActor: ActorRef = as.actorOf(Props[PrintActor])
java.lang.IllegalArgumentException: no matching constructor found on class PrintActor for arguments []
  at akka.util.Reflect$.error$1(Reflect.scala:86)
  at akka.util.Reflect$.findConstructor(Reflect.scala:110)
  ... 37 elided

The example above works as expected with Scala 2.13.1.
Random note: -Yrepl-class-based does not help.

@som-snytt
Copy link

You want to turn off the option:

$ scala -Dscala.repl.info -Yrepl-class-based:false
[info] started at Tue Jun 09 09:57:35 PDT 2020
Welcome to Scala 2.13.2 (OpenJDK 64-Bit Server VM, Java 11.0.7).
Type in expressions for evaluation. Or try :help.

scala 2.13.2> class C
class C

scala 2.13.2> classOf[C].getConstructors
val res0: Array[java.lang.reflect.Constructor[_]] = Array(public C())

scala 2.13.2>

@SethTisue
Copy link
Member

SethTisue commented Jun 10, 2020

@dwijnand is this inherent to the class-based encoding?

I thought :paste -raw might be another way around it, but no. oops, actually that does work!

fyi @patriknw

@dwijnand
Copy link
Member

Here's the summary of -Yrepl-class-based and the recent changes around it scala/scala#8712.

@dwijnand is this inherent to the class-based encoding?

Specifically for classes, it's not inherent that they are wrapped in classes - there's no impact on serialising REPL state nor impact in deadlocking. In the aggregate, it might create more confusion to have more variants that opt-out of class-based wrapping, which right now is just value classes. Also, there's the issue of what to do when there are multiple "things" defined, like class C; val x = 1 - when opting out value classes the solution decided was to just opt the whole snippet to object-based.

@dwijnand dwijnand added the repl label Jun 10, 2020
@dwijnand dwijnand changed the title Scala 2.13.2: Classes defined in the REPL have no default constructor (regression) Scala 2.13.2: Classes defined in the REPL have no default constructor Jun 10, 2020
@dwijnand dwijnand added this to the 2.13.4 milestone Jun 10, 2020
@dwijnand dwijnand changed the title Scala 2.13.2: Classes defined in the REPL have no default constructor Classes defined in the REPL have no default constructor Jun 10, 2020
@Jasper-M
Copy link

I thought final classes avoided this outer pointer stuff, but apparently the pointer still gets passed to the constructor. It just doesn't get stored in a field.

:paste -raw works for me though. But you have to be careful: "raw" classes get shadowed by non-raw classes of the same name, and can't shadow other raw classes.

@SethTisue
Copy link
Member

:paste -raw works for me though

oops, thanks for the correction, I was just confused before

@som-snytt
Copy link

can't shadow other raw classes

"raw hide".

@danielkroeni
Copy link
Author

Thank you very much for your fast responses. Using -Yrepl-class-based:false solves the problem for me:

> scala -Yrepl-class-based:false -cp "lib/*" 
Welcome to Scala 2.13.2 (OpenJDK 64-Bit Server VM, Java 13.0.1).
Type in expressions for evaluation. Or try :help.

scala> import akka.actor._
     | val as = ActorSystem("as")
     | class PrintActor extends Actor {
     | def receive = { case msg: Int => println(msg) }
     | }
     | val printActor: ActorRef = as.actorOf(Props[PrintActor])
import akka.actor._
val as: akka.actor.ActorSystem = akka://as
class PrintActor
val printActor: akka.actor.ActorRef = Actor[akka://as/user/$a#-611164863]

I let the issue open since i am not sure if there is something you want to do about it.
Thanks again!

@dwijnand dwijnand modified the milestones: 2.13.4, Backlog Oct 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants