> On Nov 28, 2016, at 10:11 PM, Douglas Gregor via swift-evolution > <swift-evolution@swift.org> wrote: > >> >> On Nov 21, 2016, at 3:05 PM, Ramiro Feria Purón via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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…
Angle brackets in function calls are hideous. This is objectively more clear and much prettier IMO: unsafeBitCast(something, to: Int) > it would enable type inference to go wild with unsafe casts: > > foo(unsafeBitCast(something)) // just cast it to.. whatever > > which is… not great. > > I’d like one bit of clarification in the proposal. Right now, one is not > permitted to have a type parameter in a generic function that isn’t used > somewhere in its signature, e.g., > > func f<T>() -> Void { … } // error: T is not part of the signature of > f() > > This restriction is obvious in today’s Swift, because there is absolutely no > way one could ever use this function. With your proposed extension, it would > be possible to use this function. Does the restriction remain or is it lifted? > > Personally, I’d like the restriction to stay, because it feels like such > functions fall into the same camp as unsafeBitCast: if the type parameter > affects how the function operates but is *not* part of its signature, then it > should be expressed like a normal parameter (of a metatype). It also helps > provide better diagnostics when changing a generic function to no longer > require one of its type parameters. +1 for required type parameters being normal parameters. I think the case mentioned in the proposal reads much better as: processAll(in: vehicles, as: Bicycle, condition: aboveSpeedLimit) If angle brackets can be limited to generic definitions and type names, that’s a great accomplishment. -Andy > > And, as Dave notes, it’s effectively syntactic sugar, so it belongs in Swift > 4 stage 2. > > - Doug > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org <mailto:swift-evolution@swift.org> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution