Godot-proposals: Add static type hints for array members

Created on 30 Oct 2019  路  16Comments  路  Source: godotengine/godot-proposals

Describe the project you are working on:
I am working on a Pokemon inspired RPG where the player would be a "manager" and would have battle moves and stats based on the objects they own

Describe the problem or limitation you are having in your project:
I guess it isn't a "problem" but I thought of something while implementing the party system.
While implementing the party system, I've made an array that would contain multiple instances of a specific class I made (BattleCharacter), however, while I always use static typing, it seems to be impossible to determine in advance the type all array members would have.

Which I am used to coming from a C# background, I also feel like it would allow a lot of optimizations in case of iterations through array members

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:
My proposal would be to allow something like
var array_name : type = []
or
var array_name = [] : type
it would then only allow to set values of the array to values of the specified type

Describe implementation detail for your proposal (in code), if possible:
As I only started using Godot recently, I unfortunately don't know enough the way the engine handles internally GDScript.

If this enhancement will not be used often, can it be worked around with a few lines of script?:
Well, yeah since it can be done without static typing, it's mostly a feature improving on the static typing added to 3.0

Is there a reason why this should be core and not an add-on in the asset library?:
It would allow big performance optimizations in games relying heavily on arrays and iterations.

gdscript

Most helpful comment

And for Dictionary members.

All 16 comments

And for Dictionary members.

It would allow big performance optimizations in games relying heavily on arrays and iterations.

This will require GDScript to support typed instructions first. Otherwise, the typing will just be used to improve autocompletion, type safety and documentation.

I see.
Yeah, I knew typed variables didn't have effects on performances yet because typed instructions haven't been implemented, but in the long run it could allow performance improvements when it would be added

It would also still help for what you said at the end of your message which is a good advantage as well

Other syntax ideas?

var char_list: [BattleCharacter] = []
var char_set: { BattleCharacter: null } = {}
var char_dict: {int: BattleCharacter} = {}

I've always been a fan of how Ruby YARD documentation handles Arrays and Dictionaries (called "Hashes" in Ruby, but I'll be calling them Dictionaries for simplicity). Perhaps we could use that syntax?

For reference, Arrays are usually handled like Array<SomeOtherClass> in YARD docs. If you need to go deeper with Arrays, you might do something like Array<Array<SomeOtherClass>>. And if you wanted to document that a array could have multiple objects, you might do Array<SomeClass, SomeSecondClass, SomeThirdClass>.

As for Dictionaries, YARD documentation would usually look something like Dictionary<String => SomeClass>, although I'll admit that the => is a ruby thing -- perhaps we can use -> here?

And the two can be put within each other: Dictionary<String => Array<BattleCharacter>>. In GDScript, this would probably end up typed out as var units_by_team_name : Dictionary<String -> Array<BattleCharacter>>.

I don't know how hard it would be to implement this sort of syntax, but that's my suggestion for handling static typing for arrays and dictionaries.

This will require GDScript to support typed instructions first. Otherwise, the typing will just be used to improve autocompletion, type safety and documentation.

Once godotengine/godot/pull/43004 gets merged hopefully work on this can be started.

Once godotengine/godot/pull/43004 gets merged hopefully work on this can be started.

I definitely want to make this for Godot 4.0. It still will take sometime since I have other tasks.

I've been thinking about this just recently and then stumbled upon this issue.

First I was thinking like C++ syntax for this, but var int_arr : Array<int> = [0, 1, 2, 3, 4, 5] wouldn't really suit GDScript. Especially because of the < > syntax that would only appear here.

I really like @willnationsdev 's idea, and I think that would be the best, and it still looks like GDScript.

Go has var arr: []int for slices, Typescript has let arr: int[] for arrays. Both would look quite natural in GDscript IMHO.

@dgellow Yeah, I often like that syntax actually (C-like too). But how would you do Dictionaries then?

For dictionaries, two options that build on my previous comment, and don't require additional characters (so shouldn't complicate the parsing rules too much, hopefully):

  • var dict: string[int], keys of type string, values of type int
  • var dict: [string]int, here too, keys of type string, values of type int

I find the second one a bit more clear, but I'm using Go quite a lot so that could be a bias.

I don't want to open a pandoras box, but have you looked more into typescript? specially the way they handle:

  • array typing
let a: number[]; // [1, 2, 3]
let b: string[]; // ["a", "b", "c"]
  • using tuples and array tuples
let t: [string, number, boolean][]; // [["a", 1, true],["b", 2, false]]
  • multiple distinct types for one variable (union type)
let foo: number | string | null;
  • as well as distinct values for one variable
let bar: "up" | "left" | "right";
  • or use enums and interfaces for distinct values
const enum Directions {
  up = "KeyW",
  left = "KeyA",
  right = "KeyD"
}
let bar2: keyof Directions; // same as : "up" | "left" | "right";
  • define key and value types for dictionaries:
let bar3: { [key: string]: number }; // { "x": 4 }
  • re-using a type from a given varibale
let foo = { bar: 42 }
let bar: typeof foo;

again - I know, this is already drifting far from array typing, and I am not saying Godot should take over all those syntax options - but I just wanted to list some of them, as I don't see them covered so far.

@dgellow

var dict: string[int], keys of type string, values of type int

I also find this very pleasing to the eye. Although, I'm likely biased due to PHP like you are of the latter version for Go.

Either way, you think of the braces as wrapping the key ("what type is the key that goes in the square brackets?") or the value ("what type am I indexing to get?"), but both approaches work well imo. Between the two, I prefer the former because I like starting to type with actual type information rather than syntax characters. Makes it easier for me to just go with my train of thought. Need "X" which maps to "Y" vs. Need a "Map" of "X" to "Y". Slightly less cognitive load.

string[int] # starts with `s` from `string`. Yay, type info!
[string]int # starts with `[`, for syntax. Boo, I have to remember to know immediately to put that

@h4de5

let t: [string, number, boolean][]; // [["a", 1, true],["b", 2, false]]

let foo: number | string | null;

let bar: "up" | "left" | "right";

Supporting any of these would mean adding support for tuples and unions in the core Variant type which would likely be a lot more work. If you think adding these types provide a significant enough advantage to warrant integrating and maintaining them in the core, then you should open proposals for them.

As it stands, I think the struct proposal already kind of does this for tuples (godotengine/godot-proposals#279), but there isn't anything yet for unions afaik.

let bar3: { [key: string]: number }; // { "x": 4 }

Besides the "starting with syntax characters" thing I mentioned before, I especially don't like the idea of needing to use key, in the type definition (regardless of whether it's arbitrary or a keyword). I don't think I should have to express a full key-value pair syntax just to indicate what the correct type information should be.

  • re-using a type from a given varibale

    let foo = { bar: 42 }
    let bar: typeof foo;

Really not sure about this one. Sounds more GDScript-like to formally declare the existence of a type alias (if support for that were added) and then allowing you to use that in type hints. There's already typeof() in GDScript, but it returns an enum value. And in order to fully understand the type of something, you'd need at least both the typeof() result and the get_class() result (or the script class name).


I'm good with structs eventually being supported, cause tuples are convenient and useful, but as for everything else, I'd just keep to the int[], string[int], etc. Although, type hinting tuples would be another thing altogether which can be discussed in the mentioned Issue if things ever progress that far. No need to waste time on it here.

* `var dict: [string]int`, here too, keys of type `string`, values of type `int`

To me, this is the only right way because you index dicts and arrays with [], so by intuition key type is expected to stand between them followed by the value type.

I think Python's dict[string, int] would work well in GDScript.

so wait you guys would perfer..

class MyDict[key, value]:
var dict := MyDict[key, value]()

over?

class MyDict<key, value>:
var dict := MyDict<key, value>()

how would something like constraints work if they were added?

EDIT: TBH the first one looks better in python
EDIT2: so here are my thoughts on this..

I think that we shouldn't do it like so..
let bar3: { [key: string]: number }; // { "x": 4 }
its confusing

I personally think something like this should be done...

var array :  Array[int]    limits it
var array := Array[int]() assigns it
var dict :  Dictionary[String, MyObject]   limits it
var dict := Dictionary[String, MyObject]() assigns it
Was this page helpful?
0 / 5 - 0 ratings