HaxeFoundation / haxe-evolution

Repository for maintaining proposal for changes to the Haxe programming language
111 stars 58 forks source link

Void as unit type #76

Closed nadako closed 2 years ago

nadako commented 4 years ago

Promote Void to a real unit type, so this is possible:

var signal = new Signal<Void>();
signal.trigger(Void);

Rendered version

Aurel300 commented 4 years ago

I would suggest leaving this as-is for now and start actively discourating usage of the old function types so we can eventually remove it and make Void->T an unary function.

That's fine, but this is still a big breaking change. I don't think it is that rare to see Void->Whatever as class fields or arguments to HOF for example. For backwards compatibility, I would suggest allowing to call a function that is f:Void->Whatever as f() – without the argument.

I also don't particularly like that Void is an expression of Void type.

RealyUniqueName commented 4 years ago

I agree with Aurel, we should keep backward compatibility here.

  • Variables of type Void are not allowed
  • Cannot use Void as value

These restrictions make sense, so we could keep them, while only allowing to pass Void as an argument. Alternatively we could lift these restrictions.

I think we'll have to lift those restrictions, because that could happen because of inlining.

nadako commented 4 years ago

I also don't particularly like that Void is an expression of Void type.

I don't see a better alternative, feel free to propose one :)

nadako commented 4 years ago

Regarding backward compatibility, I think it's fine to keep things as they are for the time being, because, as mentioned, I don't think Void->T is going to be used as an unary function much. If someone really wants that, they could use (Void)->T. This triggers my OCD a bit, but I think we could live with this small quirk and figure out transition path later.

markknol commented 4 years ago

As user, I would prefer that if Void is used as parameter, you could just do:

class Signal<T> {
    function trigger(payload:T);
}

var signal = new Signal<Void>();
signal.trigger();

Maybe in such cases, it should internally convert payload:T to an optional parameter ?payload:T.

nadako commented 4 years ago

I'm not a fan of this, because it makes it hard to reason about function arity and I would prefer passing Void explicitly.

BTW this is what TypeScript does with the void arguments, but I'm still not convinced it's a good idea for the reasons stated above.

We can do this later though, if we want (maybe for that backward compat thing).

RealyUniqueName commented 4 years ago

We have decided to keep this proposal open for now in our haxe-evolution meeting yesterday. While everyone agree we need this feature, there are still open questions regarding skipping Void arguments. Currently the plan is to allow Void as a runtime value and then think about arguments situation.

Simn commented 2 years ago

We have rejected the proposal in the haxe-evolution meeting today.

While we agree that a unit type is needed, there are concerns about mixing this with Void. The difference between "absence of a type" and "presence of the Void type" could lead to some subtle problems on various targets, which we would rather avoid. @RealyUniqueName agreed to look into making a separate proposal for a unit type.

Uzume commented 2 years ago

This was rejected in lieu of #95.