> On Nov 30, 2016, at 4:05 PM, Ramiro Feria Purón
> <[email protected]> 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 <[email protected]
> <mailto:[email protected]>> 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 <[email protected]
> <mailto:[email protected]>> 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 <[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...
>
> 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
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution