As I replied above, this doesn't work IMO because omitted generic arguments are inferred, and that can't change without being hugely source-breaking.
I think it's absolutely essential that adding a default to my library doesn't change the behavior of code that uses my library. That's currently the case, afaict, for all default arguments, and so I think it's essential here. On Tue, Jan 24, 2017 at 17:26 Srđan Rašić via swift-evolution < [email protected]> wrote: > We are probably taking the wrong direction here and trying to solve the > problem that does not need solving. We are discussing how to infer > gereneric arguments in type declarations while we should not do that at > all. > > Let me repeat Doug's examples: > > > struct X<T = Int> { } > > func f1() -> X<Double> { return X() } > > func f2() -> X<Int> { return X() } > func f2() -> X<Double> { return X() } > > func f3<T>(_: T) -> X<T> { return X() } > > let x1: X = f1() // okay: x1 has type X<Double>? > let x2: X = f2() // ambiguous? > let x3a: X = f3(1.5) // okay: x3a has type X<Double>? > let x3b: X = f3(1) // okay: x3a has type X<Int>? > > Thinking about what the generic argument of X should be inferred to for > x1, x2 and x3 is pointless. If one omits generic arguments in the variable > declaration, one is accepting the defaults. In other words, doing let x: X > = ... should always be treated as doing let x: X<Int> = ..., regardless of > what we have on the right hand side. No inference should happen in this > case. It would mean inferring already specified type. > > Why? Consider what happens if we define x as a property: > > struct Test { > let x: X > > init() { > x = f() > } > } > > It would make no sense that the initialization in the initializer > specializes the generic argument of the property, so for the sake of > consistency we should not do it for the variables/constants either. > > Given that, we can solve Doug's example as: > > let x1: X = f1() // error: cannot assign X<Double> to X<Int> > > let x2: X = f2() // ok: using X<Int> overload > let x3a: X = f3(1.5) // error like in x1 > let x3b: X = f3(1) // ok because rhs is inferred as X<Int> > > I think this is the only valid way to go and it really simplifies things, > both the understanding of how the feature works, but also the > implementation. > > What do you think? > > > tir. 24. jan. 2017 kl. 22.16 skrev David Sweeris <[email protected]>: > > > On Jan 24, 2017, at 11:41, Alexis via swift-evolution < > [email protected]> wrote: > > 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 > 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. > > > We could just remove that parameter from the type inference system... if > the default value is Int and the user passes in a String, that'd be an > error, unless the user also sets that parameter to String. > > I'd envisioned using default parameters as more "compile-time > configuration options" than something for the type system to actually have > deal with. IIRC, I was trying to come up with a way to write just one > arbitrary-sized integer struct where I *could* specify the width of its > internal calculations, but would usually just use a default value. > > - Dave Sweeris > > _______________________________________________ > 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
