[swift-evolution] [Proposal] Change Void meaning

Xiaodi Wu xiaodi.wu at gmail.com
Tue Jun 13 11:17:36 CDT 2017


On Tue, Jun 13, 2017 at 04:06 Florent Bruneau <florent.bruneau at intersec.com>
wrote:

>
> > Le 13 juin 2017 à 10:41, Xiaodi Wu via swift-evolution <
> swift-evolution at swift.org> a écrit :
> >
> >> On Tue, Jun 13, 2017 at 3:06 AM, John McCall <rjmccall at apple.com>
> wrote:
> >>> On Jun 13, 2017, at 3:30 AM, Jérémie Girault <
> jeremie.girault at gmail.com> wrote:
> >>>
> >>> Exactly,
> >>> The reflexion behind it is:
> >>>
> >>> - Let's understand that 0110 and other tuple SE are important for the
> compiler, we do not want them to rollback
> >>> - However we have number of regressions for generics / functional
> programmers
> >>> - Let’s solve this step by step like a typical problem
> >>>
> >>> - Step 0 is adressing this Void tuple of size zero :
> >>>     - Zero is in many problems of CS an edge case, so let’s handle
> this case first
> >>>     - The compiler knows what Void is, and its only value (or
> non-value)
> >>>     - It was handled historically by the compiler because of implicit
> side effects
> >>>     - Let’s handle it explicitely with rules in current context
> >>>     - one effect of the proposal is source compatibility
> >>>     - but the goal is to build atop and strengthen 0110, 0066 and
> other tuple-related SE
> >>>
> >>
> >> There are four difficulties I see with this proposal.
> >>
> >> The first is that it is a first step that quite clearly does not lead
> to anything.  It resolves a difficulty with exactly one case of function
> composition, but we would need completely different solutions to handle any
> of the other compositional regressions of SE-0110.
> >>
> >> The second is that it's a huge source of complexity for the type
> system.  The type checker would not be able to do even rudimentary type
> matching, e.g. when checking a call, without having first resolved all of
> the argument and parameter types to prove that they are not Void.  This
> would probably render it impossible to type-check many programs without
> some ad-hoc rule of inferring that certain types are not Void.  It would
> certainly make type-checking vastly more expensive.
> >>
> >> The third is that it is not possible to prevent values of Void from
> existing, because (unlike Never, which cannot be constructed) they are
> always created by returning from a Void-returning function, and a generic
> function can do anything it likes with that value — turn it into an Any,
> store it in an Array, whatever.  The proposal seems to only consider using
> the value as a parameter.
> >>
> > Hang on, though. If Jérémie is interested only in addressing the issue
> of Void as a parameter and his idea can be adequately carried out by
> inferring a default value of Void for every parameter of type Void, this
> should be a fairly self-contained change, should it not? And would the
> impact on the cost of type checking really be vastly greater in that case?
> >
> > This idea is now rather intriguing to me because it extends beyond just
> addressing one symptom of SE-0110. Swift allows us to omit the spelling out
> of return types that are Void, it allows warning-free discarding of return
> values that are Void, etc. This could add a nice consistency and
> rationalize some of the weirdness of passing a value that is stipulated by
> the parameter type.
> >
> >> Finally, it would allow a lot of inadvertent errors with the use of
> generic functions, because any argument of unconstrained type could be
> accidentally specialized with Void.  For example, if you forgot to pass an
> argument to this function, it would simply infer T=Void:
> >>   func append<T>(value: T)
> >> It seems more likely that this would lead to unexpected, frustrating
> bugs than that this would actually be desired by the programmer.  You
> really just want this to kick in in more generic situations.
> >>
> > Hmm, at first glance, that seemed like it could be bad. But if, say, a
> particular collection can store an element of type Void, is it so
> undesirable to allow `append()` to append Void?
>
> Seems to me the language should go for safety before convenience here. In
> John's example you are dealing with a generic function, not a generic type
> and having append() being silently resolve to append<Void>(value: Void)
> could clearly cause bug with the wrong append() function being called in
> some cases (because you may mean `append()` from a parent scope instead of
> `append(value: Void)` from the current scope)


Somewhat astonishingly, Swift actually prefers the “right” overload, at
least in the case of subclassing, and I can’t really explain it:

```

class C {

    func f() {

        print("C")

    }

}


class D : C {

    func f(_: Void = ()) {

        print("D")

    }

}


let d = D()

d.f() // Prints “C”.
```

In the case of a collection, or any generic type, you can simply provide an
> `extension Collection where Element == Void { }` that overloads you
> append() function with a no-param version.
>
> >>
> >> —
> >> very short reply expected - vsre.info
> >> Jérémie Girault
> >>
> >> On 13 juin 2017 at 00:44:52, Xiaodi Wu (xiaodi.wu at gmail.com) wrote:
> >>
> >>> On Mon, Jun 12, 2017 at 5:38 PM, Xiaodi Wu <xiaodi.wu at gmail.com>
> wrote:
> >>> On Mon, Jun 12, 2017 at 5:25 PM, Jérémie Girault <
> jeremie.girault at gmail.com> wrote:
> >>>
> >>>
> >>> —
> >>> very short reply expected - vsre.info
> >>> Jérémie Girault
> >>>
> >>> On 12 juin 2017 at 23:56:37, Xiaodi Wu (xiaodi.wu at gmail.com) wrote:
> >>>
> >>>> On Mon, Jun 12, 2017 at 4:47 PM, Jérémie Girault <
> jeremie.girault at gmail.com> wrote:
> >>>> - Void as arguments is pretty common when using generics, that’s a
> core point of this proposal. An maybe that’s why we misunderstood ourselves
> (around 0110 / 0066). This proposal addresses arguments.
> >>>> - maybe it should be revised around this ? Simple example :
> >>>>
> >>>> `typealias Callback<T> = (T) -> Void` -> `Callback<Void>` will give
> `(Void) => Void`.
> >>>>
> >>>> It was acceptable before swift4 but no more. However nobody cares
> about this `Void` argument and actually we know it’s value. So why let the
> developer type it ?
> >>>>
> >>>> Ah, I see. The purpose of SE-0029...SE-0110 was to make it possible
> to distinguish an argument list `(Void)` from an argument list `()`. This
> does cause some verbosity where previously users relied on implicit tuple
> splatting. Ideally, we would bring back some syntactic sugar to make this
> more ergonomic. But, whether or not the spelling is made more
> user-friendly, the point here is that _everybody_ should care about this
> `Void` argument.
> >>> It is still be typechecked and appropriate errors should be reported
> to the user so _nobody_ will ignore it.
> >>>
> >>> But with the proposal the code will be striped out of Void arguments
> at compile-time. I think it's a win for the developer on a lot of grounds.
> The fact that this proposal integrates with the type-system is also
> important.
> >>>
> >>> If you are not comfortable about Void being stripped, we can also
> discuss alternatives: someone was suggesting me that it would be possible
> to replace :
> >>>
> >>> ```
> >>>
> >>> func foo<T, U, V>(t: T, u: U) -> V {
> >>>
> >>>   // do something with t and u
> >>>
> >>>   // return some V
> >>>
> >>> }
> >>>
> >>> ```
> >>>
> >>> with
> >>>
> >>> ```
> >>>
> >>> func foo<Void, Int, String>(u: Int) -> String { let t = ()
> >>>
> >>>   // do something with t and u
> >>>
> >>>   // return some V
> >>>
> >>> }
> >>>
> >>> ```
> >>>
> >>> or
> >>>
> >>> ```
> >>>
> >>> func foo<Void, Int, String>(t: Void = (), u: Int) -> String {
> >>>
> >>>   // do something with t and u
> >>>
> >>>   // return some V
> >>>
> >>> }
> >>>
> >>> ```
> >>>
> >>> I don’t know what you would consider more effective or elegant (at an
> implementation level) but it’s the same result for the developper.
> >>>
> >>>
> >>> Ah, but I think I catch your drift with the last example. Is this a
> more general point that the compiler should treat every parameter of type
> Void as having an implied default value of Void? That would be an
> interesting idea.
> >>>
> >>> What is the goal of such changes? Is it to allow you to write `foo()`
> instead of `foo(())` for a function `foo` of type `(T) -> Void`?
> >>>
> >>> If so, then I think what you're seeking to do is reverse SE-0066 (as
> Vladimir points out), which explicits details how it's is an intentional
> change to require such a spelling. I think you're starting from the premise
> that this is unintended or undesirable, when in fact it is deliberate and
> approved.
> >>>
> >>> It is also, unless I'm mistaken, not the issue that was raised
> initially with respect to SE-0110, which had to do with the extra
> boilerplate of destructuring a tuple inside a closure, something that was
> not so obvious before implementation.
> >>>
> >>>> My point here is that `Void` should be “striped” by “reducing”
> argument list signatures.
> >>>>
> >>>> —
> >>>> very short reply expected - vsre.info
> >>>> Jérémie Girault
> >>>>
> >>>> On 12 juin 2017 at 19:15:18, John McCall (rjmccall at apple.com) wrote:
> >>>>
> >>>>>
> >>>>>> On Jun 12, 2017, at 4:48 AM, Jérémie Girault via swift-evolution <
> swift-evolution at swift.org> wrote:
> >>>>>>
> >>>>>> Hi here,
> >>>>>>
> >>>>>> As I tested swift4 in xcode9b1 I noticed a lot of regressions about
> tuples usage.
> >>>>>>
> >>>>>> After documenting myself about the changes which happened, I
> thought that they could be improved. Instead of fighting these propositions
> (which make sense), I wanted create a few proposal which would improve
> these recent changes with a few simple rules.
> >>>>>>
> >>>>>> My propositions are based on the recent decisions and in the
> continuation of SE-0110. The first one is about Void.
> >>>>>> Void is historically defined as the type of the empty tuple. The
> reason of this is that arguments were initially considered as tuple.
> >>>>>
> >>>>> The dominant consideration here was always return types, not
> parameters.  I'm not sure there was ever much point in writing Void in a
> parameter list, but whatever reasons there were surely vanished with
> SE-0066.
> >>>>>
> >>>>> Note that 'void' in C was originally exclusively a return type.
> ANSI gave it a new purpose it with void*, but the meaning is totally
> unrelated.
> >>>>>
> >>>>> John.
> >
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
> --
> Florent Bruneau
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170613/3ff21b61/attachment.html>


More information about the swift-evolution mailing list