[swift-evolution] Proposal: Allow explicit type parameter specification in generic function call

Douglas Gregor dgregor at apple.com
Wed Nov 30 22:42:41 CST 2016


> On Nov 30, 2016, at 4:09 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 
> on Mon Nov 28 2016, Douglas Gregor <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
> 
>>> On Nov 21, 2016, at 3:05 PM, Ramiro Feria Purón via swift-evolution
>> <swift-evolution at 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...
>> 
>> 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.

Well, I’d say we already have it: it’s the pass-a-metatype approach already used by unsafeBitCast, and I think usages of that API read really, really well as it is.

>  I might even be willing to inhibit deduction,
> by default, of all generic function type parameters that don't appear in
> the parameter list.


I’m not a fan of this for the reasons I and Ramiro outlined.

	- Doug

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161130/0f80bac3/attachment.html>


More information about the swift-evolution mailing list