godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Infer implicit void return type in GDScript for functions without return values #8369

Open sandygk opened 10 months ago

sandygk commented 10 months ago

Describe the project you are working on

This applies for any project that enables the Untyped Declaration warning to keep the code strongly typed.

Describe the problem or limitation you are having in your project

When the Untyped Declaration warning is enabled in GDScript, every function without an explicit return type triggers a warning. This leads to verbosity in scripts where many functions are intended to return nothing. It requires a lot of unnecessary typing of -> void which takes time and clutters code.

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

Modify GDScript to infer a void return type for functions that do not explicitly declare a return type and do not return a value. This become more relevant specifically when the Untyped Declaration warning is active. This will prevent unnecessary warnings and reduce the need for redundant type declarations.

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

With the feature implemented, when Untyped Declaration warnings are enabled, functions like the following would not trigger a warning, as void would be the default inferred return type:

func perform_action():  # Automatically inferred as `void` with no warning
    # Action code here

The compiler would understand that no return implies a void return type without the developer having to explicitly state it.

This is similar to how TypeScript works, which has proven to be very effective.

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

Currently, developers can either disable the warning or manually annotate each function with void, which is suboptimal for code cleanliness and readability. This change would allow developers to keep the warnings enabled for better practice, without the verbosity.

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

This enhancement pertains to the core language functionality of GDScript, influencing how the language handles function return types at a fundamental level. An add-on would not be suitable for this type of language feature as it requires modification of the language's parser and compiler to support implicit type inference.

dalexeev commented 10 months ago

UNTYPED_DECLARATION does have the semantics of "warn only if there is no static type at all", this warning is not triggered for an inferred static type or an explicitly specified Variant. For more verbose code, we have an additional INFERRED_DECLARATION warning.

Currently UNTYPED_DECLARATION fires for implicit void because it is not inferred in most cases (the exception is the compiler and DocGen). This proposal makes sense, but I'm not sure it's a good idea since the implicitly inferred void return has less guarantees. Perhaps many users would like UNTYPED_DECLARATION to warn about this, without having to enable INFERRED_DECLARATION.

From a technical point of view, we need a small refactoring around has_return that does not separate empty and non-empty return (we probably need an enum instead of a bool). See also godotengine/godot#79363.

So this proposal makes sense to me, it would be consistent with the compiler and DocGen, but I'm not sure if this is a good idea or not from users' point of view. Implicit inferences are rather non-obvious and less reliable. Personally, I've moved away from implicit type inference in my newer projects, even if it's more verbose.

However, GDScript is a gradually typed language, and we need to think about such scenarios. But we should focus on main use cases, and not provide excessive configurability that is difficult to maintain. That is, the main problem with this proposal is to understand whether is it a main use case or not.

sandygk commented 10 months ago

I was thinking a bit more about this, and maybe the feature request should be expanded to simply add the capability to infer the return type of functions, not just void. One of the main drawbacks of enforcing strongly typed code is the extra writing developer have to do, devs may even end up keeping the UNTYPED_DECLARATION off just to avoid the extra typing. This feature could help to alleviate that, the same way := does.

One difference is that in the case of := the user is explicit;y asking for the inference, in the case of a function a user may just forget to type it, we may want to do something like that instead, for instance:

func f() ->:
  pass

I created a proposal for that which is basically a superset of this one.

The capacity for the compiler to infer types as much as possible is usually a welcome feature to every language I've seen, including TypeScreen and C# to name some examples. Genuinely curious why it may not be the case for GDScript

If the user doesn't want inference altogether, then they can use the INFERRED_DECLARATION warning that is already implemented.

Toxe commented 10 months ago

I don't mind the -> void behind normal functions because it is doing exactly what it is supposed to. The only place I wish this would not trigger a warning is with void lambda functions like:

button.pressed.connect(func() -> void: do_something())

In this case I wish we could simply write it as:

button.pressed.connect(func(): do_something())

Or maybe introduce some kind of arrow function syntax like other languages have (that could optionally infer the return type)?

# one possible syntax
button.pressed.connect(() => do_something())
button.pressed.connect((a: int, b: int) => return sum(a, b))

# or something like this
button.pressed.connect(func() => do_something())
button.pressed.connect(func(a: int, b: int) => return sum(a, b))