-
Notifications
You must be signed in to change notification settings - Fork 21
OnCreate trait: call onCreate method after object creation #4330
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
Comments
Imported From: https://issues.scala-lang.org/browse/SI-4330?orig=1 |
@soc said:
|
Richard Emberson (rmemberson) said: |
@odersky said: |
Richard Emberson (rmemberson) said: Currently, the Java version is 147kloc (code plus test cases) In the base class constructor of the frameworks component The first is a such external communication is a call out to The second external communication in the constructor is that class Node(data: Data) {
if (data.instanceOf[WrappedData])
data.asInstanceof[WrappedData].setNode(this)
} The end user will have difficulty determining why things are not So, to make the framework safer while providing the ability to |
@odersky said: So why is DelayedInit different? Two reasons: First, DelayedInit does have to do with Scala's functional nature. You cannot simulate DelayedInit yourself without changing all affected val fields to vars. Second, DelayedInit fixes a very common pattern with the Application trait. |
Richard Emberson (rmemberson) said: |
Richard Emberson (rmemberson) said (edited on Jun 7, 2011 6:16:07 PM UTC): trait A extends DelayedInit {
println("A ConstructionCode")
def delayedInit(body: => Unit) = {
body
postConstructionCode
}
protected def postConstructionCode: Unit = {
println("A PostConstructionCode")
}
}
trait B extends A {
println("B ConstructionCode")
override protected def postConstructionCode: Unit = {
super.postConstructionCode
println("B PostConstructionCode")
}
}
class C extends B {
println("C ConstructionCode")
override protected def postConstructionCode: Unit = {
super.postConstructionCode
println("C PostConstructionCode")
}
}object Test {
def main(args: Array[String])
val c = new C
}
} This outputs: A ConstructionCode
B ConstructionCode
C ConstructionCode
A PostConstructionCode
B PostConstructionCode
C PostConstructionCode 5W (which was what we wanted)! Of course, each framework would have to create their own "onCreate" |
Erik Westra (eecolor) said: A I tried it with the code below, but the trait Native extends DelayedInit {
def delayedInit(body: => Unit) = {
body
println("object created")
//create native object for this
}
}
class Window extends Native {
val windowProperty: Boolean = false
}
class Stage extends Window {
val stageProperty: Boolean = false
} I see two workarounds:
Both of these workarounds are problematic: 1. is bad for performance and 2. goes against the DRY principle. This would be easily solved by a Can this problem be solved without the |
Erik Westra (eecolor) said (edited on Oct 21, 2012 8:43:43 PM UTC): trait OnCreate extends DelayedInit {
def onCreate:Unit
def delayedInit(body: => Unit) = {
body
if ((body _).getClass.getDeclaringClass == this.getClass)
{
onCreate
}
}
}
class A extends OnCreate {
def onCreate = println("Creation is fully complete")
val x = ""
println("a complete")
}
class B extends A {
val y = ""
println("b complete")
} Executing a complete
b complete
Creation is fully complete |
@adriaanm said: |
@adriaanm said: |
@adriaanm said: I'd propose considering how this relates to language virtualization and constructor macros. trait OnCreate[+T] { self: T =>
// Don't actually include this method signature, as we cannot express that we want
// to allow a subclass implementation to add an implicit arg section or that it could be a macro
// def completeConstruction: T
} for any macro example: scala> trait OnCreate[T] { self: T => } //def completeConstruction: Any }
defined trait OnCreate
scala> def impl[T: c.WeakTypeTag](c: BlackboxContext): c.Tree = { import c.universe._
| println(typeTag[C])
| q"""???"""
| }
impl: [T](c: scala.reflect.macros.BlackboxContext)(implicit evidence$1: c.WeakTypeTag[T])c.Tree
scala> class C extends OnCreate[C] { import language.experimental.macros
| println("c")
| def completeConstruction = macro impl[C]
| }
defined class C
scala> (new C).completeConstruction
TypeTag[C]
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:229)
... 32 elided
scala> (new C)
c
|
James Diebel (jamesd8) said: |
Markus Marvell (Marvell) said (edited on Feb 14, 2016 10:04:39 AM UTC): |
Markus Marvell (Marvell) said (edited on Feb 21, 2016 9:59:31 AM UTC): trait Worker {
def use(): Unit
}
trait SafeWorker extends DelayedInit with Worker{
private[this] var ok = true
override final def delayedInit(body: ⇒ Unit): Unit = {
if (ok) try body catch {case e: Throwable ⇒ ok = false}
}
def isOk: Boolean = ok
def use(): Unit = if (isOk) println(s"Working...") else println(s"Oops...")
}
class MediaSafeWorker extends SafeWorker {
throw new Exception
}
class MySafeWorker extends MediaSafeWorker { () }
class UnsafeWorker extends Worker{
throw new Exception
def use(): Unit = println(s"Working...")
} Running this code prints: "Oops..." object ATest extends App {
val safeObj = new MySafeWorker
safeObj.use()
} But running this code breaks execution with exception. object ATest extends App {
val unsafeObj = new UnsafeWorker
unsafeObj.use()
} (i) SUGGESTED OPTION DelayedInit trait needs some improvements.
def delayedInit (body: => Unit, bodyClass: Class[_]) . Or even version with argument for explicit mark indicating leaf class body. def delayedInit (body: => Unit, bodyClass: Class[_], isLeafClass: Boolean) Or add def onCreate() when object construction is complete. (!) NOTE for Android developers. -keep class scala.DelayedInit |
Charles Papon (Dolu) said (edited on Apr 20, 2016 3:40:38 PM UTC): Of course the user can push/pop things on the context stack by himself, but the goal is to have a smooth internal DSL that look like a proper language. |
could be revived as a discussion on https://contributor.scala-lang.org |
`App` is fairly problematic. It depends on `DelayedInit`, which is deprecated because it has some surprising behavior. Best to avoid it for anything more than a simple demo application. Details: scala/bug#4330 CHANGELOG_BEGIN CHANGELOG_END
…4366) `App` is fairly problematic. It depends on `DelayedInit`, which is deprecated because it has some surprising behavior. Best to avoid it for anything more than a simple demo application. Details: scala/bug#4330 CHANGELOG_BEGIN CHANGELOG_END
The DelayedInit trait addresses a rather small niche use case.
The following concerns the problem of calling code (automatically
and implicitly) after an instance has been created but prior to use.
This is useful for frameworks that want to enforce a on-creation
life cycle behavior.
It is always a problem of enforcing a on-creation behaviour
on a class hierarchy. The base class could have code that
gets executed in its constructor:
but the complete object has not yet been constructed.
The Base class could wrap the code in a method which is called
in the constructor of a derived class
But, the Derived class might be further extended.
The proposed solution is to have a OnCreate trait similar to the
DelayedInit trait:
We all know when object construction starts but having code that
executes after an object is created, without being explicit about it,
is not possible.
It is the inclusion of the OnCreate trait that causes the compiler to
generate code that calls the onCreate method after construction
is completed.
The text was updated successfully, but these errors were encountered: