> On Dec 3, 2017, at 11:36 AM, Chris Lattner <clatt...@nondot.org> wrote:
> 
> On Dec 2, 2017, at 7:11 PM, Matthew Johnson <matt...@anandabits.com 
> <mailto:matt...@anandabits.com>> wrote:
>>> 
>>> This does not improve clarity of code, it merely serves to obfuscate logic. 
>>>  It is immediately apparent from the APIs being used, the API style, and 
>>> the static types (in Xcode or through static declarations) that this is all 
>>> Python stuff.  
>> 
>> It may be immediately apparent when the types involved are obviously 
>> dynamic, such as in this example where Python.import is explicitly used.  
>> However, my concern is less about the intended use case of dynamic language 
>> interop than I am that this feature will be generally available to all types 
>> in Swift.  
>> 
>> This is big change from AnyObject dispatch.  It opens up the dynamism to 
>> types and contexts that are not necessarily obviously using dynamic lookup, 
>> callable, etc.  Maybe this won’t turn out to be a problem in practice but I 
>> still think it’s a legitimate concern.
> 
> Sure, it is a legit concern, but it is also nothing new.  This is the 
> standard concern with type inference.

The concern for me is orthogonal to type inference.  The name of a type 
supporting dynamic lookup will not necessarily provide any indication that the 
type supports dynamic lookup.

> 
> While there are weird cases, in practice, values do not get magicked out of 
> no-where.  They most commonly are either root values like:
> 
>       let np = Python.import(“foo”)
>       let pyInt = PyVal(42)
> 
> or they come for parameters:
> 
>       func f(x : PyVal) {
> 
> The place that is potentially surprising is when the type gets buried because 
> you’re working with some API that returns a [String, PyVal] dictionary or 
> something:
> 
> 
>       let x = foo()[“someKey”]
> 
> and you don’t realize that PyVal’s are involved.  However, if you are 
> actively writing the code, you have access to code completion and other 
> things that tell you these types, and if it is important for the clarity of 
> the code, you write this instead:
> 
>       let x :PyVal = foo()[“someKey”]
> 
> There is nothing specific to this proposal about this issue.

See above.  In the case of PyVal specifically the concern is somewhat mitigated 
by the name of the type.  That won’t necessarily always be the case.

> 
> 
>> I’m uncertain what the right answer is.  I’m still not really comfortable 
>> with opening up dynamic lookup to any user-defined type without some way to 
>> indicate to readers that dynamic lookup is happening in a piece of code.  
>> Maybe there is a less localized annotation that would indicate dynamic 
>> lookup is in effect for a larger chunk of code.  
> 
> You seem to be extremely concerned that people will adopt DynamicMemberLookup 
> for types where it doesn’t make sense and abuse the feature.  I am having a 
> real problem understanding what your concern is, so I’d really love for you 
> to explain some theoretical examples of the bad thing that happens: why 
> someone (non-maliciously) adopts the protocol, what code gets written, and 
> what harm actually comes from it.
> 
> Let me use a made up tale from a parallel universe to illustrate why I don’t 
> understand your concern.  Imagine if Swift didn’t already interoperate with 
> C, and did not already have IUOs.  Someone who cared about C language 
> interoperability would quickly realize that the ergonomics of importing 
> everything as strong optionals is a non-starter, jeopardizing the usability 
> of C interop, and would propose IUOs as a feature.
> 
> We’d then have a long and drawn out conversation about the various options on 
> how to model this, the pros and cons of each, and would settle on IUO as the 
> least bad design (as an aside, in our universe, when we went through the 
> design process that led to IUOs, this is exactly what happened, we even 
> considered syntaxing them as interobangs :-).
> 
> At that point, there would be a general uproar because IUOs have high 
> potential for abuse: Swift is “all about” strong types and safety, which IUOs 
> undermine.  Strong optionals are considered a pain to use by some people and 
> widely misunderstood (I think they are the biggest challenge in learning 
> Swift in practice), and so it is a reasonable feature that people could 
> pervasively adopt IUOs, leading to a much worse world all around.
> 
> 
> This made up parallel universe is exactly analogous to what is happening now. 
>  DynamicMemberLookup is no more dangerous and harmful than IUOs are.  They 
> will be one more tool in the toolbox.  While it is possible that someone will 
> abuse it, this will not be widespread.  People who are particularly worried 
> will build a single new rule into their linters (which already flag uses of 
> x!), and the world will keep revolving.

There is an important difference between IUOs and dynamic lookup in my mind.  
In the case of dynamic lookup a runtime value (the member name) is masquerading 
as something that is statically verified everywhere in Swift *except* in the 
case of dynamic lookup.  I would strongly prefer to not need to consider the 
possibility that a member name is actually a runtime value outside of contexts 
that make this possibility known to me when I am reading code.  Spelling a 
member name right is a precondition that is trivial to violate both by accident 
and by code evolution.

That is also why I am not concerned about the potential for failure of the 
longhand way of writing this: x.get(“foo”).get(“bar”).  It is clear that a 
runtime value (which may violate a precondition) is being provided.  That is 
not at all the case when the dynamic lookup syntax mirrors static lookup syntax 
with no contextual hint that it may be in effect.

An example of the kind of thing I am concerned about is people using dynamic 
lookup to avoid more structured forms of polymorphism.  I can imagine this 
happening for a number of reasons that are not intentionally abusive or 
malicious.  

Some people are big fans of dynamic behavior and this feature will make it much 
easier to write code in that style.  They will do it without feeling malicious 
or considering this to be abusive, considering it to be a legitimate style 
preference.  I wouldn’t be surprised to see people develop mixins that 
implement the subscript using mirror and other future reflection capabilities 
without considering that to be abusive (I would almost be surprised if this 
didn’t happen).  Requiring some kind of usage site annotation would both 
discourage this and help anyone who walks into a such a code base to understand 
what is going on.

> 
> 
>>> Even the behavior of AnyObject was carefully designed and considered, and 
>>> were really really good reasons for it returning IUO.
>> 
>> I am not trying to call into question the choices made in the past.  Swift 
>> wouldn’t be the great language with a bright future that it is today without 
>> an incredibly successful migration of a large user base from Objective-C to 
>> Swift.  This is a huge accomplishment and couldn’t have happened without 
>> making really good decisions about some really hard tradeoffs.
> 
> You miss my point.  My point is that AnyObject lookup was carefully 
> considered, has stood the test of time, and is the *right* answer.  Swift 1 
> would not have been nearly as successful without it.

I don’t think I do.  I was trying to agree with exactly the point that it was 
the right answer in the early days of Swift and getting it right then was 
essential to Swift’s success.  

Aside from the historical necessity of AnyObject, it is also a very specific 
and widely know type that doesn’t have any statically available members at all 
and only looks up @objc members.  These properties help to reduce the risk that 
somebody misunderstands what is going on.

> 
> -Chris
> 

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to