> On Nov 28, 2016, at 10:11 PM, Douglas Gregor via swift-evolution
> <[email protected]> wrote:
>
>>
>> On Nov 21, 2016, at 3:05 PM, Ramiro Feria Purón via swift-evolution
>> <[email protected] <mailto:[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…
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
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution