godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.06k stars 65 forks source link

Add "alias" keyword for functions in GDscript #9768

Open Gianpy16 opened 2 weeks ago

Gianpy16 commented 2 weeks ago

Describe the project you are working on

I want share an idea to add an "alias" keyword for gdscript that allow to give a function multiple names to call it. Similar to what Array.append is just an alias of Array.push_back, it can be defined in a script inside a class by the user.

Describe the problem or limitation you are having in your project

It could be used as syntax sugar.

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

In GDscript this keyword could be added either as an actual keyword:

alias <alias_name>: <func_name>

Or as a decorator but it doesn't look good:

@alias(<alias_name>)
func <func_name> (): ...

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

Here how it could look like on a real use case:

func add () -> void: ...

alias append: add

When calling the function "append" it will instead call the function "add", the inspector may show a message that an alias has been called showing something like this in the frame stack:

0 - res://script.gd:100 - at alias: append as function: add
1 - res://main.gd:30 - at function: main

An alias would ask the same amount of parameters of the original function:

func give (item: String, amount: int) -> void: ...

alias send: give

The engine will jump from the alias to the function it refeers to. In debug mode this could be done each time (to show it in the messages), and in release aliases are removed from scripts and replaced with the original function.

It could show an error if the alias is already used like "alias name already in use" and shouldn't be used on lambdas.

The autodocs could display the alias as a function and add the message "alias of ()".

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

In current GD script you would just define a new function that calls the original one, it will uses one extra stack call. If the function has argouments you would have to copy all of them as well.

func append () -> void:
    add()

func send (item: String, amount: int) -> void:
    give(item, amount)

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

.

Calinou commented 2 weeks ago

Aliases tend to be frowned upon in APIs, they give users several ways to achieve the same thing. This leads to inconsistent across different users of the API, along with choice paralysis.

Also, I don't know of any programming language which has syntactic sugar for this (other than through preprocessor defines).

KoBeWi commented 2 weeks ago

Ruby has alias_method, which paired with monkey patching, allows for some funny shenanigans. E.g. you can modify original class' method without extending it.

class SomeExistingClass
    alias_method :some_existing_method, :new_name

    def some_existing_method
        new_name # Call original implementation.
        # extra code goes here
    end
end

Whenever something uses the patched method in this class, it will call the original method plus some extra code.

I don't see any use for it in GDScript though, as it doesn't support monkey patching. Also aliases wouldn't solve the same problem as e.g. typedef/using in C++. Your proposal explains the idea, but fails to provide any solid use-case. You want to call the method under different names, but why? The implementation complexity you outlined makes this even less viable.

Gianpy16 commented 2 weeks ago

@Calinou you're right on the use cases, this would only make sense for API or (extreme case) a project with multiple people that have different preference on the function name.

@KoBeWi This could be used by the projects in the asset library, since some of the implements API and libraries in GDScript. Adding a new method as the alias for monkey patching would be more useful, an actual alias keyword would only have a disadvantage and make it look faulty.

Thinking about it now this feature alone would be too small as an addition because of the (extreme) rare use case, I've used in some of my projects aliases but because I'm working with other people that asked me to add them.

I got the point and I haven't thought of it before, GDscript is too simple. Even if someone else would need something like this feature they are probably making something such as an API or library that may need this complexity, and it that case they would probably use C# or C++ and bind it to GDScript.

dalexeev commented 2 weeks ago

Why not just use a wrapper?

func base_func(a, b, c = 0):
    return a + b + c

func alias_func(a, b, c = 0):
    return base_func(a, b, c)

Disadvantages:

  1. You need to update the alias function signature when changing the base function signature.
  2. It is less performant because GDScript does not have an inline keyword (#3760) and the GDScript compiler does not currently optimize it.

However, this only matters if you create a lot of aliases, which is not generally considered good practice.

KoBeWi commented 2 weeks ago

Why not just use a wrapper?

In current GD script you would just define a new function that calls the original one, it will uses one extra stack call. If the function has argouments you would have to copy all of them as well.