[swift-evolution] [Proposal] Change Void meaning

Xiaodi Wu xiaodi.wu at gmail.com
Tue Jun 13 12:46:54 CDT 2017


But yes, I agree with the overall point that (while a very interesting idea
(IMO)) there are definitely a _lot_ of cases to consider before it’s
clearly viable as a solution.
On Tue, Jun 13, 2017 at 12:43 Jens Persson <jens at bitcycle.com> wrote:

> Ah, right!
>
> On Tue, Jun 13, 2017 at 7:40 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
>> Note that “inout Void” is a distinct type from “Void”; it is not possible
>> to specify a default value for an inout Void parameter even explicitly
>> (“error: cannot pass immutable value of type ()...”), so naturally it
>> cannot be done implicitly either.
>>
>> On Tue, Jun 13, 2017 at 12:29 Jens Persson <jens at bitcycle.com> wrote:
>>
>>> The std lib swap could perhaps be an interesting example to consider:
>>> public func swap<T>(_ a: inout T, _ b: inout T)
>>>
>>> What would happen with that?
>>> Will inout arguments be an exception to the rule of Void getting a
>>> default value, and if so, what would the effects of that be?
>>> Or would it somehow be allowed to call swap()?
>>> Or is there a third alternative?
>>> /Jens
>>>
>>> On Tue, Jun 13, 2017 at 7:15 PM, John McCall via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>>
>>>> On Jun 13, 2017, at 4:41 AM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>>
>>>> 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?
>>>>
>>>>
>>>> If the proposal was phrased in terms of defaults, e.g. "trailing
>>>> parameters do not require a matching argument if they have Void type", then
>>>> yes, that would be implementable because it still admits a "local"
>>>> reduction on call constraints, one which does not need to immediately
>>>> reason about the actual types of arguments.  It is not clear that this rule
>>>> allows function compositions of the sort that Jérémie is looking for,
>>>> though.
>>>>
>>>> Anyway, that is not the proposal; the proposal is that parameters — in
>>>> any position — are simply removed from the parameter sequence if they have
>>>> Void type.  In order to allow composition (i.e. f(g(x)), where g: X ->
>>>> Void), you then need a matching rule that arguments are dropped from the
>>>> argument sequence (for purposes of type-checking) if they have Void type.
>>>> Either of these rules is sufficient to turn the reduction of function-type
>>>> matches into an extremely messy combinatoric matching problem where e.g.
>>>> (τ0, Int) can be passed to a function taking (Int, τ1) if we can decide
>>>> that τ0 == τ1 == Void.
>>>>
>>>> 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?
>>>>
>>>>
>>>> append on a Collection is not an unconstrained generic; its parameter
>>>> type is determined by the type of the collection.  Perhaps this was a
>>>> poorly-chosen example.
>>>>
>>>> John.
>>>>
>>>>
>>>>
>>>>> John.
>>>>>
>>>>>
>>>>>>>>>> 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
>>>>
>>>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170613/597b8609/attachment.html>


More information about the swift-evolution mailing list