Setter is invoked before constructor - oop

I am trying to create instances of class HelloWorld, however it does not work. I found that problem is that setter methods called instead of constructor which should initialize variable name, while variable welcome is optional.
I specified getters and setters for both variables. Browser's console is throwing an error about maximum call stack size. If I comment my getters&setters it stops throwing errors.
Could anyone explain me that strange behaviour?
Also there is another problem with mapping. I'm trying to "return" an array if li elements like in React by using .map(). It gives me the result with commas. How can I get rid of them while printing?
This is a link to my code https://codepen.io/CrUsH20/pen/yzMjzL?editors=1010
Updated #1
I fixed the problem with getters&setters by giving a _ sign for private values.
Now I have a problem with
function print() {
if (invitations) {
document.getElementById('result').innerHTML = invitations.map((e)=> {
return `<li>${e.welcome + e.name}</li>`;
});
}
}
Compiler complains that Type 'string[]' is not assignable to type 'string'. in document.getElementById('result').innerHTML while type was not assigned since it is a html element
Update #2
There are solutions:
1# About conflict with constructor and set&get - I changed object's values by adding to their names _. It solved the conflicts.
2# About commas - I added after map .join('') which solved my problem.

The following code (subset of yours) is a compile error:
class HelloWorld {
constructor(public name: string) {
}
set name(e: string) {
this.name = e;
}
get name(): string {
return this.name;
}
}
Garbage in => Garbage out
Fix
Dont use getter / setters and properties with the same name.

Related

How can I pass property getter as a function type to another function

How can I pass property getter to a function that accepts function type?
Here is an example of what I want achieve:
class Test {
val test: String
get() = "lol"
fun testFun(func: ()->String) {
// invoke it here
}
fun callTest() {
testFun(test::get)
// error: Type mismatch: inferred type is
// KFunction1<#ParameterName Int, Char> but () -> String was expected
}
}
Is there a way?
You can reference the getter by writing ::test (or this::test).
When you write test::get, you are actually referencing the get method on String. That method takes an index and returns the character at that index.
If the property was a var and you want a reference to its setter, you can write ::test::set.
For more info on property references, see here: https://kotlinlang.org/docs/reference/reflection.html#bound-function-and-property-references-since-11
As already mentioned, you can use this::test to refer to the getter. Alternatively, if you have kotlin-reflect, you can do this::test.getter.
When you pass the field as a function, it assumes you mean the getter. As a result, if you want the setter, you have two options:
this::test::set
or
this::test.setter
The latter, just like this::test.getter requires kotlin-reflect, or the program will crash (tested locally with Kotlin 1.2.50)
You can, however, get the getter in another way. But I recommend you just stick with this::test because it's shorter.
You can do:
this::something::get
With just something::get it refers to the method inside the String class, which returns a char at an index. For reference, the method declaration:
public override fun get(index: Int): Char
If you don't mind, just use { test } (e.g. testFun { test }). This will exactly translate to your () -> String. The next best alternative is probably ::test (or this::test) as was already mentioned.
The second has probably only minor (negligible?) impact on performance. I did not test it myself, nor did I found any source which tells something regarding it. The reason why I say this, is how the byte code underneath looks like. Just due to this question I asked myself about the difference of the two: Is the property reference (::test) equivalent to a function accessing the property ({ test }) when passed as argument e.g. `() -> String`?
It seems that you are doing something wrong on logical level.
If you are overriding get method of a variable, then you can access it's value through this get method. Thus, why bother with test::get (which is totally different method, by the way, all you are doing is trying to access char from string), when you can just access variable by it's name?

Why Property must be initialized when there is auto back-end field generated

I'm new to properties and moved from the java to kotlin. I'm struggling with the properties, I learned much about it but initializing the properties are confusing me, when it should be initialized or when it can work without initialization.
Let me explain it by the help of code. Below is the code which is requiring to initialize the property when the back-end field generated, before posting the code let me post the paragraph from the kotlin official website.
A backing field will be generated for a property if it uses the
default implementation of at least one of the accessors, or if a
custom accessor references it through the field identifier.
Now here is the code below.
class Employee{
var data: String // because there are default implementation of get set
// so there will be a back-end field.
}
So I have to initialize it else compilation error.
Ok I can understand it as that some one can access it so there will be no value which can produce the wrong result.
Then I move next to understand it more, so I add custom getter.
class Employee{
var data: String
get() = "default value"
}
This also generate the back-end field so compilation error to initialize it. I can understand it as that there is no initialized value so compiler complain about it.
May be compiler is not smart enough yet to check that there is value which is giving result for this property by custom getter so don't complain about initializing just return that value when required.
But there should be not a problem if any one access it then a default value is already there, then why compiler still complain?
Then I move one step more to implement custom setter too.
class Employee{
var data: String
get() = "default value"
set(value){
field = value
}
}
Still there is the back-end field because we have accessed the field so compiler generate the back-end field.
Same error, should be initialized.
Then the final stage where it works fine as below.
class Employee{
var data: String
get() = "default value"
set(value){
}
}
Now I'm not accessing field in custom getter setter so there is not a back-end field. And it works fine.
So the final question when the property should be intialized? When there is a back-end field generated?
Yes this does not compile:
class Employee{
var data: String
get() = "default value"
}
but this does:
class Employee{
val data: String
get() = "default value"
}
so maybe the compiler by stating Property must be initialized for the wrong declaration, wants from you to admit that data is something that you can not change. I say maybe.
Now the part that does compile:
class Employee{
var data: String
get() = "default value"
set(value){
}
}
This is where you explicitly admit that whatever happens I will never set a value to data, and that's why the compiler feels fine.
Just to save you from more confusion, there's a lot of explaining about Kotlin in the Internet and you may find it very difficult to get familiarized with this relatively new language, but keep in mind that everything needs to be tested by you.
I found the below code in a web page:
class User{
var firstName : String
get() = field
set(value) {field = value}
var lastName : String
get() = field
set(value) {field = value}
}
and it is presented as compilable when it's not.
You kind of answered your own question. There's no backing field when you override both getter and setter, and don't access field.
About your "compiler not being smart enough": get() function is actually RAN at runtime, so writing a lot of compiler code just to evaluate if return value is static and should be injected as default is too niche of a use case.
If your getter depends on another field which is only initialized later, this would cause a lot of confusion as to what default value should be.
Consider this code, assuming value of provider is not defined:
var data: String
get() = provider.data
What would be a default value? Do you want a null? Empty string? Maybe entire object initialization should crash? Explicit default value declaration is needed for that purpose.
That's where idea of lateinit var came to be: if You're certain you will set value before performing any get, You can use this keyword to prevent compiler errors and setting default value.
class Employee{
var data: String
get() = "default value"
}
var means there are both a getter and a setter. Because you didn't write a setter, you get the default one, which accesses the backing field. So there is a backing field, and it needs to be initialized.
But there should be not a problem if any one access it then a default value is already there, then why compiler still complain?
Because that makes the rules simpler: all properties with backing fields must be initialized. This in turn may be because in Java fields don't have to be initialized and this is a known source of bugs. I would like to say it also avoids a possible bug, because presumably you don't actually want the setter's result never to be accessible, but initializing doesn't fix that problem.
I don't see any obvious problem with changing the rules so that a field only needs to be initialized when accessed in the getter, and maybe adding a warning when only one accessor uses field. But I may be missing something, and don't see much benefit to doing so either.

How are overridden properties handled in init blocks?

I'm trying to understand why the following code throws:
open class Base(open val input: String) {
lateinit var derived: String
init {
derived = input.toUpperCase() // throws!
}
}
class Sub(override val input: String) : Base(input)
When invoking this code like this:
println(Sub("test").derived)
it throws an exception, because at the time toUpperCase is called, input resolves to null. I find this counter intuitive: I pass a non-null value to the primary constructor, yet in the init block of the super class it resolves to null?
I think I have a vague idea of what might be going on: since input serves both as a constructor argument as well as a property, the assignment internally calls this.input, but this isn't fully initialized yet. It's really odd: in the IntelliJ debugger, input resolves normally (to the value "test"), but as soon as I invoke the expression evaluation window and inspect input manually, it's suddenly null.
Assuming this is expected behavior, what do you recommend to do instead, i.e. when one needs to initialize fields derived from properties of the same class?
UPDATE:
I've posted two even more concise code snippets that illustrate where the confusion stems from:
https://gist.github.com/mttkay/9fbb0ddf72f471465afc
https://gist.github.com/mttkay/5dc9bde1006b70e1e8ba
The original example is equivalent to the following Java program:
class Base {
private String input;
private String derived;
Base(String input) {
this.input = input;
this.derived = getInput().toUpperCase(); // Initializes derived by calling an overridden method
}
public String getInput() {
return input;
}
}
class Derived extends Base {
private String input;
public Derived(String input) {
super(input); // Calls the superclass constructor, which tries to initialize derived
this.input = input; // Initializes the subclass field
}
#Override
public String getInput() {
return input; // Returns the value of the subclass field
}
}
The getInput() method is overridden in the Sub class, so the code calls Sub.getInput(). At this time, the constructor of the Sub class has not executed, so the backing field holding the value of Sub.input is still null. This is not a bug in Kotlin; you can easily run into the same problem in pure Java code.
The fix is to not override the property. (I've seen your comment, but this doesn't really explain why you think you need to override it.)
The confusion comes from the fact that you created two storages for the input value (fields in JVM). One is in base class, one in derived. When you are reading input value in base class, it calls virtual getInput method under the hood. getInput is overridden in derived class to return its own stored value, which is not initialised before base constructor is called. This is typical "virtual call in constructor" problem.
If you change derived class to actually use property of super type, everything is fine again.
class Sub(input: String) : Base(input) {
override val input : String
get() = super.input
}

A constructor with only 1 argument in Perl 6

I want to override new so that my class can be created only by passing one argument to the constructor, no more and no fewer.
class MyClass {
has $.var1;
method new($var1) {
return MyClass.new(var1 => $var1);
}
}
my $my_class1 = MyClass.new(33);
say $my_class1.var1;
The error is:
Too few positionals passed; expected 2 arguments but got 1
in method new at test1.pl6:28
in method new at test1.pl6:28
in block <unit> at test1.pl6:33
What's up with it?
Custom constructors need to call bless, ie
class MyClass {
has $.var1;
method new($var1) {
return self.bless(var1 => $var1);
}
}
There are a few things that can be improved, eg
one could add an explicit invocant parameter and use :U to make .new() fail when called on instance objects
the explicit return is superfluous - the last expression within the method will be returned anyway, and currently, it actually hurts performance
there's syntactic sugar for passing a named argument held in a variable of the same name
Putting it all together, we end up with
class MyClass {
has $.var1;
method new(MyClass:U: $var1) {
self.bless(:$var1);
}
}
As to where your error comes from:
Your method new is declared to take a positional argument (giving a total count of 2 expected arguments due to the implicit invocant), but the call MyClass.new(var1 => $var1) only passed a named one. Note that said method is the only .new() present in your class, so if the call had actually worked, you would have ended up with infinite recursion!

Using asType with Mixin annotation

I'd like write a custom type conversion Category in Groovy. The goal is to assign the values of a Map to the fields of a Groovy bean. In the future there will be different response types. The values of of the Map are always of type String but will have to be converted into a different data type. To make this work I created a Category class that implements a method named asType. This is a simplified example of my code:
class MapCategory {
static Object asType(Map self, Class clazz) {
if(clazz == Response) {
Response response = new Response()
self.each { key, value ->
response.setProperty(key, value)
}
return response
}
DefaultGroovyMethods.asType(self, clazz)
}
}
class Response {
String result
String message
}
This works just fine when when I apply the category using the use keyword.
use(MapCategory) {
println [result: 'OK', message: 'Success'] as Response
}
However, when I try to use the #Mixin annotation instead it doesn't seem to work correctly. I get the correct response type but all fields are null.
#Mixin(MapCategory)
class MyClass {
def printResponse() {
println [result: 'OK', message: 'Success'] as Response
}
}
Does anybody know why it doesn't work correctly using the annotation?
Mixins don't work that way. You are trying to mix in the method for Map into your MyClass object. The mixin would only work if MyClass extended Map.
Instead, you want to use the use keyword like normal, and just use your category as a category.
Alternatively, you might not need it at all. Did you know that you can, by default, convert any map into any GroovyBean without extra code? Just use the map-based constructor, like so:
#groovy.transform.Canonical // Groovy 1.8, just added for automatic toString method
class Response {
String result
String message
}
println new Response([result: 'OK', message: 'Success'])
println([result: 'bad', message: 'blah'] as Response)
Notice, automatic Map conversion works both ways. It's a built-in feature of Groovy.
Of course, if you need something more complex than just assigning bean properties, this won't help.
Note: I'd give you a link, but the Groovy website appears to be broken, and I can't find code examples. :-(
EDIT: Another Suggestion
Instead of using a Category at all, why don't you let the bean itself handle it:
#groovy.transform.Canonical
class Response {
String result
String message
int num
public void setNum(String num) {
this.num = Integer.parseInt(num)
}
}
def map = [result: 'OK', message: 'Success', num: '35' ]
println map as Response