> 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

Reply via email to