winglang/wing

Signature of closure - return type should be mandatory (even if it is `void`)

eladb opened this issue ยท 12 comments

eladb commented

I tried this

Declare a variable for a closure that doesn't return a value (void).

I expected this:

To look like this:

let my_closure: inflight (): void;

Instead, this happened

Apparently this is the syntax:

let my_closure: inflight ();

Is there a workaround?

N/A

Component

Language Design

Wing Version

No response

Wing Console Version

No response

Node.js Version

No response

Platform(s)

No response

Anything else?

No response

Community Notes

  • Please vote by adding a ๐Ÿ‘ reaction to the issue to help us prioritize.
  • If you are interested to work on this issue, please leave a comment.

@yoav-steinberg - this means we will also have to add void #432 to the language

Hey, what's the reasoning behind this? I think that last language to adopt this approach was C++...

I think that last language to adopt this approach was C++

Typescript works like this

// not valid
let my_closure: ();

// valid
let my_closure: () => void;
eladb commented

The reasoning is ergonomic/aesthetic in my mind. This () doesn't feel like it's a type that represents a function signature in my mind.

We have decided to move along with Elad's suggested approach and expose void as return type for closures not returning anything. This should also handle #2378

Lets see how it feels to make signatures and closures require void while methods definitions keeping it optional:

let var_of_sig_type: (x: num): void; // Function type annotation requires void
let my_func = (callback: (x:num): void): void => { ... }; // callback argument type annotation requires void, closure requires void
let my_func2 = (x: num): void => { ... }; // again, closure definition requires void
class C {
  my_method(x: num) { ... } // No need for void here
  my_method2(x: num): void { ... } // But also works when return type explicitly annotated as void
}
interface IPointOfView {
  computeTheMeaningOfLifeTheUniverseAndEverything(x: num); // Here too void can be implicit
  computeTheMeaningOfLifeTheUniverseAndEverything2(x: num): void; // .. Or explicit
}
eladb commented

@yoav-steinberg why can't we make void optional in closure definitions?

Callback argument type annotation requires void (because it's a declaration), closure DOES NOT requires void (because it's a definition):

let my_func = (callback: (x:num): void) => { ... }; 

Closure definitions DOES NOT require void:

let my_func2 = (x: num) => { ... };

What do you think?

@yoav-steinberg why can't we make void optional in closure definitions?

Sure, lets do that!

eladb commented

BTW, I think the interface declarations SHOULD HAVE void (because they are declarations):

interface IPointOfView {
  computeTheMeaningOfLifeTheUniverseAndEverything(x: num): void;
  // ...
}

Revised reference given above comments:

let var_of_sig_type: (x: num): void; // Function type annotation requires void
let my_func = (callback: (x:num): void) => { ... }; // callback argument type annotation requires void, closure definition doesn't require void
let my_func2 = (x: num) => { ... }; // again, closure definition doesn't require void
let my_func3 = (x: num): void => { ... }; // but can have it
class C {
  my_method(x: num) { ... } // No need for void here
  my_method2(x: num): void { ... } // But also works when return type explicitly annotated as void
}
interface IPointOfView {
  computeTheMeaningOfLifeTheUniverseAndEverything(x: num): void; // In interfaces we require void, since it's a declaration (type annotation)
}
eladb commented

Ack

Congrats! ๐Ÿš€ This was released in Wing 0.18.1.