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.
Related
Thanks to #roddy for his answer to my query here
Copy pasting from earlier to set the context :
here is my data structure :
public class Premium{
private Map<String,Map<String,String>> valuesMap = new HashMap<String,Map<String,String>>();
public Map<String, Map<String, String>> getValuesMap() {
return valuesMap;
}
}
Sample values that will be present inside this 'valuesMap' :
Map<String,String> m1= new HashMap<String,String>();
m1.put("death","100");
m1.put("income","50");
valuesMap.put("Male",m1);
valuesMap.put("Female",m2);
....
Thanks to #Roddy now I can extract the map 'm1' embedded within 'valuesMap' for "Male"
rule "rule#7 testing me 001 "
when
// below line extracts 'valuesMap' from Premium object
$pr:Premium($masterMap:valuesMap)
// now have a handle to the embedded map for 'Male'
Map( $male: this["Male"] ) from $masterMap
// defining an object in which I want to populate the value from map obtained for male
$rulesResponse:RulesResponse();
then
System.out.println("rule#7 map " + $map);
// this is where in below code it is failing
$rulesResponse.abc = $innerMap.get("income");
end
when I am trying to extract the string from map against key 'income' and assign it to the 'RulesResponse' object it fails with :
[Error: unable to resolve method using strict-mode: java.lang.Object.get(java.lang.String)]
[Near : {... nse.abc = $innerMap.get("income"); ....}]
The response object is a simple POJO with getter and setter for attribute : abc
public class RulesResponse {
private String abc = "";
public String getAbc() {
return abc;
}
public void setAbc(String abc) {
this.abc = abc;
}
If I try and assign a hard coded value - it works and also reflects after the rule is executed
// this works
$rulesResponse.abc = "hard coded value";
When you get this["Male"] out of the map, it's an Object, not anything typed. It's basically due to type erasure -- Map<String, ?>.
You can get "income" out by doing Map( $income: this["income"]) from $male. Of course, now $income will too also be an Object so you'll need to cast it again. Could be as simple as a (String)$income on the right-hand side, or a $incomeStr: String() from $income on the left.
rule "Example"
when
$pr: Premium( $masterMap: valuesMap != null )
Map( $male: this["Male"] != null ) from $masterMap
Map( $income: this["income"] != null ) from $male
$rulesResponse: RulesResponse()
then
$rulesResponse.abc = (String)$income; // cast as necessary
end
We lose the nested type identity because of type erasure -- you've got a Map<String, ?> which becomes Map<String, Object> in practice.
Strongly suggest using a properly structured POJO instead of a Map as a rule input. Even if your actual code uses these nested maps (bad practice!), you should leverage a transform before calling the rules -- not only will your rules be a lot simpler and easier to work with, but they'll also be much more performant.
Even converting that inner map into an object will make things easier:
class GenderValues {
String death;
String income;
}
class Premium {
Map<String, GenderValues> valuesByGender;
}
Best practice would be to omit the Map entirely.
I came to know that dart mirrors is disabled in flutter but hope that there might be some alternate way to achieve. Mirrors must not be disabled in flutter, it is an important & must have feature.
import 'package:reflectable/mirrors.dart';
import 'package:reflectable/reflectable.dart';
const reflector = const Reflector();
class Reflector extends Reflectable
{
const Reflector() : super(
invokingCapability,
typingCapability,
reflectedTypeCapability,
);
}
#reflector
class Dictionary
{
String english, myLang;
int index;
}
main() {
test();
}
test()
{
ClassMirror classMirror = reflector.reflectType(Dictionary);
classMirror.declarations.values.forEach((field)
{
VariableMirror variableMirror = field;
/*??????????????????????????????????????????
Now How To Get Field types i.e. String & int
How to instantiate class object
How to set fields values
???????????????????????????????????????????*/
});
}
Runtime object instantiation:
Use the method newInstance from ClassMirror. The first argument is the constructor name. Like you haven't name constructors, simple pass an empty string. The second argument are an array of positional constructor arguments. No constructor, empty array.
Dictionary dic = classMirror.newInstance("", []);
Set fields values:
Use the method invokeSetter from InstanceMirror. The first argument is the field name and the second is the value.
InstanceMirror instanceMirror = reflector.reflect(dic);
instanceMirror.invokeSetter("index", 3);
So far I am able to know field(s) type:
ClassMirror classMirror = reflector.reflectType(Dictionary);
VariableMirror variableMirror = classMirror.declarations["english"] as VariableMirror;
Type type = variableMirror.dynamicReflectedType;
print("field: " + variableMirror.simpleName + " has type: " + type.toString());
Now remaining:
Runtime object instantiation?
How to set fields value of instantiated object?
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
My code looks like:
case class SRecord(trialId: String, private var _max:Int) {
def max=_max
def max_=(value:Int):Unit=_max=value
}
Then later on I apply a function onto it:
def groupSummaryRecords(it:Iterator[Option[SRecord]], optionSummary:Option[SRecord]):Option[SRecord] = {
var max=0;
var sRecord1 : Option[SRecord] = None
var i=0
while(it.hasNext) {
var sRecord:Option[SRecord] = it.next();
if(i==0) {
sRecord1 = sRecord;
}
..
}
sRecord1.max=max; // getting 'reassignment to val' compilation error
..
}
Why am i getting this compilation error, and how to fix it ?
If I instead change sRecord and sRecord1 instances to be of type SRecord instead of Option[SRecord] as well as the method signature, it all works fine however.
But in some cases I may have a null SRecord hence the use of None/Some. I am new to Scala, using Option/Some all over feels like a real pain if you ask me, i am just thinking of removing all this Option nonsense and testing for 'null' in good ol' Java, at least my code would work ??!
With the line sRecord1.max=max you are trying to call the max method on an Option[SRecord], not an SRecord. You want to access the contained SRecord (if any) and call the method on that, which can be done using foreach:
sRecord1.foreach(_.max=max)
which is desugared to:
sRecord1.foreach( srec => srec.max=max )
(the actual name "srec" is made up, the compiler will assign some internal name, but you get the idea). If sRecord1 is None, this won't do anything, but if it is Some(srec), the method execution will be passed in to operate on the contained instance.
I am using dotnetrdf and trying to parse some triples with NTriplesParser. I have my own handler RobHandler in which I process each triple in turn.
public class RobHandler : BaseRdfHandler
{
protected override bool HandleTripleInternal(Triple t)
{
string predicateUrl = ((BaseUriNode)(t.Predicate)).Uri.AbsoluteUri;
string value = t.Object.ToString();
}
}
This works fine but I want to get the object minus the language. My objects look like "Lincoln"#en. I could obviously write some code to remove the #en bit, but I'd rather use some library code rather than my own that hard-coded strings like #en. To do this I think I need to create a LiteralNode but there doesn't seem to be a way to get from a string which is what I have (my variable value) to a LiteralNode.
How can I extract just the textual value from an object string?
Actually I think I have the answer myself:
if (t.Object.NodeType == NodeType.Literal)
{
var node = (ILiteralNode)t.Object;
}