It’s worth noting that the question of “how do these defaults interact with 
other defaults” is an issue that has left this feature dead in the water in the 
Rust language despite being accepted for inclusion two years ago. See 
https://internals.rust-lang.org/t/interaction-of-user-defined-and-integral-fallbacks-with-inference/2496
 
<https://internals.rust-lang.org/t/interaction-of-user-defined-and-integral-fallbacks-with-inference/2496>
 for some discussion of the issues at hand.

For those who don’t want to click that link, or are having trouble translating 
the syntax/terms to Swift. The heart of Niko’s post is the following (note: 
functions are used here for expedience; you can imagine these are `inits` for a 
generic type if you wish):

// Example 1: user supplied default is IntegerLiteralConvertible

func foo<T=Int64>(t: T) { ... }

foo<_>(22)
//  ^
//  |
//  What type gets inferred here?



// Example 2: user supplied default isn't IntegerLiteralConvertible

func bar<T=Character>(t: T) { ... }

bar<_>(22)
//  ^
//  |
//  What type gets inferred here?


There are 4 strategies:

(Note: I use “integer literal” here for simplicity; in general it's “any kind 
of literal, and its associated LiteralType”. So this reasoning also applies to 
FloatLiteralType, StringLiteralType, BooleanLiteralType, etc.)

* Unify all: always unify the variables with all defaults. This is the 
conservative choice in that it gives an error if there is any doubt.

* Prefer literal: always prefer IntegerLiteralType (Int). This is the maximally 
backwards compatible choice, but I think it leads to very surprising outcomes.

* Prefer user: always the user-defined choice. This is simple from one point of 
view, but does lead to a potentially counterintuitive result for example 2.

* Do What I Mean (DWIM): Prefer the user-defined default, except in the case 
where the variable is unified with an integer literal and the user-defined 
default isn't IntegerLiteralConvertible. This is complex to say but leads to 
sensible results on both examples. (Basically: prefer user, but fallback to 
IntegerLiteralType if the user default doesn’t actually make sense)

| Strategy       | Example 1 | Example 2 |
| -------------- | --------- | --------- |
| Unify all      | Error     | Error     |
| Prefer literal | Int       | Int       |
| Prefer user    | Int64     | Error     |
| DWIM           | Int64     | Int       |

Personally, I’ve always favoured DWIM. Especially in Swift where 
IntegerLiteralType inference is so frequently used (you don’t want adding a 
default to cause code to stop compiling!). In practice I don’t expect there to 
be many cases where this ambiguity actually kicks in, as it requires the 
user-specified default to be a LiteralConvertible type that isn't the relevant 
LiteralType, and for the type variable to affect an actual Literal. So 
<T=String>(x: T) never causes problems, but <T=StaticString>(x: T) does.

As for the matter of “what if I want the other one” — you clearly know the 
actual type you want; just name it explicitly.




> On Jan 24, 2017, at 2:59 AM, Srđan Rašić via swift-evolution 
> <[email protected]> wrote:
> 
> > If the answer to the above question is "yes, T is inferred as Int" then we 
> > need some way to express "give me the default for T, which is Float."
> 
> I don't think that we need that. It would introduce a new level of 
> explicitness, "I want the default, but I don't care what the default is", 
> that is not really useful. If you don't care what the default type is, you 
> probably also don't care that you are defaulting. If you do care what the 
> default type is, you would explicitly sepecify it as `X<Float>`. 
> 
> 
> > If the answer to the above question is "no" then we need some way to 
> > express "don't give me the default; rather, infer type T from the right 
> > hand side."
> 
> That would be preferred behavior. Infer from the context if possible, use 
> default otherwise. 
> 
> 
> tir. 24. jan. 2017 kl. 05.11 skrev Xiaodi Wu <[email protected] 
> <mailto:[email protected]>>:
> While it looks nicer without the angle brackets, that suggestion is 
> unresponsive to David's point that we need some way to distinguish defaulted 
> generic arguments from inferred generic arguments.
> 
> Consider:
> ```
> let a: Optional = 1 // Optional<Int>
> 
> enum FloatPreferringOptional<T = Float> {
>   case some(T)
>   case none
> }
> 
> let b: FloatPreferringOptional = 1
> // Does this give you an FloatPreferringOptional<Int>?
> ```
> 
> If the answer to the above question is "yes, T is inferred as Int" then we 
> need some way to express "give me the default for T, which is Float." If the 
> answer to the above question is "no" then we need some way to express "don't 
> give me the default; rather, infer type T from the right hand side."
> 
> 
> On Mon, Jan 23, 2017 at 6:30 PM, Matthew Johnson via swift-evolution 
> <[email protected] <mailto:[email protected]>> wrote:
> This proposal looks good to me.  I have been looking forward to more flexible 
> generic arguments for a while.
> 
> I agree with previous commenters who prefer the option to leave off the angle 
> brackets when all parameters have defaults.
> 
> The proposal specifically mentions that the syntax is inspired by that of 
> function arguments.  This is good, but I wonder if maybe we should draw 
> further inspiration from function arguments and also add parameter labels for 
> generic arguments.  Both feel like low hanging fruit in the generics area 
> (correct me if I’m wrong about that) and it would be great to see both 
> enhancements make it into Swift 4.
> 
>> On Jan 23, 2017, at 9:55 AM, Srđan Rašić via swift-evolution 
>> <[email protected] <mailto:[email protected]>> wrote:
>> 
>> Hi Everyone,
>> 
>> I've opened a PR (https://github.com/apple/swift-evolution/pull/591 
>> <https://github.com/apple/swift-evolution/pull/591>) proposing default 
>> generic arguments which I think would be nice addition to the language. They 
>> are also mentioned in "Generic manifesto". 
>> 
>> The proposal is focusing around generic types. Generic functions are not 
>> coved by the proposal and I don't think that we need default generic 
>> arguments in generic functions as all the types are always part of the 
>> function signature so the compiler can always infer them. One corner case 
>> might be if using default argument values in which case support for default 
>> generic arguments in functions might be useful.
>> 
>> It would be great to hear your opinions and suggestions so I can refine the 
>> proposal.
>> 
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> 
> _______________________________________________
> 
> 
> swift-evolution mailing list
> 
> 
> [email protected] <mailto:[email protected]>
> 
> 
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> 
> 
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to