> 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