How Scala App trait and main works internally?
Hi I'm newbie in Scala.
As far as I know there are 2ways to make entry point in scala, one is define main method with object and the other is extending App trait.
I wondered how App trait works, so I checked the source for App trait, but there are full of confusing code...
The code said that the App has initCodes which are extended from App trait, and these are added in delayedInit method that inherited from DelayedInit. Also the App trait has main method, which will be entry point.
But the What confusing me are
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
- Where can I check these knowledge? I tried to search in document but I couldn't
scala
add a comment |
Hi I'm newbie in Scala.
As far as I know there are 2ways to make entry point in scala, one is define main method with object and the other is extending App trait.
I wondered how App trait works, so I checked the source for App trait, but there are full of confusing code...
The code said that the App has initCodes which are extended from App trait, and these are added in delayedInit method that inherited from DelayedInit. Also the App trait has main method, which will be entry point.
But the What confusing me are
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
- Where can I check these knowledge? I tried to search in document but I couldn't
scala
add a comment |
Hi I'm newbie in Scala.
As far as I know there are 2ways to make entry point in scala, one is define main method with object and the other is extending App trait.
I wondered how App trait works, so I checked the source for App trait, but there are full of confusing code...
The code said that the App has initCodes which are extended from App trait, and these are added in delayedInit method that inherited from DelayedInit. Also the App trait has main method, which will be entry point.
But the What confusing me are
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
- Where can I check these knowledge? I tried to search in document but I couldn't
scala
Hi I'm newbie in Scala.
As far as I know there are 2ways to make entry point in scala, one is define main method with object and the other is extending App trait.
I wondered how App trait works, so I checked the source for App trait, but there are full of confusing code...
The code said that the App has initCodes which are extended from App trait, and these are added in delayedInit method that inherited from DelayedInit. Also the App trait has main method, which will be entry point.
But the What confusing me are
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
- Where can I check these knowledge? I tried to search in document but I couldn't
scala
scala
asked Nov 25 '18 at 14:12
Hacking JHacking J
11910
11910
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
The delayedInit
would be called automatically by the Scala compiler as the initialisation code of the object/class that extends the DelayedInit
trait. I expand more on this answer below.
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
Because it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. An example is also provided below.
- Where can I check these knowledge? I tried to search in document but I couldn't.
I got to learn about the dynamics by reading the Scala docs and the links it points to. For example this https://github.com/scala/scala/releases/tag/v2.11.0 and https://issues.scala-lang.org/browse/SI-4330?jql=labels%20%3D%20delayedinit%20AND%20resolution%20%3D%20unresolved
I would now try to expatiate more on the answer above by going into more details into the workings of DelayedInit
, and how the JVM specifies entry points to programs.
First of all, we have to understand that when Scala is run on the JVM, it still has to adhere to the JVM requirement for defining the entry point to your program, which is to provide the JVM with a class with a main method with signature of public static void main(String)
. Even though when we use the App
trait, it might appear as if we are getting away from do this, but this is just an illusion, the JVM still needs to have access to a method with the signature public static void main(String)
. It is just that by extending App
together with the mechanism of DelayedInit
, Scala can provide this method on our behalf.
Second, it is also good to reiterate that code snippets found in the body of a class (or object) definition, would be the initialisation code of such a class/object and would be executed automatically when such is instantiated. In Java, it is more or less the code you put in the constructor block.
So for a class:
class Foo {
// code.
def method = ???
}
Whatever code
is, it will be executed automatically when you call new Foo
.
In case of an object
object Foo {
// code.
def method = ???
}
The code
will be executed automatically without you having to call new
since Scala would automatically make a singleton instance called Foo
available for you.
So basically if anything is in the body definition, it gets executed automatically. You do not need to explicitly execute it.
Now to the DelayedInit
trait. One thing to be aware of is that it provides us a mechanism to perform what can be called a compiler trick, where certain part of our code gets rewritten. This is one of the reason why it could be confusing to reason about. Because when you use it, what actually gets executed by the Scala compiler is not the code you reading but a slight modification of it. To understand what is going on, you then need to understand the ways the compiler alters the code.
The trick, the DelayedInit
trait allows us to perform is to take the code that is part of the body of a class/object definition and turn it, into an argument that is passed by name, to the method delayedInit
defined on DelayedInit
.
Basically it rewrites this:
object Foo {
// some code
}
into
object Foo {
// delayedInt({some code})
}
This means instead of having // some code
executed automatically, delayedInt
is the method that is called automatically with // some code
passed to it as arguments.
So anything that extends DelayedInit
would have its initialisation code replaced by the method call delayedInt
with the initialisation code passed as an argument. Hence why nobody needs to explicitly call the delayedInt
method.
Now let use see how this then tie to the App
trait and how the App
trait is used to provide the entry point to a Scala application.
As you will notice, the delayedInit
method on the DelayedInit
trait does not provide any implementation. Hence the actual behaviour of delayedInit
when it is called needs to be provided by something else that extends DelayedInit
.
The App
trait is such an implementation. And what does the App
trait do? Two important thing related to the topic of discussion:
- It provides an implementation of
delayedInit
which takes the initialisation code it is passed, and puts it in aListBuffer
. - It provides the main method
def main(args: Array[String])
which satisfy the requirement of the JVM to have a method withpublic static void main(String)
to serve as the entry point to a program. And what this main method does, is to execute whatever code placed in the ListBuffer.
The above characteristics of the App
trait means that any object/class that extends it would have its initialisation code passed to delayedInit
, which would then add it into a ListBuffer, and then the object/class extending it would now have a main method, which when called (most of the time by the JVM as the entry point) would run through the code in the ListBuffer and execute it.
Basically it turns this:
object Foo {
// some code
}
into this
object Foo {
// the implementation of delayedInt is to put `// some code` into a list buffer
delayedInt (// some code)
def main(args: Array[String]) = {
// the implementation below just runs through and execute the code found in list buffer that would have been populated by the call to delayedInt and
???
}
}
So why have a List buffer to store the code to be executed? Because, as I said above it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. To see this in action.
Given the following code snippet:
class AnotherClass {
println("Initialising AnotherClass")
}
trait AnotherTrait {
println("Initialising AnotherTrait")
}
trait YetAnotherTrait {
println("Initialising YetAnotherTrait")
}
object Runner extends AnotherClass with AnotherTrait with YetAnotherTrait with App {
println("Hello world")
}
When run would output the following:
Initialising AnotherClass
Initialising AnotherTrait
Initialising YetAnotherTrait
Hello world
So the individual initialisation code in the hierarchy that consists of AnotherClass
, AnotherTrait
and YetAnotherTrait
gets added to the initCode
list buffer, via the delayedInit
method of the App
trait, and then they get executed by the main method also provided by the App
trait.
As you would have noticed by peeking into the source code, the whole mechanism of DelayedInt
is deprecated and schedule for removal in the future.
1
Perfect answer! I appreciate it
– Hacking J
Nov 25 '18 at 23:19
add a comment |
delayedInit:-
The init hook. This saves all initialization code for execution within
main
. This method is normally never called directly from user code.
Instead it is called as compiler-generated code for those classes and
objects (but not traits) that inherit from theDelayedInit
trait and
that do not themselves define adelayedInit
method.
App scala
delayedInit
is deprecated since 2.11.0
. Also, it has some outstanding bugs which are not fixed.
initCodes:-
I am not sure about the reason for defining the initCodes
as ListBuffer.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53468358%2fhow-scala-app-trait-and-main-works-internally%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
The delayedInit
would be called automatically by the Scala compiler as the initialisation code of the object/class that extends the DelayedInit
trait. I expand more on this answer below.
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
Because it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. An example is also provided below.
- Where can I check these knowledge? I tried to search in document but I couldn't.
I got to learn about the dynamics by reading the Scala docs and the links it points to. For example this https://github.com/scala/scala/releases/tag/v2.11.0 and https://issues.scala-lang.org/browse/SI-4330?jql=labels%20%3D%20delayedinit%20AND%20resolution%20%3D%20unresolved
I would now try to expatiate more on the answer above by going into more details into the workings of DelayedInit
, and how the JVM specifies entry points to programs.
First of all, we have to understand that when Scala is run on the JVM, it still has to adhere to the JVM requirement for defining the entry point to your program, which is to provide the JVM with a class with a main method with signature of public static void main(String)
. Even though when we use the App
trait, it might appear as if we are getting away from do this, but this is just an illusion, the JVM still needs to have access to a method with the signature public static void main(String)
. It is just that by extending App
together with the mechanism of DelayedInit
, Scala can provide this method on our behalf.
Second, it is also good to reiterate that code snippets found in the body of a class (or object) definition, would be the initialisation code of such a class/object and would be executed automatically when such is instantiated. In Java, it is more or less the code you put in the constructor block.
So for a class:
class Foo {
// code.
def method = ???
}
Whatever code
is, it will be executed automatically when you call new Foo
.
In case of an object
object Foo {
// code.
def method = ???
}
The code
will be executed automatically without you having to call new
since Scala would automatically make a singleton instance called Foo
available for you.
So basically if anything is in the body definition, it gets executed automatically. You do not need to explicitly execute it.
Now to the DelayedInit
trait. One thing to be aware of is that it provides us a mechanism to perform what can be called a compiler trick, where certain part of our code gets rewritten. This is one of the reason why it could be confusing to reason about. Because when you use it, what actually gets executed by the Scala compiler is not the code you reading but a slight modification of it. To understand what is going on, you then need to understand the ways the compiler alters the code.
The trick, the DelayedInit
trait allows us to perform is to take the code that is part of the body of a class/object definition and turn it, into an argument that is passed by name, to the method delayedInit
defined on DelayedInit
.
Basically it rewrites this:
object Foo {
// some code
}
into
object Foo {
// delayedInt({some code})
}
This means instead of having // some code
executed automatically, delayedInt
is the method that is called automatically with // some code
passed to it as arguments.
So anything that extends DelayedInit
would have its initialisation code replaced by the method call delayedInt
with the initialisation code passed as an argument. Hence why nobody needs to explicitly call the delayedInt
method.
Now let use see how this then tie to the App
trait and how the App
trait is used to provide the entry point to a Scala application.
As you will notice, the delayedInit
method on the DelayedInit
trait does not provide any implementation. Hence the actual behaviour of delayedInit
when it is called needs to be provided by something else that extends DelayedInit
.
The App
trait is such an implementation. And what does the App
trait do? Two important thing related to the topic of discussion:
- It provides an implementation of
delayedInit
which takes the initialisation code it is passed, and puts it in aListBuffer
. - It provides the main method
def main(args: Array[String])
which satisfy the requirement of the JVM to have a method withpublic static void main(String)
to serve as the entry point to a program. And what this main method does, is to execute whatever code placed in the ListBuffer.
The above characteristics of the App
trait means that any object/class that extends it would have its initialisation code passed to delayedInit
, which would then add it into a ListBuffer, and then the object/class extending it would now have a main method, which when called (most of the time by the JVM as the entry point) would run through the code in the ListBuffer and execute it.
Basically it turns this:
object Foo {
// some code
}
into this
object Foo {
// the implementation of delayedInt is to put `// some code` into a list buffer
delayedInt (// some code)
def main(args: Array[String]) = {
// the implementation below just runs through and execute the code found in list buffer that would have been populated by the call to delayedInt and
???
}
}
So why have a List buffer to store the code to be executed? Because, as I said above it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. To see this in action.
Given the following code snippet:
class AnotherClass {
println("Initialising AnotherClass")
}
trait AnotherTrait {
println("Initialising AnotherTrait")
}
trait YetAnotherTrait {
println("Initialising YetAnotherTrait")
}
object Runner extends AnotherClass with AnotherTrait with YetAnotherTrait with App {
println("Hello world")
}
When run would output the following:
Initialising AnotherClass
Initialising AnotherTrait
Initialising YetAnotherTrait
Hello world
So the individual initialisation code in the hierarchy that consists of AnotherClass
, AnotherTrait
and YetAnotherTrait
gets added to the initCode
list buffer, via the delayedInit
method of the App
trait, and then they get executed by the main method also provided by the App
trait.
As you would have noticed by peeking into the source code, the whole mechanism of DelayedInt
is deprecated and schedule for removal in the future.
1
Perfect answer! I appreciate it
– Hacking J
Nov 25 '18 at 23:19
add a comment |
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
The delayedInit
would be called automatically by the Scala compiler as the initialisation code of the object/class that extends the DelayedInit
trait. I expand more on this answer below.
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
Because it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. An example is also provided below.
- Where can I check these knowledge? I tried to search in document but I couldn't.
I got to learn about the dynamics by reading the Scala docs and the links it points to. For example this https://github.com/scala/scala/releases/tag/v2.11.0 and https://issues.scala-lang.org/browse/SI-4330?jql=labels%20%3D%20delayedinit%20AND%20resolution%20%3D%20unresolved
I would now try to expatiate more on the answer above by going into more details into the workings of DelayedInit
, and how the JVM specifies entry points to programs.
First of all, we have to understand that when Scala is run on the JVM, it still has to adhere to the JVM requirement for defining the entry point to your program, which is to provide the JVM with a class with a main method with signature of public static void main(String)
. Even though when we use the App
trait, it might appear as if we are getting away from do this, but this is just an illusion, the JVM still needs to have access to a method with the signature public static void main(String)
. It is just that by extending App
together with the mechanism of DelayedInit
, Scala can provide this method on our behalf.
Second, it is also good to reiterate that code snippets found in the body of a class (or object) definition, would be the initialisation code of such a class/object and would be executed automatically when such is instantiated. In Java, it is more or less the code you put in the constructor block.
So for a class:
class Foo {
// code.
def method = ???
}
Whatever code
is, it will be executed automatically when you call new Foo
.
In case of an object
object Foo {
// code.
def method = ???
}
The code
will be executed automatically without you having to call new
since Scala would automatically make a singleton instance called Foo
available for you.
So basically if anything is in the body definition, it gets executed automatically. You do not need to explicitly execute it.
Now to the DelayedInit
trait. One thing to be aware of is that it provides us a mechanism to perform what can be called a compiler trick, where certain part of our code gets rewritten. This is one of the reason why it could be confusing to reason about. Because when you use it, what actually gets executed by the Scala compiler is not the code you reading but a slight modification of it. To understand what is going on, you then need to understand the ways the compiler alters the code.
The trick, the DelayedInit
trait allows us to perform is to take the code that is part of the body of a class/object definition and turn it, into an argument that is passed by name, to the method delayedInit
defined on DelayedInit
.
Basically it rewrites this:
object Foo {
// some code
}
into
object Foo {
// delayedInt({some code})
}
This means instead of having // some code
executed automatically, delayedInt
is the method that is called automatically with // some code
passed to it as arguments.
So anything that extends DelayedInit
would have its initialisation code replaced by the method call delayedInt
with the initialisation code passed as an argument. Hence why nobody needs to explicitly call the delayedInt
method.
Now let use see how this then tie to the App
trait and how the App
trait is used to provide the entry point to a Scala application.
As you will notice, the delayedInit
method on the DelayedInit
trait does not provide any implementation. Hence the actual behaviour of delayedInit
when it is called needs to be provided by something else that extends DelayedInit
.
The App
trait is such an implementation. And what does the App
trait do? Two important thing related to the topic of discussion:
- It provides an implementation of
delayedInit
which takes the initialisation code it is passed, and puts it in aListBuffer
. - It provides the main method
def main(args: Array[String])
which satisfy the requirement of the JVM to have a method withpublic static void main(String)
to serve as the entry point to a program. And what this main method does, is to execute whatever code placed in the ListBuffer.
The above characteristics of the App
trait means that any object/class that extends it would have its initialisation code passed to delayedInit
, which would then add it into a ListBuffer, and then the object/class extending it would now have a main method, which when called (most of the time by the JVM as the entry point) would run through the code in the ListBuffer and execute it.
Basically it turns this:
object Foo {
// some code
}
into this
object Foo {
// the implementation of delayedInt is to put `// some code` into a list buffer
delayedInt (// some code)
def main(args: Array[String]) = {
// the implementation below just runs through and execute the code found in list buffer that would have been populated by the call to delayedInt and
???
}
}
So why have a List buffer to store the code to be executed? Because, as I said above it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. To see this in action.
Given the following code snippet:
class AnotherClass {
println("Initialising AnotherClass")
}
trait AnotherTrait {
println("Initialising AnotherTrait")
}
trait YetAnotherTrait {
println("Initialising YetAnotherTrait")
}
object Runner extends AnotherClass with AnotherTrait with YetAnotherTrait with App {
println("Hello world")
}
When run would output the following:
Initialising AnotherClass
Initialising AnotherTrait
Initialising YetAnotherTrait
Hello world
So the individual initialisation code in the hierarchy that consists of AnotherClass
, AnotherTrait
and YetAnotherTrait
gets added to the initCode
list buffer, via the delayedInit
method of the App
trait, and then they get executed by the main method also provided by the App
trait.
As you would have noticed by peeking into the source code, the whole mechanism of DelayedInt
is deprecated and schedule for removal in the future.
1
Perfect answer! I appreciate it
– Hacking J
Nov 25 '18 at 23:19
add a comment |
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
The delayedInit
would be called automatically by the Scala compiler as the initialisation code of the object/class that extends the DelayedInit
trait. I expand more on this answer below.
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
Because it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. An example is also provided below.
- Where can I check these knowledge? I tried to search in document but I couldn't.
I got to learn about the dynamics by reading the Scala docs and the links it points to. For example this https://github.com/scala/scala/releases/tag/v2.11.0 and https://issues.scala-lang.org/browse/SI-4330?jql=labels%20%3D%20delayedinit%20AND%20resolution%20%3D%20unresolved
I would now try to expatiate more on the answer above by going into more details into the workings of DelayedInit
, and how the JVM specifies entry points to programs.
First of all, we have to understand that when Scala is run on the JVM, it still has to adhere to the JVM requirement for defining the entry point to your program, which is to provide the JVM with a class with a main method with signature of public static void main(String)
. Even though when we use the App
trait, it might appear as if we are getting away from do this, but this is just an illusion, the JVM still needs to have access to a method with the signature public static void main(String)
. It is just that by extending App
together with the mechanism of DelayedInit
, Scala can provide this method on our behalf.
Second, it is also good to reiterate that code snippets found in the body of a class (or object) definition, would be the initialisation code of such a class/object and would be executed automatically when such is instantiated. In Java, it is more or less the code you put in the constructor block.
So for a class:
class Foo {
// code.
def method = ???
}
Whatever code
is, it will be executed automatically when you call new Foo
.
In case of an object
object Foo {
// code.
def method = ???
}
The code
will be executed automatically without you having to call new
since Scala would automatically make a singleton instance called Foo
available for you.
So basically if anything is in the body definition, it gets executed automatically. You do not need to explicitly execute it.
Now to the DelayedInit
trait. One thing to be aware of is that it provides us a mechanism to perform what can be called a compiler trick, where certain part of our code gets rewritten. This is one of the reason why it could be confusing to reason about. Because when you use it, what actually gets executed by the Scala compiler is not the code you reading but a slight modification of it. To understand what is going on, you then need to understand the ways the compiler alters the code.
The trick, the DelayedInit
trait allows us to perform is to take the code that is part of the body of a class/object definition and turn it, into an argument that is passed by name, to the method delayedInit
defined on DelayedInit
.
Basically it rewrites this:
object Foo {
// some code
}
into
object Foo {
// delayedInt({some code})
}
This means instead of having // some code
executed automatically, delayedInt
is the method that is called automatically with // some code
passed to it as arguments.
So anything that extends DelayedInit
would have its initialisation code replaced by the method call delayedInt
with the initialisation code passed as an argument. Hence why nobody needs to explicitly call the delayedInt
method.
Now let use see how this then tie to the App
trait and how the App
trait is used to provide the entry point to a Scala application.
As you will notice, the delayedInit
method on the DelayedInit
trait does not provide any implementation. Hence the actual behaviour of delayedInit
when it is called needs to be provided by something else that extends DelayedInit
.
The App
trait is such an implementation. And what does the App
trait do? Two important thing related to the topic of discussion:
- It provides an implementation of
delayedInit
which takes the initialisation code it is passed, and puts it in aListBuffer
. - It provides the main method
def main(args: Array[String])
which satisfy the requirement of the JVM to have a method withpublic static void main(String)
to serve as the entry point to a program. And what this main method does, is to execute whatever code placed in the ListBuffer.
The above characteristics of the App
trait means that any object/class that extends it would have its initialisation code passed to delayedInit
, which would then add it into a ListBuffer, and then the object/class extending it would now have a main method, which when called (most of the time by the JVM as the entry point) would run through the code in the ListBuffer and execute it.
Basically it turns this:
object Foo {
// some code
}
into this
object Foo {
// the implementation of delayedInt is to put `// some code` into a list buffer
delayedInt (// some code)
def main(args: Array[String]) = {
// the implementation below just runs through and execute the code found in list buffer that would have been populated by the call to delayedInt and
???
}
}
So why have a List buffer to store the code to be executed? Because, as I said above it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. To see this in action.
Given the following code snippet:
class AnotherClass {
println("Initialising AnotherClass")
}
trait AnotherTrait {
println("Initialising AnotherTrait")
}
trait YetAnotherTrait {
println("Initialising YetAnotherTrait")
}
object Runner extends AnotherClass with AnotherTrait with YetAnotherTrait with App {
println("Hello world")
}
When run would output the following:
Initialising AnotherClass
Initialising AnotherTrait
Initialising YetAnotherTrait
Hello world
So the individual initialisation code in the hierarchy that consists of AnotherClass
, AnotherTrait
and YetAnotherTrait
gets added to the initCode
list buffer, via the delayedInit
method of the App
trait, and then they get executed by the main method also provided by the App
trait.
As you would have noticed by peeking into the source code, the whole mechanism of DelayedInt
is deprecated and schedule for removal in the future.
- Who call delayedInit? Is it called before the main method is called?(I guess Yes)
The delayedInit
would be called automatically by the Scala compiler as the initialisation code of the object/class that extends the DelayedInit
trait. I expand more on this answer below.
- Why initCodes is ListBuffer not a element? I think there is only one entry point in application, so I don't think it should be plural.
Because it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. An example is also provided below.
- Where can I check these knowledge? I tried to search in document but I couldn't.
I got to learn about the dynamics by reading the Scala docs and the links it points to. For example this https://github.com/scala/scala/releases/tag/v2.11.0 and https://issues.scala-lang.org/browse/SI-4330?jql=labels%20%3D%20delayedinit%20AND%20resolution%20%3D%20unresolved
I would now try to expatiate more on the answer above by going into more details into the workings of DelayedInit
, and how the JVM specifies entry points to programs.
First of all, we have to understand that when Scala is run on the JVM, it still has to adhere to the JVM requirement for defining the entry point to your program, which is to provide the JVM with a class with a main method with signature of public static void main(String)
. Even though when we use the App
trait, it might appear as if we are getting away from do this, but this is just an illusion, the JVM still needs to have access to a method with the signature public static void main(String)
. It is just that by extending App
together with the mechanism of DelayedInit
, Scala can provide this method on our behalf.
Second, it is also good to reiterate that code snippets found in the body of a class (or object) definition, would be the initialisation code of such a class/object and would be executed automatically when such is instantiated. In Java, it is more or less the code you put in the constructor block.
So for a class:
class Foo {
// code.
def method = ???
}
Whatever code
is, it will be executed automatically when you call new Foo
.
In case of an object
object Foo {
// code.
def method = ???
}
The code
will be executed automatically without you having to call new
since Scala would automatically make a singleton instance called Foo
available for you.
So basically if anything is in the body definition, it gets executed automatically. You do not need to explicitly execute it.
Now to the DelayedInit
trait. One thing to be aware of is that it provides us a mechanism to perform what can be called a compiler trick, where certain part of our code gets rewritten. This is one of the reason why it could be confusing to reason about. Because when you use it, what actually gets executed by the Scala compiler is not the code you reading but a slight modification of it. To understand what is going on, you then need to understand the ways the compiler alters the code.
The trick, the DelayedInit
trait allows us to perform is to take the code that is part of the body of a class/object definition and turn it, into an argument that is passed by name, to the method delayedInit
defined on DelayedInit
.
Basically it rewrites this:
object Foo {
// some code
}
into
object Foo {
// delayedInt({some code})
}
This means instead of having // some code
executed automatically, delayedInt
is the method that is called automatically with // some code
passed to it as arguments.
So anything that extends DelayedInit
would have its initialisation code replaced by the method call delayedInt
with the initialisation code passed as an argument. Hence why nobody needs to explicitly call the delayedInt
method.
Now let use see how this then tie to the App
trait and how the App
trait is used to provide the entry point to a Scala application.
As you will notice, the delayedInit
method on the DelayedInit
trait does not provide any implementation. Hence the actual behaviour of delayedInit
when it is called needs to be provided by something else that extends DelayedInit
.
The App
trait is such an implementation. And what does the App
trait do? Two important thing related to the topic of discussion:
- It provides an implementation of
delayedInit
which takes the initialisation code it is passed, and puts it in aListBuffer
. - It provides the main method
def main(args: Array[String])
which satisfy the requirement of the JVM to have a method withpublic static void main(String)
to serve as the entry point to a program. And what this main method does, is to execute whatever code placed in the ListBuffer.
The above characteristics of the App
trait means that any object/class that extends it would have its initialisation code passed to delayedInit
, which would then add it into a ListBuffer, and then the object/class extending it would now have a main method, which when called (most of the time by the JVM as the entry point) would run through the code in the ListBuffer and execute it.
Basically it turns this:
object Foo {
// some code
}
into this
object Foo {
// the implementation of delayedInt is to put `// some code` into a list buffer
delayedInt (// some code)
def main(args: Array[String]) = {
// the implementation below just runs through and execute the code found in list buffer that would have been populated by the call to delayedInt and
???
}
}
So why have a List buffer to store the code to be executed? Because, as I said above it is possible to have a hierarchy of classes, where the initialisation code of each class in the hierarchy gets executed as part of executing the program. To see this in action.
Given the following code snippet:
class AnotherClass {
println("Initialising AnotherClass")
}
trait AnotherTrait {
println("Initialising AnotherTrait")
}
trait YetAnotherTrait {
println("Initialising YetAnotherTrait")
}
object Runner extends AnotherClass with AnotherTrait with YetAnotherTrait with App {
println("Hello world")
}
When run would output the following:
Initialising AnotherClass
Initialising AnotherTrait
Initialising YetAnotherTrait
Hello world
So the individual initialisation code in the hierarchy that consists of AnotherClass
, AnotherTrait
and YetAnotherTrait
gets added to the initCode
list buffer, via the delayedInit
method of the App
trait, and then they get executed by the main method also provided by the App
trait.
As you would have noticed by peeking into the source code, the whole mechanism of DelayedInt
is deprecated and schedule for removal in the future.
edited Nov 25 '18 at 21:47
answered Nov 25 '18 at 19:32
dadedade
1,45731932
1,45731932
1
Perfect answer! I appreciate it
– Hacking J
Nov 25 '18 at 23:19
add a comment |
1
Perfect answer! I appreciate it
– Hacking J
Nov 25 '18 at 23:19
1
1
Perfect answer! I appreciate it
– Hacking J
Nov 25 '18 at 23:19
Perfect answer! I appreciate it
– Hacking J
Nov 25 '18 at 23:19
add a comment |
delayedInit:-
The init hook. This saves all initialization code for execution within
main
. This method is normally never called directly from user code.
Instead it is called as compiler-generated code for those classes and
objects (but not traits) that inherit from theDelayedInit
trait and
that do not themselves define adelayedInit
method.
App scala
delayedInit
is deprecated since 2.11.0
. Also, it has some outstanding bugs which are not fixed.
initCodes:-
I am not sure about the reason for defining the initCodes
as ListBuffer.
add a comment |
delayedInit:-
The init hook. This saves all initialization code for execution within
main
. This method is normally never called directly from user code.
Instead it is called as compiler-generated code for those classes and
objects (but not traits) that inherit from theDelayedInit
trait and
that do not themselves define adelayedInit
method.
App scala
delayedInit
is deprecated since 2.11.0
. Also, it has some outstanding bugs which are not fixed.
initCodes:-
I am not sure about the reason for defining the initCodes
as ListBuffer.
add a comment |
delayedInit:-
The init hook. This saves all initialization code for execution within
main
. This method is normally never called directly from user code.
Instead it is called as compiler-generated code for those classes and
objects (but not traits) that inherit from theDelayedInit
trait and
that do not themselves define adelayedInit
method.
App scala
delayedInit
is deprecated since 2.11.0
. Also, it has some outstanding bugs which are not fixed.
initCodes:-
I am not sure about the reason for defining the initCodes
as ListBuffer.
delayedInit:-
The init hook. This saves all initialization code for execution within
main
. This method is normally never called directly from user code.
Instead it is called as compiler-generated code for those classes and
objects (but not traits) that inherit from theDelayedInit
trait and
that do not themselves define adelayedInit
method.
App scala
delayedInit
is deprecated since 2.11.0
. Also, it has some outstanding bugs which are not fixed.
initCodes:-
I am not sure about the reason for defining the initCodes
as ListBuffer.
answered Nov 25 '18 at 18:51
notionquestnotionquest
17.5k13152
17.5k13152
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53468358%2fhow-scala-app-trait-and-main-works-internally%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown