Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot cast typed arrays using type hints #72627

Open
the-eclectic-dyslexic opened this issue Feb 2, 2023 · 6 comments
Open

Cannot cast typed arrays using type hints #72627

the-eclectic-dyslexic opened this issue Feb 2, 2023 · 6 comments

Comments

@the-eclectic-dyslexic
Copy link

the-eclectic-dyslexic commented Feb 2, 2023

Godot version

4.0 beta 17

System information

Arch Linux

Issue description

type hints for typed arrays seem to be entirely ignored. The particular use case I am having trouble with seems to be related both to Dictionaries not being typed as mentioned in #56, and to the typed array implementation change in #69248.

Steps to reproduce

Attempt to run the following script, and note that the interpreter complains about trying to assign an Array to an Array[int], despite trying to cast the untyped Array to Array[int] in that very line. Commenting out the lines related to the Array[int] will still leave you with an issue as you get the same error trying to pass an Array into an argument for an Array[String].

class_name ArrayCaster extends Node

var my_dictionary : Dictionary = {
	1 : "one",
	5 : "five",
	31 : "thirty-one",
}


func _ready():
	var arr : Array[int] = my_dictionary.keys() as Array[int]
	print(sum(arr))
	print_all(my_dictionary.values() as Array[String])


static func sum(ints: Array[int]) -> int:
	var result = 0
	for i in ints:
		result += i
	return result


static func print_all(strings: Array[String]) -> void:
	for s in strings:
		print(s)

Minimal reproduction project

array_casting_from_dictionary.zip

@KoBeWi
Copy link
Member

KoBeWi commented Feb 2, 2023

Same issue as #72620
Last time I asked there are no plans to add typed array casting, you will be able to use constructor, like

var arr : Array[int] = Array[int](my_dictionary.keys())

It's not implemented yet though. Use assign() as mentioned in the above issue.

@vonagam
Copy link
Contributor

vonagam commented Feb 2, 2023

It is possible to add support for as Array[T], but unlike Array[T](...) call where you always will get a separate new converted array, with cast you may end up with the same array (if T was the type of the array already) or different one and this can lead to some confusion or strange behavior in user code where a user expects to always get a new one.

@dalexeev
Copy link
Member

dalexeev commented Feb 3, 2023

Note that:

  1. as should only be used with objects. You cannot use as with Variant types. This works, but an error occurs if the conversion fails. This is not a safe replacement for a type constructor.
  2. With incompatible types (label as Sprite2D, node as Label), a as B silently returns null. The error appears only if it is known in advance that the given cast does not make sense.
  3. With compatible types (label as Node), as does not convert the value to another type, but only allows it to be statically interpreted as a value of a more general class.

ShadowApex added a commit to ShadowBlip/OpenGamepadUI that referenced this issue Feb 3, 2023
@vonagam
Copy link
Contributor

vonagam commented Feb 4, 2023

Correction, value as T is almost a shortcut for temp: T = value, so it makes sense to use it for non-object types too:

print( typeof( 1 as float ) == TYPE_FLOAT ) # true
print( typeof( 'a' as StringName ) == TYPE_STRING_NAME ) # true
print( typeof( [ 'a' ] as PackedStringArray ) == TYPE_PACKED_STRING_ARRAY ) # true

@Maran23
Copy link
Contributor

Maran23 commented Jun 14, 2023

I have the same issue quite often and it is always caused by calling keys or values on a dictionary. I never had this problem outside of dictionaries.
So IMO we should rather implement typed dictionaries: godotengine/godot-proposals#56, which will probably fix 99% of the need to cast an array.

@rcorre
Copy link
Contributor

rcorre commented Jan 19, 2024

I intuitively expected as to work, and this was very surprising:

var arr := [1,2,3]
var typed = arr as Array[int]
assert(typed.is_typed())

It's more surprising that typed is not null (as it would be for any other invalid conversion), it's simply the same untyped array. Even typed as Array[String] returns a regular Array with the elements 1,2,3.

Ideally as perform a conversion, as it seems intuitive. If that's not possible, it should print an error and return null as any other invalid cast does.

rcorre added a commit to rcorre/godobuf that referenced this issue Jan 22, 2024
Fixes oniksan#38.

Given:

```
message Foo {
    repeated int32 i = 1;
    repeated string s = 2;
    repeated Bar b = 3;
}
```

Previously godobuf would generate:

```
get_i() -> Array
get_s() -> Array
get_b() -> Array
```

Now it generates:

```
get_i() -> Array[int]
get_s() -> Array[string]
get_b() -> Array[Bar]
```

To do this, we must assign a typed array when constructing the PBField.
Godot does not currently have a typed array constructor: godotengine/godot#72627 (comment)
To work around this, we create a local typed variable, like so:

```
class Test1:
    func _init():
        var __rf_double_default: Array[float] = []
        __rf_double = PBField.new("rf_double", PB_DATA_TYPE.DOUBLE, PB_RULE.REPEATED, 23, true, __rf_double_default)
...
    func get_rf_double() -> Array[float]:
        return __rf_double.value
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants