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.puron@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,
RamiroOn Tue, 29 Nov 2016 at 17:11 Douglas Gregor <dgregor@apple.com> wrote:
On Nov 21, 2016, at 3:05 PM, Ramiro Feria Purón via swift-evolution < > 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 stringIf 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 inferredlet 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 CarprocessAll<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 tofunc 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