I recently came across a situation where my standard variable's values are replaced by the default one even if I have assigned a value with the constructor using init block.
What I tried was:
class Example(function: Example.() -> Unit) {
init {
function()
}
var name = "default name"
}
// assigning it like this:
val example = Example { name = "new name" }
// print value
print(example.name) // prints "default name"
After struggling a bit, I have found that the position of the init block matters. If I put the init block at the last in the class, It initializes the name with default one first and then calls the function() which replaces the value with the "new name".
And If I put it first, it doesn't found the name and it is replaced by the "default name" when properties are initialized.
This is strange to me. Can anyone explain why this has happened?
The reason is kotlin follows top-to-bottom approach
From the documents (An in-depth look at Kotlin’s initializers) Initializers (property initializers and init blocks) are executed in the order that they are defined in the class, top-to-bottom.
You can define multiple secondary constructors, but only one will be called when you create a class instance unless the constructor explicitly calls another one.
Constructors can also have default argument values which are evaluated each time the constructor is called. Like property initializers, these can be function calls or other expressions that will run arbitrary code.
initializers are run top to bottom at the beginning of a class’ primary constructor.
This is correct way
class Example(function: Example.() -> Unit) {
var name = "default name"
init {
function()
}
}
Java constructor is just a method that run after object creation. Before running the constructor, all the class fields get initialized.
In Kotlin there are two types of constructors namely primary constructor and the secondary constructor. I see primary constructor as a regular java constructor that supports field encapsulation built-in. After compilation, primary constructor fields are put on the top of the class if they have declared visible to the whole class.
In java or kotlin, constructor is invoked after initializing class fields. But in primary constructor we cannot write any statements. If we want to write statements that need to be executed after object creation, we have to put them in the initialization blocks. But init blocks are executed as they appear in the class body. We can define multiple init blocks in the class. They will be executed from top to the bottom.
Lets do some experiment with init blocks..
Test.kt
fun main() {
Subject("a1")
}
class Element {
init {
println("Element init block 1")
}
constructor(message: String) {
println(message)
}
init {
println("Element init block 2")
}
}
class Subject(private val name: String, e: Element = Element("$name: first element")) {
private val field1: Int = 1
init {
println("$name: first init")
}
val e2 = Element("$name: second element")
init {
println("$name: second init")
}
val e3 = Element("$name: third element")
}
Lets compile the above and run it.
kotlinc Test.kt -include-runtime -d Test.jar
java -jar Test.jar
The output of the above program is
Element init block 1
Element init block 2
a1: first element
a1: first init
Element init block 1
Element init block 2
a1: second element
a1: second init
Element init block 1
Element init block 2
a1: third element
As you can see, first primary constructor was called, before secondary constructor, all the init blocks were executed. This is because init blocks become a part of the constructor in the order they appear in the class body.
Lets compile the kotlin code to java byte code and decompile it back to java. I used jd-gui to decompile java classes. You can install it with yay -S jd-gui-bin in arch linux based distributions.
Here is the output I got after decompiling Subject.class file
import kotlin.Metadata;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
#Metadata(mv = {1, 6, 0}, k = 1, xi = 48, d1 = {"\000\034\n\002\030\002\n\002\020\000\n\000\n\002\020\016\n\000\n\002\030\002\n\002\b\007\n\002\020\b\030\0002\0020\001B\027\022\006\020\002\032\0020\003\022\b\b\002\020\004\032\0020\005\006\002\020\006R\021\020\007\032\0020\005\006\b\n\000\032\004\b\b\020\tR\021\020\n\032\0020\005\006\b\n\000\032\004\b\013\020\tR\016\020\f\032\0020\rX\006\002\n\000R\016\020\002\032\0020\003X\004\006\002\n\000"}, d2 = {"LSubject;", "", "name", "", "e", "LElement;", "(Ljava/lang/String;LElement;)V", "e2", "getE2", "()LElement;", "e3", "getE3", "field1", ""})
public final class Subject {
#NotNull
private final String name;
private final int field1;
#NotNull
private final Element e2;
#NotNull
private final Element e3;
public Subject(#NotNull String name, #NotNull Element e) {
this.name = name;
this.field1 = 1;
System.out
.println(Intrinsics.stringPlus(this.name, ": first init"));
this.e2 = new Element(Intrinsics.stringPlus(this.name, ": second element"));
System.out
.println(Intrinsics.stringPlus(this.name, ": second init"));
this.e3 = new Element(Intrinsics.stringPlus(this.name, ": third element"));
}
#NotNull
public final Element getE2() {
return this.e2;
}
#NotNull
public final Element getE3() {
return this.e3;
}
}
As you can see all the init blocks have become a part of the constructor in the order they appear in the class body. I noticed one thing different from java. Class fields were initialized in the constructor. Class fields and init blocks were initialized in the order they appear in the class body. It seems order is so important in kotlin.
As stated in the Kotlin docs:
During an instance initialization, the initializer blocks are executed in the same order as they appear in the class body, interleaved with the property initializers: ...
https://kotlinlang.org/docs/classes.html#constructors
Related
I am receiving a NullPointerException which I believe is due to the way objects are initialised but cannot find any supporting documentation.
I have this example code which illustrates the problem in Scala 2.12.7, I have found repeatable results in Scala 3.1.3 also:
abstract class Item(val collectionName: String)
abstract class ItemCollection(val name: String)
object TechItems extends ItemCollection("tech") {
// referencing 'name' from 'ItemCollection' superclass
case object TV extends Item(collectionName = name)
val items: Map[String, Item] = Map("tv" -> TV)
}
object Test1 extends App {
// prints 'tech'
println(TechItems.items.get("tv").map(_.collectionName))
}
object Test2 extends App {
// prints 'tech'
println(TechItems.TV.collectionName)
// throws NullPointerException
println(TechItems.items.get("tv").map(_.collectionName))
}
When running Test1, the code behaves as you'd expect. When running Test2, we now receive a NullPointerException when accessing the map after accessing the TV object directly.
When I no longer reference a field from the superclass, the issue no longer occurs:
...
object TechItems extends ItemCollection("tech") {
// using String instead of reference to superclass field
case object TV extends Item(collectionName = "mycollection")
val items: Map[String, Item] = Map("tv" -> TV)
}
...
object Test2 extends App {
// prints 'mycollection'
println(TechItems.TV.collectionName)
// prints 'Some(mycollection)'
println(TechItems.items.get("tv").map(_.collectionName))
}
My current understanding of how TechItems is initialised:
We access TechItems.TV.collectionName which begins initialising TechItems
An ItemCollection("tech") is created whose fields are then available inside of TechItems (depending on access modifiers of said superclass fields)
TV is initialised and references the superclass field name
items is initialised and references TV as a value for key "tv"
I am sure that understanding is wrong but that is what I am here to learn.
My current theory for the NullPointerException:
We access TechItems.TV.collectionName which begins initialising TechItems
items is initialised alongside TV, but items captures an uninitialised TV as null
Our access to TechItems.TV.collectionName returns the value of "tech"
TechItems.items.get("tv") returns Some(null) because TV at the point of initialising items was null, due to not being initialised.
NullPointerException is thrown
To me it feels like a somewhat farfetched theory. I am sure my lack of understanding is shown here and there is an explanation in some documentation that I have failed to find. Why do I get this NullPointerException? What is the initialisation order? And why does removing the reference to a superclass field affect this initialisation?
Wow, this is a good one!
Here is what I think is going on ...
Consider this "pseudo-java" code, that I believe more-or-less accurately reflects what is actually happening in the JVM:
class TechItems extends ItemCollection {
static MODULE = new TechItems("tech")
static class TV extends Item {
static MODULE = new TV(TechItems.MODULE.name)
}
val items = Map("tv" -> TV.MODULE)
}
So, now, when you do print(TechItems.TV.MODULE.collectionName),
TechItems.MODULE gets constructed, because we need to pull name out of it to create TV.
This constructor, runs to the Map("tv" -> TV.MODULE) line, and puts null into the map (TV.MODULE is still null - we are only figuring out what to pass to its constructor.
If you use "mycollection" instead of name, it becomes
static MODULE = new TV("mycollection"), which doesn't trigger TechItems constructor.
What happens when you don't access TV before looking at items? Well, in that case, TechItems.MODULE gets initialized first, so, by the time you get to the new TV thing, as part of constructing the items, TechItems.MODULE.name is already available, so TV.MODULE can be created and put into the map.
Dima is right. In fact, without inspecting the decompiled code, it would be harder to figure out what is happening under the hood. For simplicity, let's assume you just do these 2 calls in order (it will reproduce the issue):
println(TechItems.TV) // prints 'TV'
println(TechItems.items) // prints 'Map(tv -> null)'
Now let's decompile the code and show only the relevant parts. (I removed unnecessary code to be easier to follow) First these calls:
Predef$.MODULE$.println((Object)Main.TechItems$.TV$.MODULE$);
Predef$.MODULE$.println((Object)Main.TechItems$.MODULE$.items());
This was our Main. Now TechItems and TV:
public static class TechItems$ extends ItemCollection {
public static final TechItems$ MODULE$;
private static final Map<String, Main.Item> items;
static {
MODULE$ = new TechItems$();
items = (Map)Predef$.MODULE$.Map().apply((Seq)ScalaRunTime$.MODULE$.wrapRefArray(
(Object[])new Tuple2[] {
Predef.ArrowAssoc$.MODULE$.$minus$greater$extension(
Predef$.MODULE$.ArrowAssoc((Object)"tv"), (Object)TV$.MODULE$)
}));
}
public Map<String, Main.Item> items() {
return TechItems$.items;
}
public TechItems$() {
super("tech");
}
public static class TV$ extends Main.Item implements Product, Serializable {
public static final TV$ MODULE$;
static {
Product.$init$((Product)(MODULE$ = new TV$()));
}
public TV$() {
super(TechItems$.MODULE$.name());
}
}
When calling our first println statement we trigger the evaluation of TechItems.TV which translates to TechItems$.TV$.MODULE$. The MODULE$ is just a static final reference of TV that gets initialized in the static block of TV. To get initialized, it starts executing the static block, which in turn calls TV's constructor, new TV$() which in turn triggers the call to TechItems via: super(TechItems$.MODULE$.name());
This is the part where it gets interesting: TechItems$.MODULE$ is just the static final reference of TechItems, that was not yet referenced, so it was not yet initialized. Again, in the same manner, to get initialized, the static block of TechItems gets called. But this time the static block is different: It has to initialize TechItems$.MODULE$ and items as well, because both reside in the same static block.
Since we are in the middle of initializing TV$.MODULE$, and we just called items which requires the same reference - that we have not yet finished initializing, this reference is null at this point in time, so items is executed having TV$.MODULE$ as null.
After this, the static block of TechItems$.MODULE$ finishes, the static block of TechItems.TV finishes and we get printed TV at the console. The second print becomes self-explanatory. The call to items() returns TechItems$.items that we just evaluated in the previous call to TV, so items return Map(tv -> null) which gets printed.
Observations:
Using case object TV extends Item(collectionName = name) is precisely what triggers the issue. The logical idea is that, you do not want to evaluate items before TV finishes evaluation. So one can do 2 things: 1 - either not call TV before first calling items or just TechItems - which will trigger the evaluation of TV, and thus the correct initialization of items - or 2 (better solution) - delay evaluation of items as much as possible, until you really needed.
Naturally - the solution to the second point is to make items a lazy val. If we do this, the issue goes away, because items will no longer be evaluated unless explicitly referenced by us, and it will no longer trigger evaluation when calling just TV. And if we call items first, it will trigger TV's evaluation first. I can't show you the difference in the decompiled code because only the ScalaSignature differs: keywords like lazy are implemented as "pickled" signature bytes since these are easily picked up by the JVM through reflection.
Changing it to case object TV extends Item(collectionName = "mycollection") is also a fix. Since you no longer call super(TechItems$.MODULE$.name()); from TV at all, items's evaluation is no longer triggered when just TV is called. The call to TV's constructor becomes super("mycollection"), so the second print would then correctly evaluate items to Map(tv -> TV). This is why the null goes away when you change it.
This is an example of a circular dependency: TV "kind of" needs items and items needs TV - and the order of initialization really makes the difference between a working code and a code that throws nulls at unexpected times.
Since TV is presumably initialized lazy, making items lazy as well should theoretically remove the circular dependency.
An object definition in Scala behaves much like a lazy val with an annonymous class, that gets initialized on demand, the first time it is used.
So the first instinct when you see an object inside another object, is to assume the former object will be lazily initialized (unless explicitly referenced). Because items does reference TV explicitly, even if you don't call TV explicitly, TV will be evaluated either when referencing just TechItems or directly items, whichever comes first, because both are in the same static context, as we saw.
I'm a beginner learning dart from the book dart apprentice and I reached where they were discussing constructors in dart classes, the book was implying that constructors create instances of the class which I understood but I needed more info about constructors. So I googled and some results repeated what was already in the book about it being used to create instances of a class while others also showed that it's used to instantiate class properties, but my problem is with the other answer which I found that they are used to instantiate properties of a class, but my question is: I instantiate all class properties when I create the class by declaring the property variables, like this:
class UserClass{
userClassProperty = "";
anotherUserClassProperty = ""; }
why is the constructor also needed to instantiate class properties?
Often, values are unique to every class instance.
Consider the following example:
class Point {
final int x;
final int y;
const Point(this.x, this.y);
double get distanceToOrigin => sqrt(x * x + y * y);
}
If the x and y values were defined inside the class, it would be pretty useless. Instead, different Point objects can be instantiated with different values, which means the same code can be used for different situations.
Ok, so constructors instantiate or start a class by collecting all the data the class needs to start to start working. Constructors are so important that the dart compiler provides one even if you don't explicitly create one. For example, you create a class for mammals like this :
class Mammal{
String name = "cat";
int numberOfLegs = 2;
}
Although you don't explicitly add a constructor the dart compiler adds a default constructor like this :
class Mammal{
Mammal(); //This is added by dart during the class instantiation by default.
String name = "cat";
int numberOfLegs = 2;
}
Yeah, that's how crucial constructors are to the dart compiler.
And on the topic of why are they necessary even when you declare all the properties by yourself in the class, as hacker1024 said it would make the class pretty useless, as the point of the existence of classes is to create variants but with different properties. Not adding a constructor to your class and defining all the properties in the class would mean that your class doesn't take property arguments which in turn also means that different variants of your class can't be created. Again this goes directly against the point of the existence of dart classes. For example, you have a class like this :
class Mammals{
Strig name = "Human";
int numberOfLegs = 2;
bool hasFur = false;
}
final cat = Mammal();
final human = Mammal();
print(cat.numberOfLegs); //Prints 2
//2
print(human.numberOfLegs); //Also prints 2
//2
print(cat.hasFur);
// false
Yeah, this class is problematic. Cats with 2 legs? You would agree with me that that's not how things are in reality. And also the class is pretty useless in the sense that it's not modular, no matter which kind of mammal we create be it a cat, a sheep or even a cow the name property is going to be the default one we set, that is "Human". When we create a class to simulate mammals we want to be able to define what kind of properties it has, not use some fixed values. So you want to create a class which has a constructor like this :
class Mammals{
Mammals(String name,int noOfLegs, bool hasFur){
this.name = name;
this.noOfLegs = noOfLegs;
this.hasFur = hasFur;
}
String name = "";
int noOfLegs = 0;
bool hasFur = False;
}
final cat = Mammal("Cat", 4, True); //Now you can pass in the properties ou want.
final human = Mammal("Human", 2, false);
print(cat.name); //This prints the customized name of the object cat instead of some fixed value
//Cat
print(human.name); //This prints the customized name of the object human
Now we have two instances of the class with separate property values.
Although this adds a little more code, the modularity benefit is worth it.
I have to following scenario
case class A(name:String)
class Eq { def isMe(s:String) = s == "ME" }
val a = List(A("ME")).toDS
a.filter(l => new Eq().isMe(l.name))
Does this create a new object Eq every time for each data point on each executor ?
Nice one! I didn't know there is a different filter method for a typed dataset.
In order to answer your question, I will do some deep dive into Spark internals.
filter on a typed Dtaset has the following signature:
def filter(func: T => Boolean): Dataset[T]
Note that func is parameterized with T, hence Spark needs to deserialize both your object A along with the function.
TypedFilter Main$$$Lambda$, class A, [StructField(name,StringType,true)], newInstance(class A)
where Main$$$Lambda$ is a randomly generated function name
During optimization phase it might be eliminated by the EliminateSerialization rule if the following condition is met:
ds.map(...).filter(...) can be optimized by this rule to save extra deserialization, but ds.map(...).as[AnotherType].filter(...) can not be optimized.
If the rule is applicable TypedFilter is replaced by Filter.
The catch here is a Filter's condition. In fact, it is another special expression named Invoke where:
targetObject is the filter function Main$$$Lambda$
functionName is apply since it is a regular Scala function.
Spark eventually runs in one of these two modes - generate code or interpreter. Let's concentrate on the first one as it is the default.
Here is a simplified stack trace of the methods invocation that will generate the code
SparkPlan.execute
//https://github.com/apache/spark/blob/03e30063127fd71bef8a14553381e805fe5b6679/sql/core/src/main/scala/org/apache/spark/sql/execution/WholeStageCodegenExec.scala#L596
-> WholeStageCodegenExec.execute
[child: Filter]
-> child.execute
[condition Invoke]
-> Invoke.genCode
//https://github.com/apache/spark/blob/branch-2.4/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/objects/objects.scala#L345
-> doGenCode
Simplified code after generation phase:
final class GeneratedIteratorForCodegenStage1 extends BufferedRowIterator {
private Object[] references;
private scala.collection.Iterator input;
private UnsafeRowWriter writer = new UnsafeRowWriter();
public GeneratedIteratorForCodegenStage1(Object[] references) {
this.references = references;
}
public void init(Iterator inputs) {
this.inputs = inputs;
}
protected void processNext() throws IOException {
while (input.hasNext() && !stopEarly()) {
InternalRow row = input.next();
do {
//Create A object
UTF8String value = row.getUTF8String(0));
A a = new A(value.toString)
//Filter by A's value
result = (scala.Function1) references[0].apply(a);
if (!result) continue;
writer.write(0, value)
append((writer.getRow());
}
if (shouldStop()) return;
}
}
}
We can see that projection is constructed with an array of objects passed in references variable. But where and how many times the references variable is instantiated?
It is created during WholeStageCodegenExec and instantiated only once per partition.
And this leads us to the answer that, however, filter function will be created only once per partition and not per data point, the Eq and A classes will be created per data point.
If you are curious about where it has been added to the code context:
It happens here
where javaType is scala.function1 .
and value is the implementation - Main$$$Lambda$
I know this is a very fundamental question but answer to this will solve many of my doubts.
val new_parent = ParentDetails(intent.extras.getString("name"),
intent.extras.getString("email"),
intent.extras.getString("parent_relation"),
intent.extras.getString("locationdata"))
println(new_parent.tostring())
The code above doesn't print the various fields and their values present in the class.
The ParentDetails is a model I have created with some fields that are initialized. The ParentDetails model:
class ParentDetails {
var parent_id: Int = 0
var parent_name: String = ""
var parent_email: String = ""
var parent_relation: String = ""
var parent_location: String=""
constructor(parent_name: String, parent_email: String, parent_relation: String,parent_location:String) {
this.parent_name = parent_name
this.parent_email = parent_email
this.parent_relation = parent_relation
this.parent_location = parent_location
}
public fun getparentId(): Int {
return parent_id
}
fun ParentDetailsprintme() {
println(parent_name)
println(parent_email)
println(parent_relation)
println(parent_location)
}
}
In fact, it prints null and accessing individual fields, it prints empty string(the way it was initialized).
How do we explain this?
As I understand your problem is that calling println(new_parent.tostring()) does not print what you would like to print in function ParentDetailsprintme.
First of all, you have a typo, the correct call would be new_parent.toString().
Note that it could have been simplified as println(new_parent).
It does not print that you defined in the ParentDetailsprintme method, as the method is not called.
What println(new_parent.toString()) prints, is actually the hashcode of the object, as this is the default behaviour of every object.
To make it work call it like println(new_parent.ParentDetailsprintme()) or override the toString() method for example as:
override fun toString() = "$parent_name $parent_email $parent_relation $parent_location"
then the following
val new_parent = ParentDetails("myName", "myEmail", "myParent_relation", "myLocationdata")
println(new_parent)
should print
myName myEmail myParent_relation myLocationdata
Kotlin's println function simply calls System.out.println(message) under the hood which will call String.valueOf() (e.g. String.valueOf(Object object) for objects, which will call the toString() method of the passed object).
/** Prints the given message and newline to the standard output stream. */
#kotlin.internal.InlineOnly
public inline fun println(message: CharArray) {
System.out.println(message)
}
Update ("Using data class method also works"):
If you make the class to be a data class:
data class ParentDetails(
val parent_id: Int = 0,
val parent_name: String = "",
val parent_email: String = "",
val parent_relation: String = "",
val parent_location: String = ""
)
and then you execute
val new_parent = ParentDetails(0, "myName", "myEmail", "myParent_relation", "myLocationdata")
println(new_parent)
you will receive as result
ParentDetails(parent_id=0, parent_name=myName, parent_email=myEmail, parent_relation=myParent_relation, parent_location=myLocationdata)
This is because data classes override the toString() function:
The compiler automatically derives the following members from all
properties declared in the primary constructor:
equals()/hashCode() pair;
toString() of the form "User(name=John, age=42)";
Did you check that you receive valid data from your intent.extras?
Also I suggest you use data class for your models.
It will look something like this:
data class ParentDetails(
var parent_id: Int = 0,
var parent_name: String = "",
var parent_email: String = "",
var parent_relation: String = "",
var parent_location: String = ""
)
You will be able to use it like this :
val new_parent = ParentDetails(
parent_name = intent.extras.getString("name"),
parent_email = intent.extras.getString("email"),
parent_relation = intent.extras.getString("parent_relation"),
parent_location = intent.extras.getString("locationdata")
)
println(new_parent.tostring())
As already mentioned, you have a typo. toString returns the hashcode of an object unless it's overridden to return something else. Look up the original implementation for more details.
By overriding the toString method, you change what it returns, and through that, what is printed when you print(someClass). DVarga showed that in their answer.
Data classes auto-generate a toString method containing the content of the class. So creating a data class is a shortcut to getting output containing the data.
The reason the method you had didn't work is because you didn't call it. if you call it instead of toString, you would get the data printed.
Also, toString is explicitly called when you print a class. You don't need to call print(someInstance.toString()), print(someInstance) is enough.
And while I'm writing an answer, you don't need to use secondary constructors in Kotlin. Primary constructors would shorten your code significantly, whether it's a data class or not. Also, you should look into naming conventions.
Method
method() {}
function
function func() {}
Above is just to elaborate difference between method and function.
class Student {
constructor(name, age) {
this.name = name;
this.age = age;
}
method1(){}
}
In the above class, after writing the definition.
I want to add a method2 to the class, similar to the way method1 is there.
I can add a function like soo
Student.prototype.func = function(){...}
But I do not have a way to add a method on the same class. and inside function I will not be able to use super as that is just available inside the method.
Is there a way I can add method after the class is defined ?
So that I will be able to use super inside that.
As has already been explained, you can only use super() inside the regular class definition. But, long before we had ES6, we were calling parent method implementations manually. It can be done using the parent's prototype:
class Person {
talk() {
// some implementation here
}
}
class Student extends Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
Student.prototype.talk = function(data) {
// now call base method manually
Person.prototype.talk.call(this, data);
// then do our extra work
log(data);
}
Of course, normally you could just declare all your methods within the class declaration so this would not be something you would normally need to do.
Your snippet adding a new property to the prototype is only approach for adding a function later. One main difference in this case is that simple assignment like that will create the property as enumerable by default, whereas class syntax would create is as non-enumerable. You could use
Object.defineProperty(Student.prototype, "func", {
configurable: true,
writable: true,
value: function() {
},
});
to address that at least.
Unfortunately as you've seen, adding things to the prototype afterward does not allow usage of super.foo. There is no way for this to be supported, because the behavior of super is based specifically on the lexical nesting of the method syntax method(){} being inside of the class syntax. Methods added programmatically later on would have no way to know which prototype is the "super" one.