> On Nov 30, 2016, at 4:05 PM, Ramiro Feria Purón 
> <ramiro.feria.pu...@gmail.com> wrote:
> 
> Formally, perhaps the proposal should include the following:
> 
> 1. Missing type parameters are assumed to be implicit and trailing (as in the 
> particular case of all type parameters missing).

Yeah, this makes sense. Presumably this means that one could also write

        foo<>(1)

where everything is still deduced. In C++, this syntax exists and means that 
non-template functions named “foo” are ignored.

> 2. _ is allowed as a placeholder when specifying explicit parameters in a 
> function call. The corresponding parameter is assumed to be implicit.

This could be a more general feature that works wherever a type is specified 
and deduction works. For example, today you can do, e.g,

        let d1: Dictionary = [ “Hello” : 2017 ]

and we’ll infer the type arguments. It wouldn’t be unreasonable to allow 

        let d2: Dictionary<_, Int32> = [ “Hello”: 2017 ]

or

        let d3: [ _: Int32 ] = [ “Hello”: 2017 ]

or 

        let d4 = [ “Hello”: 2017 ] as [ _: Int32 ]

to partially specify the types of the result. I think this is a 
separate-but-interesting proposal (that is out of scope for Swift 4 stage 1).

> 
> In addition to this, and following the discussion on the unsafeBitCast 
> example, it might be a good idea to incorporate to the proposal adding an 
> (optional) explicit keyword for type parameters in generic function 
> definitions:
> 
> func unsafeBitCast<explicit U, T>(_ x: T) -> U
> 
> foo(unsafeBitCast(something))      // error: explicit type parameter required
> foo(unsafeBitCast<U>(something))   // ok

As I noted in my reply to Dave, I personally don’t want this: I feel that the 
idiom used by unsafeBitCast produces more readable code with already-existing 
features.

        - Doug


> Regards,
> Ramiro
> 
> 
> 
> 
> On Thu, 1 Dec 2016 at 01:36 Ramiro Feria Purón <ramiro.feria.pu...@gmail.com 
> <mailto:ramiro.feria.pu...@gmail.com>> wrote:
> Or perhaps in a more "swifty" way, use _ for implicit type parameters, i.e.:
> 
> f<_,T>()
> 
> On Thu, 1 Dec 2016 at 01:13 Ramiro Feria Purón <ramiro.feria.pu...@gmail.com 
> <mailto:ramiro.feria.pu...@gmail.com>> wrote:
> Douglas,
> 
> Regarding the question on the restriction for type parameters to appear on 
> the signature, the answer is remain. The proposal does not intend this 
> restriction to be lifted.
> 
> One might expect to find a few legitimate cases where having it lifted would 
> be handy or desirable. They seem to emerge often, for example, while 
> developing components using Core Data. From a real case scenario:
> 
> protocol Activable { var dateLastActive: Date { get } }
> 
> class A: NSManagedObject {}
> class B: NSManagedObject {}
> //..
> class Z: NSManagedObject {}
> 
> extension A: Activable { var dateLastActive: Date { return Date() } }
> extension B: Activable { var dateLastActive: Date { return Date() } }
> //..
> extension Z: Activable { var dateLastActive: Date { return Date() } }
> 
> 
> 
> func deleteInactiveObjects<T: NSManagedObject>(since date: Date, inContext 
> context: NSManagedObjectContext) where T: Activable {
>     //..
> }
> 
> // for the sake of the example
> let context = NSManagedObjectContext(concurrencyType: 
> .privateQueueConcurrencyType)
> let yesterday = Date()
> let oneWeekAgo = Date()
> 
> 
> deleteInactiveObjects<A>(since: yesterday, inContext: context)
> deleteInactiveObjects<B>(since: oneWeekAgo, inContext: context)
> //..
> 
> (here again, as you mention, the parameter affects how the function operates, 
> yet it is not part of the signature)
> 
> If the restriction was lifted, however, it would also be in detriment of the 
> educational value of the proposal (apart from your arguments above). When 
> defining a generic function, it feels natural to expect all of the type 
> parameters to be present in the generic function signature. Relaxing this 
> rule could be perceived by the novice as an invitation to an obscure design. 
> In the best case, it would generate doubts about its actual intent. 
> 
> From a pedagogical perspective, the proposal aims to save Swift from 
> disappointment when this topic is brought to discussion, say whether at the 
> end of a Programming or a Compilers undergraduate course -- albeit fully 
> understanding (or implementing) the current alternatives could be an 
> excellent exercise for the class.
> 
> From the (primary) language and development perspective, I don't think it 
> could be expressed in a better way than in your lines, which are truly 
> appreciated:
> 
> "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."
> 
> Finally, we should also consider the possibility of being explicit about some 
> but not all type parameters. If allowed, something like "only trailing type 
> parameters could be missing" would be necessary to avoid ambiguity.
> 
> All the best,
> Ramiro
> 
> 
> On Tue, 29 Nov 2016 at 17:11 Douglas Gregor <dgre...@apple.com 
> <mailto:dgre...@apple.com>> 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...
> 
> 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.
> 
> 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
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to