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 achieve type safety in GDScript due to lack of basic language features #8137

Closed
Johnrobmiller opened this issue Oct 15, 2023 · 9 comments
Labels

Comments

@Johnrobmiller
Copy link

Johnrobmiller commented Oct 15, 2023

Describe the project you are working on

This is not a duplicate of #8135 as that one is talking about unions only, while this post is talking more broadly about type safety. Please do not close this issue as a duplicate.

Unions, intersections, declaring explicit types, interfaces, strongly typed returns on every method, and more -- all of these GDScript does not have. I would not call it a dynamically typed language at the moment even if it is one technically speaking. And until these features are implemented, it is currently impossible to have type safety using GDScript.

This is a very serious problem, and I really hope the devs are reading this and taking this seriously. This is honestly very bad, and I think that implementing basic and essential features like this should be high priority.

Describe the problem or limitation you are having in your project

Cannot achieve type safety using Godot

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Godot needs at least the minimum set of features needed to write typesafe code.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Typescript is a great example of how this should work: https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html

If this enhancement will not be used often, can it be worked around with a few lines of script?

There is no workaround for not having basic features like this.

Is there a reason why this should be core and not an add-on in the asset library?

People are not going to write typesafe code without a basic set of features that enable them to do so, and this is so essential and importatn that it would make no sense for it to simply be an add-on.

@gamedev-pnc
Copy link

Generally agree, but Godot already has type inference:

  1. https://godotengine.org/article/gdscript-progress-report-type-checking-back/#inferred-by-default
  2. https://ask.godotengine.org/85433/difference-between-equals-and-colon-equals

@theraot
Copy link

theraot commented Oct 16, 2023

The following is my view on the road ahead for better statically typed GDScript.


Statically typed

Before you look into type safety, GDScript is not even fully statically typed, and by that I mean that there are many situations where we get Variant.

The main offender for me is Dictionary.

Another offender are Callables because the function signature is not part of their type.

And then there is Godot API:

  • There are also some methods that return Variant because they would return a value type or null, for which we need some Option type (which, yes, I would rather have as a union type, but option is sufficient).
  • There are a few methods that return Variant heavens knows why.
  • And there are APIs that return a Dictionary with an specific shape (with a given set of keys, each having values of different types). For these we would need what Juan Linietsky call "structs".

I believe that with these there would be no excuse to fall back to dynamically typed GDScript.


Type safe

But is that type safe? Well, there would still be situations of unsafe casting, and situations where duck typing makes sense. I believe to address those we also need:

  • To match by type, if not a more elaborate kind of pattern matching. Intersection types could be useful here.
  • Some kind of code contracts. It seems that GDScript is likely to get traits, but interfaces or other code contracts would work too.

Generics

Ah, but there would be cases were we would be repeating code but with different types. To fix those we need to be able to declare generic methods and classes. And finally we get to generic constraints. Intersection types could be useful here too.


Inference and type declarations

As pointed out above GDScript has type inference. So you can declare variables untyped (Variant), explicitly typed (Note: starting with Godot 4.2 we can explicitly type as Variant), or implicitly typed (inferred from the initialization).

I wonder if you were thinking of inferring generic types... Which, yes, would be useful. Yet it is not strictly necessary, it more of syntactic sugar.

Although we can declare types (those would be classes), we cannot declare every kind of type.


Erasure?

By the way, since GDScript allows to mix fully typed and untyped code, and we want the guarantees of typed code to hold even when the values are passed to untyped code, GDScript probably won't do type erasure. Because of that, I don't think TypeScript is a good model (as there most of the type information is lost when compiling to JavaScript), instead I believe the path for GDScript is closer to that of PHP.

@Johnrobmiller
Copy link
Author

Johnrobmiller commented Oct 16, 2023

Generally agree, but Godot already has type inference:

  1. https://godotengine.org/article/gdscript-progress-report-type-checking-back/#inferred-by-default
  2. https://ask.godotengine.org/85433/difference-between-equals-and-colon-equals

I suppose you're right in hindsight. However, there are individual API methods whose return type is not inferred, but this might be a separate issue unrelated to your post.

Regardless, I edited the post to reflect this.

@Johnrobmiller
Copy link
Author

Johnrobmiller commented Oct 16, 2023

The following is my view on the road ahead for better statically typed GDScript.

Statically typed

Before you look into type safety, GDScript is not even fully statically typed, and by that I mean that there are many situations where we get Variant.

The main offender for me is Dictionary.

Another offender are Callables because the function signature is not part of their type.

And then there is Godot API:

  • There are also some methods that return Variant because they would return a value type or null, for which we need some Option type (which, yes, I would rather have as a union type, but option is sufficient).
  • There are a few methods that return Variant heavens knows why.
  • And there are APIs that return a Dictionary with an specific shape (with a given set of keys, each having values of different types). For these we would need what Juan Linietsky call "structs".

I believe that with these there would be no excuse to fall back to dynamically typed GDScript.

Type safe

But is that type safe? Well, there would still be situations of unsafe casting, and situations where duck typing makes sense. I believe to address those we also need:

  • To match by type, if not a more elaborate kind of pattern matching. Intersection types could be useful here.
  • Some kind of code contracts. It seems that GDScript is likely to get traits, but interfaces or other code contracts would work too.

Generics

Ah, but there would be cases were we would be repeating code but with different types. To fix those we need to be able to declare generic methods and classes. And finally we get to generic constraints. Intersection types could be useful here too.

Inference and type declarations

As pointed out above GDScript has type inference. So you can declare variables untyped (Variant), explicitly typed (Note: starting with Godot 4.2 we can explicitly type as Variant), or implicitly typed (inferred from the initialization).

I wonder if you were thinking of inferring generic types... Which, yes, would be useful. Yet it is not strictly necessary, it more of syntactic sugar.

Although we can declare types (those would be classes), we cannot declare every kind of type.

Erasure?

By the way, since GDScript allows to mix fully typed and untyped code, and we want the guarantees of typed code to hold even when the values are passed to untyped code, GDScript probably won't do type erasure. Because of that, I don't think TypeScript is a good model (as there most of the type information is lost when compiling to JavaScript), instead I believe the path for GDScript is closer to that of PHP.

Brilliant 👍

Please don't hate me for saying this (I know that many of you will), but after taking my dogs to the dog park and thinking it over, I think I'm going to switch back to Unity. As much as I love the simplicity and open-source wonderfulness of Godot, the cost of not being able to code with type safety (as well as other issues unmentioned here) is too great.

@QbieShay
Copy link

Nobody will hate you! People should use whatever technology is best for them. If it's Godot we're happy of course, but if not, it's much better for everyone to use something you're happy with than something that frustrates you constantly.

@YuriSizov
Copy link
Contributor

Closing per author's above comment. Keep in mind that you can use C# in Godot, as one of the two main offered scripting languages.

@gamedev-pnc
Copy link

Why is it closed? Mentioned problems still remain.

@YuriSizov
Copy link
Contributor

YuriSizov commented Oct 16, 2023

@good-gamedev The author is not interested in the project anymore, and the proposal is not actionable. If you want to discuss the general issue of type safety, you can open a discussion. A proposal needs to offer a specific solution, and just stating a problem and pointing at others who have resolved it is not enough to do much about it. Since the author has moved on, I don't think they'll be around to champion the cause or come up with a plan to fix the issues.

If you have an idea for a qualified proposal, please open one. This is a technical issue, so try to be as specific as you can about the design and/or implementation.

@gamedev-pnc
Copy link

@YuriSizov, ok, understand. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants