Godot: Optional typing in GDScript: Allow return "void" from void functions

Created on 31 Oct 2018  路  22Comments  路  Source: godotengine/godot

Godot version:
Godot 3.1.alpha

Issue description:
Suggestion: It would be nice to be able to return void functions from gdscript like in C

func set_state(state) -> void:
    state = new_state

func state_walk() -> void:
    if input_running:
        return set_state(PlayerState.run)

func state_run() -> void:
    if not input_running:
        return set_state(PlayerState.walk)

instead of

func set_state(state) -> void:
    state = new_state

func state_walk() -> void:
    if input_running:
        set_state(PlayerState.run)
        return

func state_run() -> void:
    if not input_running:
        set_state(PlayerState.walk)
        return

Optional typing: https://github.com/godotengine/godot/issues/10630

archived discussion gdscript

Most helpful comment

I find this confusing. What's the point of return something if you aren't returning anything? If I see such statement I assume it's a programmer's mistake who forgot the function was declared void.

All 22 comments

Could also be an explicit way to request TCO

TCO?

Tail-call optimization

I'm not sure what TCO has to do with returning void though? You can easily return something via TCO.

I mean for the case where you want TCO when the function you are calling doesn't return anything.

For implicit TCO if it's in tail call position regardless then it wouldn't matter anyway. If you want explicit TCO then you'd have a new keyword in any case.

I find this confusing. What's the point of return something if you aren't returning anything? If I see such statement I assume it's a programmer's mistake who forgot the function was declared void.

I think that they're trying to to avoid an extra line.

One reason you might need it is if you are calling a function that you don't know in advance, like if it is passed into the function.

I find this confusing. What's the point of return something if you aren't returning anything? If I see such statement I assume it's a programmer's mistake who forgot the function was declared void.

return can be used to bounce execution out of a scope early to.. for example guard an invariant, even if the function is intended to return no value

    if health < thing:
        return
    do_thing()

@ShawnMcCool return without an argument should already work in functions with a void return type. What won't work is return with an argument (even null).

@ShawnMcCool return without an argument should already work in functions with a void return type. What won't work is return with an argument (even null).

Right. I must have made a mistake before searching out this thread. Thanks.

One reason you might need it is if you are calling a function that you don't know in advance, like if it is passed into the function.

I still don't get it. 1) How you don't know the function you're calling? (even if passed as an argument, you should have an idea). 2) If you _may_ return something, then don't declare your function as void.

For me the only purpose for this is saving one line, which I find pointless. Especially since it might cover up a legitimate mistake from the programmer.

We also have to consider that if you do something like the following:

func return_something():
    return 1

func void_func() -> void:
    return return_something()

The compiler would have to add an extra check to see if the function being called return something or not, so to not allow you to actually return a value from a void function.

I was thinking of something like:

func print_and_call_with_42(f):
  print("Blah")
  return f.call_func(42)

func do_a_thing(n) -> void:
  print(n + 5)

# Usage
print_and_call_with_42(funcref(self, "do_a_thing"))

Don't know if this kind of thing is already possible. Would be even more useful to be able to store the result like

func call_timed(f):
  time = ... # Get the current time
  result = f.call_func(r)
  elapsed = ... # Get the time elapsed
  print("Time elapsed:", elapsed)
  return result

func do_a_thing(n) -> void:
  for i in range(1000000):
    pass # Something very expensive

# Usage
call_timed(funcref(self, "do_a_thing"))

Could use it for other things too, like temporarily changing some global state while a function is called.

@raymoo this is already possible and valid. The problem would be if you had declared call_timed() to be void, because inside of it you call return result, which wouldn't make sense in a void function.


To clarify, this is not an issue to me:

func void_func() -> void:
    return

func return_void_func():
    return void_func()

Even if void_func() returns nothing, it's still okay to use the result (which is always null). Though it could trigger a warning.

What I don't understand is this:

func void_func_a() -> void:
    return

func void_func_b() -> void:
    return void_func_a()

Because in this case if void_func_a() is changed to return something, then void_func_b() will also be returning something, even though it was declared as void. I would consider it a bug, that's why I don't want to allow it.

Because in this case if void_func_a() is changed to return something, then void_func_b() will also be returning something, even though it was declared as void. I would consider it a bug, that's why I don't want to allow it.

If void_func_a was changed to return non-void, then should void_func_b trying to return void fail the type check on the return void_func_a() line?

If void_func_a was changed to return non-void, then should void_func_b trying to return void fail the type check on the return void_func_a() line?

Yes, but note that such check does not exist yet, currently it simply doesn't allow anything after return if the current function is declared as void. I don't really feel the need to add this check just for saving one line break in the code.

In the future it might be useful if we wanted a feature that would allow the return type of call_timed to match the return type of the input function.

(EDIT: Statically)

In the future it might be useful if we wanted a feature that would allow the return type of call_timed to match the return type of the input function.

I don't see how this is related to the original request.

It's not, sorry. My original confusion has already been cleared up.

This feature request doesn't make any sense to me. Why would you want to pass anything into a return in a void function, and why would you want to use a void function as a value?

Most comments and reactions agree this is not needed and I haven't seen a use case for this (apart from saving an extra line break), so I'm closing this.

If anyone has a valid use case for this feature that can't be done currently (or only done with workarounds), feel free to comment and we'll reopen.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ducdetronquito picture ducdetronquito  路  3Comments

n-pigeon picture n-pigeon  路  3Comments

RebelliousX picture RebelliousX  路  3Comments

blurymind picture blurymind  路  3Comments

Spooner picture Spooner  路  3Comments