utopia-rise/godot-kotlin-native

public lateinit Vector2 is unassigned if has a value of 0,0 in Godot editor

Wavesonics opened this issue · 16 comments

Version:
Godot 3.2

*OS/device including version:
Windows 10

Issue description:
If your Kotlin class has a public lateinit var of Vector2, it's "unassigned" value in the Godot editor is 0,0. Giving it any other value will cause it to be assigned in Kotlin, and everything is fine. However, the user may want 0,0 as their value, and in this case, accessing the var in Kotlin will result in an unassigned lateinit var exception being thrown.

Steps to reproduce:
Run the coroutines sample project.
MirrorBall.kt
lateinit var center: Vector2

Minimal reproduction project:
The coroutines sample project.

One work around that isn't bad would just be declaring it with a default value in Kotlin:
var center = Vector2()

Well, it's not really an issue, just good kotlin practice. If you use a lateinit variable, you have to be sure some external code doesn't call it before being initialiazed.
Lateinit should be use for private/internal variables. If public, it should at least be initialized in the ready method or given a default value.
In other cases, it would be better to just create a nullable variable. That way static checking will force you to handle the null case in the code.
A lazy delegate could also be a solution.

Feel free to fix that in your project layout rework.

@Wavesonics are you ok to fix this in your rework ? So that it is included in first release :)

So it's not so much about Kotlin here, as it is staying consistent with Godot.

@CedNaru Yes in normal Kotlin everything you said about lateinit semantics is true, but in Godot exported value types (which Vector2 is in Godot) are always given a value.

If I have something like this in GDScript:

extends Node2D

export (Vector2) var testVec: Vector2


func _ready():
	if self.testVec == null:
		print("it was null")
	else:
		print("not null")

And I don't change anything in the editor. Meaning the Editor shows 0,0 as the value for testVec. Then testVec is not null.

I don't think this is a critical issue, but if it's possible to have it behave the same as GDScript, I think it'd be a nice-to-have. At the very least, we should call it out as a difference if Vector2 types must be assigned a default value in order to prevent nulls. (Or as you say, just make it nullable)

As for right now, I did make that change in the layout PR.

We should discuss about that I guess. The fact that our kotlin implem should be consistent with engine is right. But we also have to be consistent with language specs as well

Yes, I agree that the Kotlin bindings should be as close as possible to Gdscript.
Godot core type are the primitives of Gdscript, so just like in many languages, declaring a primitive without assignement will give you a "zero" value, not a null.
But I don't think there is much we can do about it. In Kotlin, declaring an object without assignment just result in a null value. Despite all the syntaxic sugar we can use in Kotlin, I don't see how we can declare a property and give it a default value without any assignement or delegate.

Currently we expose all public fields to the editor, maybe instead we introduce a delegate such as var vecTest by expose

Again this would be more like GD Script since not all public fields are exposed automatically.

Then we could have some special handling in there for things like Vector2 that are built in types in Godot.

I like the delegate idea !

I don't see the utility of an "expose" delegate. The annotation should already handle that. If you don't want the property to be exposed, just don't annote it.
Special initializers can be a thing. We can create some kind of lambda Kproperty<X> -> X for each godot coreType.
When a property is registered in the Entry.Kt, we add this lambda in a companion object of the class. Then we only have to make so that GodotObjects call this lambda in their constructor.
The issue we will probably met with this solution is that Kotlin Native freeze static object so I don't know if we can easily update a companion object.

@chippmann has implemented it in his branch, the annotation has a visibleInEditor parameter.

If you are really curious https://github.com/utopia-rise/godot-kotlin/blob/feature/rework_entry_code_generation/REGISTRATION.md
but note: i'm not yet finished. Expect some minor changes and wait for the full PR.

Wow, great work so far! This is looking awesome, especially the strongly typed signals, big fan.

Just love this work !

@Wavesonics Is it ok for you if i close this issue with the merge of #42 ?

@chippmann Ya that's fine

Ha whops