* What is your evaluation of the proposal? a reluctant +1 * Is the problem being addressed significant enough to warrant a change to Swift? Yes. * Does this proposal fit well with the feel and direction of Swift? Yes. * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those? It works well enough * How much effort did you put into your review? A glance, a quick reading, or an in-depth study? Read a few times over.
The point that actually tipped my opinion came from Jordan Rose " Argument labels are definitely part of the *name* of the function, but they aren’t part of the *type*. A few functions happen to have argument labels " I am of the general opinion that argument labels are part of the type, which helps explain `stride(to:by:)` vs `stride(through:by:)` in terms of overloading instead of name lookup. While this proposal would render that explanation invalid, I realize that I was conflating the ideas of name and type. I wish we could have the tuple to tuple model but I see how it isn't tractable when combined with other features. On Fri, Jul 1, 2016 at 12:56 PM, Michael Ilseman via swift-evolution < swift-evolution@swift.org> wrote: > > On Jul 1, 2016, at 1:30 AM, Taras Zakharko via swift-evolution < > swift-evolution@swift.org> wrote: > > Jordan, Thanks for the very insightful explanation! It all makes a lot of > sense in perspective. > > Apparently I was thinking about this issue a bit while I was sleeping, and > now it seems to me that part of the problem is because one strives for the > function signature to be linguistically meaningful (as in natural language > meaningful). It was mentioned that argument labels often don’t make much > sense when detached from the function name, and that some function seem to > have semantically compatible signatures and some don’t, e.g. the example of > drawLineTo(x: Float, y: Float) and drawLineWith(angle: Float, distance: > Float) > > So this is actually a linguistic problem. More precisely, its a problem of > predicate frames/argument semantics. Consider verbs like ‚hit' and ‚kill'. > In term of precise semantics, we can model them as something like > > kill(killer:victim:) > hit(hitter:victim:) > > However, the actual status of the arguments here is compatible. Both verbs > describe asymmetric actions, with one argument playing an active role in > (negatively) changing the state of the other , passive one. So both are > compatible with a broad metatype (what we often call predicate type in > linguistics) > > P(agent:undergoer:) > > However, there are plenty of verbs that are quite different. Like > go(person:to). Also two arguments, but the semantic status of them is very > different. > > If that is really the case, then there is indeed no general solution which > keeps the argument labels semantically meaningful. But there is still a > potential conflict with the tuple/function signature labels. > The only reasonable choice that comes to my mind is to completely drop > argument labels in closure variables and just look at the argument type. > Basically, by assigning function variables, we drop any semantics and just > look at the overall structure (cardinality/argument types) > > In more detail: > > 1. Maintain that argument labels are not part of the type, but merely > hints for the function dispatch/programmer convenience > > > They are not merely hints, they are part of the full name of the function. > Functions with different names are different functions, even if they share > the same base name. That is, they are syntactically meaningful. > > 2. *Disallow* argument labels in closure variables. I.e.: > > var fun = drawLineTo(x:y:) > > has type (Float, Float) -> (), which makes the variable explicitly > compatible with any function of cardinality 2 that takes Float arguments. > At the sae time, any declaration like > > var fun : (x: Float, y: Float) -> () > > should be illegal. This further makes clear that tuples and functions > are not the same thing. > > > 3. In the long term, maybe consider *removing* *labels from tuples*. At > the same time, there should be a new mechanism in place that allows one to > elevate tuples to structs, with properties taking the role of the current > tuple labels (like Python’s namedtuple) > > An alternative, in order to keep the cake and eat it too, would be > something along the lines of making predicate types explicit. E.g. creating > some sort of function ‚semantic metatype‘ and declaring function > conformance to this metatype. But I can’t imagine that it is a good idea. > Natural languages are really not a good source of inspiration in this > regard. > > Best, > > Taras > > > On 01 Jul 2016, at 05:33, Jordan Rose <jordan_r...@apple.com> wrote: > > > On Jun 30, 2016, at 13:36, Taras Zakharko via swift-evolution < > swift-evolution@swift.org> wrote: > > > On 30 Jun 2016, at 22:11, Austin Zheng <austinzh...@gmail.com> wrote: > > As for the label semantics, Swift's current behavior is actively > misleading, please see the example in the prior email. There are no > meaningful semantics in the label, because implicit conversion between > differently-labeled function types means that there is no way to usefully > enforce these invariants to begin with. > > > That is a good point. I admit to not knowing this (I strongly expected > that labels would be semantically meaningful). But what exactly is the > status of the argument labels than in Swift? Just a documentation device > for the programmer and a hint for the compiler to do function dispatch? > But if the compiler indeed does dispatch on argument labels, then they are > not completely void of semantics, are they? As I mentioned before, I think > the problem here is much deeper. > > The state of affairs I would prefer is something along these lines: > > 1. Labels are semantically meaningful > 2. There is an explicit casting system for function signatures > 3. This casting system should be in close correspondence to tuples. The > "function argument lists look sort of like tuples“ is a very compelling > reason actually, because of the principle of the least surprise. If I have > two things in the language that look very similar, then its very confusing > if they exhibit very different behaviour. Again, I am not proposing that > one goes back to model functions in terms of tuples. But as long as there > is a surface resemblance (and an obvious morphisms between the two), at > least some aspects of their design should be kept in sync. > > But again, this touches on some deep design decisions for the language, so > I — as an amateur — don’t feel in my plate discussing this here. I believe > that there currently might be some inconsistencies in the language design > that should be sealed with (but maybe they are no inconsistencies at all > and I simply have false expectations). > > > Language history, a.k.a. story time! > > We started out with the “perfect” model of a function type being a map > from a tuple to a tuple. Different argument labels were just overloads. It > really was quite a simple model, other than not having 1-tuples. Well, and > variadics and default values and trailing closures didn’t make sense > anywhere but in functions, but still. Very simple. > > (And inout. And autoclosure. And maybe a few more.) > > Then we hit a snag: naming guidelines. We wanted argument labels to be > something people felt comfortable using, something that would be encouraged > over a sea of unlabeled arguments. But even before the Swift 3 naming > conventions were hammered out, the natural names for argument labels didn’t > seem to match the names you’d want to use in the function. So we split the > names of parameters off from the names of tuple elements. > > (This was precipitated by wanting to import Objective-C methods, but I > think it would have come up regardless.) > > As seen earlier in the thread, argument labels don’t make for good tuple > element labels. Especially with the Swift 3 guidelines, argument labels > usually don’t make sense without the context provided by the base name, and > two methods that happen to share argument labels might not actually be very > similar, while two methods that are duals of each other might have > different argument labels due to, well, English (e.g. 'add(to:)' vs. > 'remove(from:)’). > > The real blow, however, came with that very first idea: that we could > treat methods with different argument labels as simple overloads in type. > This led to poor diagnostics where the compiler couldn’t decide whether to > believe the types or the argument labels, and might tell you you have the > wrong argument labels rather than a type mismatch. For pretty much every > Apple API, this was the wrong decision. On top of all that, it was really > hard to refer to a method when you *didn’t* want to call it. (Most > methods with the same base name still have unique labels, so you don’t need > the types to disambiguate.) > > So we introduced the notion of “full names”, which are the things you see > written as ‘move(from:to:)` (and which are represented by DeclName in the > compiler). Almost immediately diagnostics got better, testing optional > protocol requirements got shorter, and a lot of compiler implementation got > simpler. > > And then we kind of got stuck here. We have full names used throughout the > compiler, but tuple labels still appear in types. They’re still used in > mangling. We got rid of the “tuple splat” feature, but still model > out-of-order arguments as “tuple shuffles”. And we allow a number of > conversions that *look* like they should be invalid, but aren’t. > > (And it’s important that we continue allowing them, or at least some of > them, because we want to be able to pass existing functions to things like > map and reduce without worrying about conflicting labels.) > > So we’ve given up the perfect ideal of tuple-to-tuple. But we did it > because we value other things more than that ideal: variadics, default > values, trailing closures, inout, autoclosure, distinct argument labels and > parameter names, referencing a function by full name, and diagnostics that > better match the user’s likely intent (particularly given the naming > guidelines and existing libraries). I think that’s a worthwhile trade. > > Jordan > > P.S. Anyone is allowed to think this is *not* a worthwhile trade! But > part of the purpose of this story is to show that we’re already 90% of the > way towards making tuples and function arguments completely separate, even > if they have similar syntax. This proposal gets us to maybe 95%. > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution > > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution > >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution