> On 26 Jan 2017, at 02:15, Xiaodi Wu via swift-evolution 
> <[email protected]> wrote:
> 
> Srdan, I'm afraid I don't understand your discussion. Can you simplify it for 
> me by explaining your proposed solution in terms of Alexis's examples below?
> 
> ```
> // Example 1: user supplied default is IntegerLiteralConvertible
> 
> func foo<T=Int64>(t: T) { ... }
> 
> foo(22)
> //  ^
> //  |
> //  What type gets inferred here?
> ```
> 
> I believe that it is essential that the answer here be `Int` and not `Int64`.
> 
> My reasoning is: a user's code *must not* change because a library *adds* a 
> default in a newer version. (As mentioned in several design docs, most 
> recently the new ABI manifesto, defaults in Swift are safe to add without 
> breaking source compatibility.)
> 
> Here, if version 1 of a library has `func foo<T>(t: T) { ... }`, then 
> `foo(22)` must infer `T` to be `Int`. That's just the rule in Swift, and it 
> would be severely source-breaking to change that. Therefore, if version 2 of 
> that library has `func foo<T=Int64>(t: T) { ... }`, then `foo(22)` must still 
> infer `T` to be `Int`.
> 
> Does your proposed solution have the same effect?
> 
> ```
> // Example 2: user supplied default isn't IntegerLiteralConvertible
> 
> func bar<T=Character>(t: T) { ... }
> 
> bar(22)
> //  ^
> //  |
> //  What type gets inferred here?
> ```
> 
> By the same reasoning as above, this ought to be `Int`. What would the answer 
> be in your proposed solution?
> 


I fundamentally disagree. In this case, you’re treating “22” as having type 
Int, which is conceptually false. Literals do not have an inherent type - they 
are (ideally) abstract, arbitrary-precision “things” which can be transformed 
to a type in some context.

Let’s consider what a default binding for a generic parameter actually is and 
when it would be used by the compiler. It is a hint which gives the compiler 
context when it can’t infer one in any other way. Basically: if you pass in a 
String as parameter ’t’, the compiler has some context and knows that T must be 
String.self. It is only when the parameter value is representable as multiple 
types that the default would be consulted.

As Gankro mentioned WRT the Rust proposal, Int is not a “default” type for 
IntegerLiteralConvertible; it is a “fallback" to be used when the compiler 
cannot infer any other type because there is absolutely no context (e.g. “let 
myNum = 42”). In some other context, that literal may be transformed in to a 
different numerical type, a struct, enum, class or even an entire class 
hierarchy.

I believe that programmers would expect the literal in the first example to be 
an Int64. The function declaration gives the compiler context for the preferred 
type to use.

Ultimately, default bindings for generic parameters are syntax-level 
conveniences. There is no code which is impossible without them; they save you 
being explicit about certain types by allowing the library author to pick 
sensible/optimal values to use in case you have no specific requirement for a 
particular parameter. Therefore, it stands to reason that adding a default 
parameter, and feeding the compiler some context where there previously was 
none, would be a potentially source-breaking change. It does not, however, 
necessarily need to be a resilience-breaking change; we could store the 
defaults information in some kind of metadata and leave the original function 
symbols intact. The function/type is still as generic as it ever was, after all.

In your example, T is never returned from the function, so it makes no 
difference to anybody what type “T” actually gets inferred as. If it did, and 
they tried to store it as some particular type which is no longer the resolved 
type of T, it would be a compile error. Just like we have to do all the time in 
Swift, they would have to provide explicit context - for example, by writing 
“22 as Int”.

If the design documents disagree, we can change them. There is no such thing as 
“default types” in the language right now (only default values), so it is 
surprising that ABI documentation would attempt to impose constraints on 
whether or not they may be source-breaking. It is more important that we have 
the right design for Swift, rather than one which is consistent with some 
arbitrary restrictions defined before the feature even existed.

As for the second example, yes it should be Int. The context, which tells the 
compiler to prefer Character, is not meaningful to an integer literal. In that 
case, the zero-context “fallback” applied - i.e. Swift.Int.

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

Reply via email to