So, the question is in the title. I declared some properties in my classes using 'never' keyword so I may set the values of these properties only once, in the constructor. However, I get the following error:
Cannot access field or identifier %name% for writing
Example of the problematic code:
class TreeAbility
{
public var id(default, never):String;
public var maxLvl(default, never):Int;
public function new(id:String, maxLvl:Int)
{
Assert.assert(maxLvl > 0);
this.id = id; (*)
this.maxLvl = maxLvl; (*)
this.currentLvl = 0;
}
}
The lines marked with (*) throw the access error
I believe the never write property means that writing/setting the variable is never allowed, not even within the constructor. See: https://haxe.org/manual/class-field-property.html
Perhaps you are looking for the final keyword, which is coming in Haxe 4. For instance fields, it allows assignment to the variable only from the class constructor. Confirmed here: https://haxe.org/download/version/4.0.0-preview.2/ and https://github.com/HaxeFoundation/haxe/issues/6584
Related
I have a Kotlin class with a member object:
private var strings = object { var foo = ""; var bar = "" }
Inside my class's functions, I can reference strings.foo and strings.bar.
But when I make strings a public var, suddenly all of its members become "unresolved references". Why?
class Foo {
// Making this `private` fixes the errors below for some reason
public var strings = object {
var foo = ""
var bar = ""
}
fun initialize() {
strings.foo = getFoo() // "Unresolved reference: foo"
strings.bar = getBar() // "Unresolved reference: bar"
}
}
(What I'm trying to do here is expose a whole bunch of string resources as constants so I don't have to use the literal string values throughout my code. I'm actually using lateinit var for each member but that doesn't change the result here.)
strings is defined with an object literal. You probably want to use an regular object declaration instead:
object Strings {...}
strings = Strings()
With the object literal, strings is an anonymous object whose type is "usable (and visible) only in the scope where it is declared".
without any explicitly declared supertype, menaing Any is implicit super type of this object.
When you make strings a public var, it escapes the current scope and is implicitly downcasted to its supertype; without any explicitly declared supertype, the supertype is Any, so of course you get errors trying to reference the properties foo and bar.
From Kotlin spec
The main difference between a regular object declaration and an anonymous object is its type. The type of an anonymous object is a special kind of type which is usable (and visible) only in the scope where it is declared. It is similar to a type of a regular object declaration, but, as it cannot be used outside the declaring scope, has some interesting effects.
When a value of an anonymous object type escapes current scope:
If the type has only one declared supertype, it is implicitly downcasted to this declared supertype;
If the type has several declared supertypes, there must be an implicit or explicit cast to any suitable type visible outside the scope, otherwise it is a compile-time error.
Note: an implicit cast may arise, for example, from the results of type inference.
Note: in this context “escaping current scope” is performed immediately if the corresponding value is declared as a non-private global- or classifier-scope property, as those are parts of an externally accessible interface.
You could also use a Companion object:
companion object Strings {
var foo = ""
var bar = ""
}
fun init(){
foo = getFoo()
bar = getBar()
}
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.
I hit a problem with some Kotlin code and I found out it was related to calling a method that assigns some variables from an init block (or a secondary constructor for that matter, either reproduces the problem).
MCVE:
abstract class Shader(/*Input arguments omitted for the sake of an MCVE*/){
init{
//Shader loading and attaching, not relevant
bindAttribs()//One of the abstract methods. In my actual program, this uses OpenGL to bind attributes
//GLSL program validation
getUniforms()//Same as the previous one: abstract method using GL calls to get uniforms. This gets locations so an integer is set (the problem)
}
abstract fun getUniforms();//This is the one causing problems
abstract fun bindAttribs();//This would to if primitives or non-lateinit vars are set
}
abstract class BoilerplateShader() : Shader(){
var loc_projectionMatrix: Int = 404//404 is an initial value. This can be anything though
var loc_transformationMatrix: Int = 404
var loc_viewMatrix: Int = 404
override fun getUniforms(){
//These would be grabbed by using glGetUniformLocations, but it's reproducable with static values as well
loc_projectionMatrix = 0
loc_transformationMatrix = 1
loc_viewMatrix = 2
println(loc_projectionMatrix.toString() + ", " + loc_transformationMatrix + ", " + loc_viewMatrix)
}
//debug method, only used to show the values
fun dump(){
println(loc_projectionMatrix.toString() + ", " + loc_transformationMatrix + ", " + loc_viewMatrix)
}
}
class TextureShader() : BoilerplateShader(){
override fun bindAttribs() {
//This doesn't cause a problem even though it's called from the init block, as nothing is assigned
//bindAttrib(0, "a_position");
//bindAttrib(1, "a_texCoord0");
}
}
//Other repetitive shaders, omitted for brevity
Then doing:
val tx = TextureShader()
tx.dump()
prints:
0, 1, 2
404, 404, 404
The print statements are called in order from getUniforms to the dump call at the end. It's assigned fine in the getUniforms method, but when calling them just a few milliseconds later, they're suddenly set to the default value of (in this case) 404. This value can be anything though, but I use 404 because that's a value I know I won't use for testing in this particular MCVE.
I'm using a system that relies heavily on abstract classes, but calling some of these methods (getUniforms is extremely important) is a must. If I add an init block in either BoilerplateShader or TextureShader with a call to getUniforms, it works fine. Doing a workaround with an init function (not an init block) called after object creation:
fun init(){
bindAttribs();
getUniforms();
}
works fine. But that would involve the created instance manually calls it:
val ts = TexturedShader();
ts.init();
ts.dump()
which isn't an option. Writing the code that causes problems in Kotlin in Java works like expected (considerably shortened code, but still reproducable):
abstract class Shader{
public Shader(){
getUniforms();
}
public abstract void getUniforms();
}
abstract class BoilerplateShader extends Shader{
int loc_projectionMatrix;//When this is initialized, it produces the same issue as Kotlin. But Java doesn't require the vars to be initialized when they're declared globally, so it doesn't cause a problem
public void getUniforms(){
loc_projectionMatrix = 1;
System.out.println(loc_projectionMatrix);
}
//and a dump method or any kind of basic print statement to print it after object creation
}
class TextureShader extends BoilerplateShader {
public TextureShader(){
super();
}
}
and printing the value of the variable after initialization of both the variable and the class prints 0, as expected.
Trying to reproduce the same thing with an object produces the same result as with numbers when the var isn't lateinit. So this:
var test: String = ""
prints:
0, 1, 2, test
404, 404, 404,
The last line is exactly as printed: the value if test is set to an empty String by default, so it shows up as empty.
But if the var is declared as a lateinit var:
lateinit var test: String
it prints:
0, 1, 2, test
404, 404, 404, test
I can't declare primitives with lateinit. And since it's called outside a constructor, it either needs to be initialized or be declared as lateinit.
So, is it possible to initialize primitives from an overridden abstract method without creating a function to call it?
Edit:
A comment suggested a factory method, but that's not going to work because of the abstraction. Since the attempted goal is to call the methods from the base class (Shader), and since abstract classes can't be initialized, factory methods won't work without creating a manual implementation in each class, which is overkill. And if the constructor is private to get it to work (avoid initialization outside factory methods), extending won't work (<init> is private in Shader).
So the constructors are forced to be public (whether the Shader class has a primary or secondary constructor, the child classes have to have a primary to initialize it) meaning the shaders can be created while bypassing the factory method. And, abstraction causes problems again, the factory method (having to be abstract) would be manually implemented in each child class, once again resulting in initialization and manually calling the init() method.
The question is still whether or not it's possible to make sure the non-lateinit and primitives are initialized when calling an abstract method from the constructor. Creating factory methods would be a perfect solution had there not been abstraction involved.
Note: The absolutely best idea is to avoid declaring objects/primitives in abstract functions called from the abstract class' constructor method, but there are cases where it's useful. Avoid it if possible.
The only workaround I found for this is using by lazy, since there are primitives involved and I can convert assignment to work in the blocks.
lateinit would have made it slightly easier, so creating object wrappers could of course be an option, but using by lazy works in my case.
Anyways, what's happening here is that the value assigned to the int in the constructor is later overridden by the fixed value. Pseudocode:
var x /* = 0 */
constructor() : super.constructor()//x is not initialized yet
super.constructor(){
overridden function();
}
abstract function()
overridden function() {
x = 4;
}
// The assignment if `= 0` takes place after the construction of the parent, setting x to 0 and overriding the value in the constructor
With lateinit, the problem is removed:
lateinit var x: Integer//x exists, but doesn't get a value. It's assigned later
constructor() : super.constructor()
super.constructor(){
overridden function()
}
abstract function()
overridden function(){
x = Integer(4);//using an object here since Kotlin doesn't support lateinit with primtives
}
//x, being lateinit and now initialized, doesn't get re-initialized by the declaration. x = 4 instead of 0, as in the first example
When I wrote the question, I thought Java worked differently. This was because I didn't initialize the variables there either (effectively, making them lateinit). When the class then is fully initialized, int x; doesn't get assigned a value. If it was declared as int x = 1234;, the same problem in Java occurs as here.
Now, the problem goes back to lateinit and primitives; primitives cannot be lateinit. A fairly basic solution is using a data class:
data class IntWrapper(var value: Int)
Since the value of data classes can be unpacked:
var (value) = intWrapperInstance//doing "var value = ..." sets value to the intWrapperInstance. With the parenthesis it works the same way as unpacking the values of a pair or triple, just with a single value.
Now, since there's an instance with an object (not a primitive), lateinit can be used. However, this isn't particularly efficient since it involves another object being created.
The only remaining option: by lazy.
Wherever it's possible to create initialization as a function, this is the best option. The code in the question was a simplified version of OpenGL shaders (more specifically, the locations for uniforms). Meaning this particular code is fairly easy to convert to a by lazy block:
val projectionMatrixLocation by lazy{
glGetUniformLocation(program, "projectionMatrix")
}
Depending on the case though, this might not be feasible. Especially since by lazy requires a val, which means it isn't possible to change it afterwards. This depends on the usage though, since it isn't a problem if it isn't going to change.
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.
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
}