Pitch: Allow functions with void-params to be called as void-functions

To be clear, what’s discussed here for functions wouldn’t roll back the distinction between .success(()) and .success(), because this has to do with enum cases, and that distinction specifically was introduced in a separate Swift Evolution proposal. Additionally, it wouldn’t take you from .success(()) to .success.

Sure, I realize that. It was just an example of how cumbersome these () as arguments are.

I don't think you'll find any disagreement on that: quite sure that no one likes writing nested parens like (()).

My overarching point is that Swift was released with some very clever ideas about this that were generalized consistently to cover all of these use cases and (at least, IMO) really nice—and then we spent numerous Swift Evolution proposals (5, I think?, not counting amendments) spanning more than one release to rip it all out, with significant implementation headaches, "temporary" rules (like bringing back implicit tuple splatting for closures) to paper over the transition that still remain in the language today, and parts of these proposals only partly done (like the revised rules for enum cases with associated types).

We're going to have to be very careful poking at this.

1 Like

Sure, I remember the implicit tuple splatting from Swift's early years. And, like you, I quite liked it. However, I am not familiar with the compiler implementation details of how this worked, nor how the still present remains of it works to this day.

Are you saying that implicit tuple splatting for closures, implicit void-returns, and its like are hacked-on one-offs, and that adding more of those, is likely going to get rejected? I can certainly understand if that's the case, but I also do feel that () is different from most other tuples. In fact, I feel like the fact that () even is a tuple, is an implementation detail, rather than some intrinsic property of the void or unit type.

But I digress.

Implicit tuple splatting, yes—it was a one-off measure to make the transition tolerable. I'd imagine more of that is going to be frowned upon; on the other hand, an addition to the language that can be shown to result in a more consistent set of rules, rather than adding more exceptions, would likely be welcomed.

Well consistency on use-site, doesn't necessarily mean consistency in implementation. Especially if there is a discrepancy between how compiler-internal structures are modeled, the formal linguistic syntax rules, and programmer's mental models.

Personally, I think this is already insistent:

// some implicit void-returning function "bar"
func bar() { ... }

func foo() -> Void {
  // can be used as the return value from an explicit 
  // void-returning function "foo"
  return bar()
}

// but cannot be used as argument to the same implicit 
// void-consuming function
foo(bar())

Maybe foo isn't void-consuming at all, since we have a way to spell func foo(_: Void) with an explicit void argument. But then, as closures go, it is.

But that aside. Personally, I'm just really tired of having to type (()) all over in generic functions.

This was also proposed in 2018 and rather extensively discussed: