on Mon Nov 28 2016, Douglas Gregor <[email protected]> wrote:
>> On Nov 21, 2016, at 3:05 PM, Ramiro Feria Purón via swift-evolution > <[email protected]> wrote: >> >> Problem: >> >> Currently, it is not possible to be explicit about the generic parameters >> (type parameters) in a > generic function call. Type parameters are inferred from actual parameters: > >> >> func f<T>(_ t: T) { >> >> //.. >> } >> >> f(5) // T inferred to be Int >> f("xzcvzxcvx") // T inferred to be string >> >> If no type parameter is involved in the formal parameters, the type >> parameter needs to be used somehow as part of the return type. For example: >> >> func g<T>(_ x: Int) -> [T] { >> >> var result: [T] = [] >> >> //.. >> >> return result >> } >> >> In such cases, the type parameters must be inferrable from the context: >> >> g(7) // Error: T cannot be inferred >> let array = g(7) // Error: T cannot be inferred >> let array: [String] = g(7) // Ok: T inferred to be String >> let array = g<String>(7) // Error: Cannot explicitly specialise >> generic function >> >> >> >> Proposed Solution: >> >> Allow explicit type parameters in generic function call: >> >> let _ = g<String>(7) // Ok >> >> >> >> Motivation: >> >> Consider the following contrived example: >> >> class Vehicle { >> var currentSpeed = 0 >> //.. >> } >> >> class Bicycle: Vehicle { >> //.. >> } >> >> class Car: Vehicle { >> //.. >> } >> >> @discardableResult >> func processAll<T: Vehicle>(in vehicles: [Vehicle], condition: (Vehicle) -> >> Bool) -> [T] { >> >> var processed: [T] = [] >> >> for vehicle in vehicles { >> guard let t = vehicle as? T, condition(vehicle) else { continue } >> //.. >> processed.append(t) >> } >> >> return processed >> } >> >> func aboveSpeedLimit(vehicle: Vehicle) -> Bool { >> return vehicle.currentSpeed >= 100 >> } >> >> >> let processedVehicles = processAll(in: vehicles, condition: aboveSpeedLimit) >> // Uh, T inferred to > be Vehicle! >> let processedCars: [Car] = processAll(in: vehicles, condition: >> aboveSpeedLimit) // T inferred to > be Car >> processAll<Bicycle>(in: vehicles, condition: aboveSpeedLimit) // This should >> be allowed under this > proposal >> >> >> Notes: >> >> If necessary, the (real life) Swift code that lead to the proposal could be >> shared. > > This seems completely reasonable to me. I had always expected us to > implement this feature, but we never got around to it, and it wasn’t a > high priority because one can always use type inference. Additionally, > there were a few places where we originally thought we wanted this > feature, but prefer the more-explicit form where the user is required > to explicitly pass along a metatype. unsafeBitCast is one such case: > > func unsafeBitCast<T, U>(_ x: T, to: U.Type) -> U > > Even if we had the ability to provide explicit type arguments, we > would *not* want to change this signature to > > func unsafeBitCast<U, T>(_ x: T) -> U // bad idea > > because while it makes the correct usage slightly cleaner: > > unsafeBitCast<Int>(something) // slightly prettier, but... > > it would enable type inference to go wild with unsafe casts: > > foo(unsafeBitCast(something)) // just cast it to.. whatever > > which is… not great. Yeah, but IMO ideally we'd have a way to inhibit deduction of some generic type parameters. I might even be willing to inhibit deduction, by default, of all generic function type parameters that don't appear in the parameter list. -- -Dave _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
