> On Nov 29, 2016, at 8:00 AM, Derrick Ho via swift-evolution
> <[email protected]> wrote:
>
> I don't think the angle brackets adds any additional benefit than adding the
> type information as a parameter. Adding Angle brackets will just make it
> more crowded….
Adding the type information as a parameter effectively disables type inference
for that parameter, because you have to pass the parameter explicitly. In some
cases, like the unsafeBitCast function I pointed out, that is a good thing. In
other cases, type inference might do the right thing for most callers, but
specific call sites want the extra control provided by explicitly specifying
generic arguments. That’s how I see this proposal: not as a replacement for the
metatype parameter idiom that unsafeBitCast uses, but as a way to be more
explicit at particular call sites when type inference either fails (e.g., due
to lack of contextual type information), produces a result different than what
is desired, or is sufficiently complicated that the call site requires more
documentation.
> plus, the syntax just seems too much like c++
Lots of languages use angle brackets like this; Swift has it for types already,
so I find this an odd criticism.
- Doug
> On Tue, Nov 29, 2016 at 8:43 AM Goffredo Marocchi via swift-evolution
> <[email protected] <mailto:[email protected]>> wrote:
> I think this is a case where the angle bran jets is both more readable and
> terse without losing context... opinions and all :).
>
> Sent from my iPhone
>
> On 29 Nov 2016, at 09:47, Andrew Trick via swift-evolution
> <[email protected] <mailto:[email protected]>> wrote:
>
>>
>>> On Nov 28, 2016, at 10:11 PM, Douglas Gregor via swift-evolution
>>> <[email protected] <mailto:[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] <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] <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
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution