Proposal: Introduce User-defined "Dynamic Member Lookup" Types

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.

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.

Going with this line of thought: a lot of these concerns could be a job for static analysis. Autocomplete, linters, refactoring tools, etc. can all help us reason wisely about dynamism where it appears.

One important factor in the success of Swift’s type inference is that modern dev tools are up to the task of working with it. Xcode (and AppCode for that matter) have, shall we say, a long way to go to realize their potential — but even with their warts, the fact is that a developer today can reasonably expect real-time feedback about code structure that is not explicitly surfaced in the syntax itself.

It’s worth asking why Java didn’t add Swift-like type inference 20 years ago. Java is a language whose type system at the time (no function types, no generics even!) would if anything have made inference much easier to implement, and for developers to reason about. I don’t think this was just down to Gosling’s taste, though; language designers can assume some ready availability of static analysis at edit time in a way they couldn’t back in the 90s.

• • •

What do I mean by this in practice? Well:

I agree with Chris that this syntax is…yucky:

    let y = np^.arange^(24)^.reshape^(2, 3, 4)

…but an editor could use syntax coloring to differentiate dynamic dispatches:

    let y = np.arange(24).reshape(2, 3, 4)

Teams worried about their abuse or inadvertent use could make them bold and red. This would achieve the same purpose as the separate syntax, sans yuckiness.

Refactoring tools could flag •potential• name matches in dynamic dispatches much the same they currently do for comments.

For those teams concerned about abuse of the feature, a lint tool could enable individual project to either prohibit dynamic calls or limit them to certain files or comment-fenced code sections.

Most of the concerns I’ve heard expressed in this thread could be addressed by sensible developers and good tools. The latter are feasible; the former no language can enforce.

···

On Dec 3, 2017, at 11:36 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
On Dec 2, 2017, at 7:11 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

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.

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.

-Chris

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

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.

···

On Dec 3, 2017, at 11:36 AM, Chris Lattner <clattner@nondot.org> wrote:
On Dec 2, 2017, at 7:11 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

-Chris

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.

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.

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.

The difference is that IUOs are marked by a "!“ whereas dynamic member lookups look just like normal member lookups but unlike them can fail.
With the exception of corner cases like indexed lookups or arithmetic overflow Swift marks places where something can fail with "!“ or "Unsafe“ prefixes or "try“ or "?“. The latter examples are even protected from runtime failure (crashes) because the type system enforces handling the failing case. Nonetheless we put the "try“ and "?“ to mark those places (and with good reason).
One might even say that indexed lookups are marked by special syntax ("[…]“).

Now DynamicMemberLookup would introduce a new possibility where something can fail with a runtime crash and it is *not* visible that this can happen there. A typo in the member name is sufficient to trigger a crash (at least the PythonPlayground did crash when I changed a name being looked up - will this change? Probably not because there is nothing it could sensibly do!).

This is not possible in current Swift and therefore it should be visible somehow.

-Thorsten

···

Am 03.12.2017 um 18:36 schrieb Chris Lattner via swift-evolution <swift-evolution@swift.org>:
On Dec 2, 2017, at 7:11 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

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.

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.

-Chris

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

Sent from my iPad

Sent from my iPad

For all those reasons, we really do need something like AnyObject dispatch if we care about working with dynamically typed languages. The design I’m suggesting carefully cordons this off into its own struct type, so it doesn’t infect the rest of the type system, and is non-invasive in the compiler.

I am quite familiar with dynamic languages and agree that this is necessary if we are going to fully open up access to these languages from Swift.

Ok, then it appears you agree that something like anyobject dispatch is necessary for effective dynamic language interop.

I strongly urge you to reconsider the decision of that dynamic members must be made available with no indication at usage sites. An indication of dynamic lookup at usage sites aligns very well (IMO) with the rest of Swift (AnyObject lookup aside) by calling attention to code that requires extra care to get right.

I don’t understand this. The proposal is fully type safe, and this approach is completely precedented by AnyObject. Swift’s type system supports many ways to express fallibility, and keeping those decisions orthogonal to this proposal is the right thing to do, because it allows the author of the type to decide what model makes sense for them.

Allowing the author of the type to choose whether the mechanism is hidden or visible is exactly what I don’t want to allow. I think you have the right design regarding types and semantics - the author chooses. But I don’t want these calls to look like ordinary member lookup when I’m reading code.

They inherently have a much greater chance of failure than ordinary member lookup. Further, authors are likely to choose immediate traps or nil IUO as failure modes as forcing users to deal with Optional on every call is likely to be untenable. I believe this behavior should be represented by some kind of syntax at the usage site. I don’t believe it is an undue burden. It would make the dynamic lookup semantic clear to all readers and would help to discourage abuse.

I believe that adding explicit syntax would be counterproductive to your goals, and would not make dynamic lookup syntax more clear. I assume that you would also want the same thing for DynamicCallable too, and operator overloads, subscripts, and every other operation you perform on these values, since they all have the exact same behavior.

If we required some syntax even as minimal as “foo.^bar” and "baz^(42)”, that change would turn this (which uses runtime failing or IUO return values like AnyObject):

  let np = Python.import("numpy")
  let x = np.array([6, 7, 8])
  let y = np.arange(24).reshape(2, 3, 4)
  
  let a = np.ones(3, dtype: np.int32)
  let b = np.linspace(0, pi, 3)
  let c = a+b
  let d = np.exp(c)
  print(d)

into:

  let np = Python.import("numpy")
  let b = np^.array^([6, 7, 8])
  let y = np^.arange^(24)^.reshape^(2, 3, 4)
  
  let a = np^.ones^(3, dtype: np^.int32)
  let b = np^.linspace^(0, pi, 3)
  let c = a+^b
  let d = np^.exp^(c)

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.

If dynamism if restricted to subclasses of a DynamicObject type, like Xiaodi suggested earlier, then we can protect ourselves from this dynamic dispatch being generally available to all types in Swift.

Chris has good reasons for not wanting to use a class. More generally, designs that require subclassing a specific superclass are usually a bad idea. They should only be used with very specific and very good reasons. I’m not sure what this would buy us here. How specifically do you think this helps in ways that requiring conformance to be stated in the original type declaration will not?

It achieves the same objectives as requiring conformance be stated in the original type declaration. But I’m less enthusiastic about this approach as it introduces a new language rule for one specific protocol.

···

On 3 Dec 2017, at 18:42, Matthew Johnson <matthew@anandabits.com> wrote:
On Dec 3, 2017, at 10:40 AM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:

On 3 Dec 2017, at 04:11, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Dec 2, 2017, at 7:40 PM, Chris Lattner <clattner@nondot.org <mailto:clattner@nondot.org>> wrote:

On Dec 2, 2017, at 2:13 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

When you start mixing in use of native Swift types like dictionaries (something we want to encourage because they are typed!) you end up with an inconsistent mismash where people would just try adding syntax or applying fixits continuously until the code builds.

Beyond that, it is counterproductive to your goals, because it means that people are far less likely to use to use optional returns. Doing so (which produces a safer result) would cause a double tax in syntax, and would be a confusing jumble. I can’t bring myself to do the whole example above, one line - just converting member lookup syntax but not callable syntax - would end up:

  let y = np^.arange?^(24)^.reshape^?(2, 3, 4)

If you made DynamicCallable also return optional it would be:

  let y = np^.arange?^(24)?^.reshape^?(2, 3, 4)!

or something. This is such madness that no one would do that.

Yes, I agree. The interaction with optional chaining makes it unworkable. I hadn’t thought that all the way through. Thank you for indulging in the discussion about this idea.

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.

I think that making dynamic calls syntactically different to readers is going too far in the direction of safety. Plus, it makes the language inconsistent as we already have AnyObject dispatch with exactly the same syntax. But I understand why you would want it if *any* type could end up being conformed to a dynamic lookupable/callable protocol. Like said above, I think that a DynamicObject type is enough protection to not bother making the syntax heavier at the point of use.

One idea that hasn’t been explored yet is introducing a dynamic lookup effect. That would provide clean syntax at the expression level while still making it clear that dynamic lookup is happening. This probably isn’t the right approach as it would be viral and wouldn’t even indicate that the code in a specific function body even contains a dynamic lookup. I mention it mostly to broaden the conversation and thought space about what kind of approach might address my concerns without cluttering up expressions.

Another, potentially more viable approach would be to use an approach similar to try and the proposed async of a statement modifier (possibly also allowed at the expression level as with try and async). This could be used in conjunction with an effect as mentioned above but could also be used independently even though there isn’t a current precedent for that. Your example written with this approach might be:

  let np = Python.import("numpy")
  let b = dynamic np.array([6, 7, 8])
  let y = dynamic np.arange(24).reshape(2, 3, 4)
  
  let a = dynamic np.ones(3, dtype: np.int32)
  let b = dynamic np.linspace(0, pi, 3)
  let c = dynamic a + b
  let d = dynamic np.exp(c)

Note: `dynamic` is just a straw man here. This is obviously a lot of boilerplate repetition of the same modifier. I would also be perfectly happy allowing this annotation to apply to a block of code or even a whole function body. Then it might be:

dynamic {
  let np = Python.import("numpy")
  let b = np.array([6, 7, 8])
  let y = np.arange(24).reshape(2, 3, 4)
  
  let a = np.ones(3, dtype: np.int32)
  let b = np.linspace(0, pi, 3)
  let c = a + b
  let d = np.exp(c)
}

The most obvious objection to this is that it introduces nesting and does so in a way that only very indirectly influences control flow (through the potential for dynamic failure).

My objective certainly isn’t to make code ugly and obfuscate logic. It is simply to make the usage of dynamic features that are prone to failure at runtime immediately clear to a reader. This should be as lightweight as possible while still providing valuable information to the reader.

Swift already has a dynamic member lookup feature, "AnyObject dispatch" which does not use additional punctuation, so this would break precedent.

I would prefer if dynamic lookup were visible with AnyObject as well. For that reason I don’t believe it makes a good precedent to follow. In fact, I would prefer to see us go the other direction and perhaps even consider revising dynamic lookup syntax for AnyObject in the future.

This is definitely not going to happen. The change Doug mentioned is to have AnyObject lookup return optional instead of IUO, which forces ? on the clients. Adding other syntax (like you’re suggesting) is certainly not going to happen.

The entire point of AnyObject dispatch is to improve syntactic elegance and clarity of code using it. There is no other reason to exist. Making code that uses it syntactically onerous completely defeats the point of having it in the first place, as I’ve mentioned before.

I agree. The interaction with optional chaining is significantly more onerous than I had considered. I should have worked through an example on my own. I do hope you will consider a less localized approach to usage-site annotation though.

Furthermore, your premise that Swift does not have invisibly failable operations is plainly wrong. Array subscript and even integer addition can fail.

I am well aware of these behaviors. The difference IMO is that programmers tend to be well aware of these preconditions even if they also often choose to ignore them. Dynamic lookup will not be so clear. This is especially true if people use it with types that also have an API available through static lookup.

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.

-Chris

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

Until, and if, the “resistance” presents some conceptual explanation of

how this could cause harm (I’m not asking for anything concrete, just a
logical series of events that causes a plausible problem in practice), my
belief is that the Swift community will see this as unwarranted fear.

On the server side :
automatically generate an administration api for your model based on
introspection. Since swift doesn't provide anything convenient, and people
may simply try to "port" approach from python framework (like django),
they'll resort on recreating some kind of BaseDynamicObject that you'll
have to extend for all your base classe, using some "properties()" and
"methods()" functions to define your properties and methods for your model.

Or :
Automatically generate a database schema based on your model. Same idea.

The explicit harm that Chris is looking for is yet to be shown.

The harm isn't in generating the database schema, or the administration
api. it's in abandonning all kind of compile-time safety in your model
layer (and such by extension in almost every part of your stack) in order
to accomplish this. Dynamic language obviously don't have this concern, but
thankfully Swift isn't a dynamic language.

You should not assume that everybody feels an horror thrill by reading
such applications of dynamism. As a matter of fact, users of dynamic
languages *live* and *enjoy* this. Python and Ruby users, obviously (Rails
+ Django), but also ours close cousins, the Objective-C developers, who
rely on Key-Value coding or validation methods. Those use cases are, I'm
sorry to say it, *compelling* use cases for dynamism.

Not sure what field you're working in, but at least on the server the
general trend toward more compile-time safety has been pretty obvious for
some time now.

Ironically, "Explicit is better than implicit" is a... Python motto ;-)

It's also a community that used to rely on writing types annotation and
signatures in comments above functions as a best practice, before
annotations became a thing. Not sure we should take it as an example.

···

On Thu, Dec 7, 2017 at 1:45 PM, Gwendal Roué <gwendal.roue@gmail.com> wrote:

Le 7 déc. 2017 à 11:00, Benjamin G via swift-evolution < > swift-evolution@swift.org> a écrit :

Gwendal

Great post Paul. Similarly, look at the early days of Swift, where many ObjC programmers used IOUs for everything.

Bad code gets written all the time, this is unavoidable. This feature will not affect or measurably change that.

-Chris

···

On Dec 7, 2017, at 2:07 PM, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 7, 2017, at 12:37 AM, Letanyan Arumugam <letanyan.a@gmail.com> wrote:

My main objection to the critical responses is that most of the objections are fundamentally cultural, not technical, and are fear-based, not evidence-based.

The goal of this proposal is to bring people from a culture where excessive use of this would be the norm for them. Why would it be so hard to imagine that people would adopt bad principles, knowing or unknowing, because this is what they’ve always done?

Languages bring in new developers who misapply their experience all the time. Look at the early days of Ruby when it was actively working to pull new developers away from Java, developers who were in the habit of using names like AbstractItemManagerFactoryImpl. Look at beginner Swift code posted in Stack Overflow questions, littered with careless force unwraps that are clearly there because that’s the fixit and sort of smells like C or Java, not because they actually thought about what they were doing.

I’m talking specifically about fatalError not precondition. fatalError is something that goes out with production code while precondition is used for debugging. I think you would agree a shipped program that has many states of being unrecoverable is not a good design?

···

On 07 Dec 2017, at 17:02, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Thu, Dec 7, 2017 at 00:37 Letanyan Arumugam via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This seems marginally tolerable, but excessive.

Do we mark every usage of a type that can generate precondition failures or fatal errors for reasons other than “no such method?” No, we don’t.

fatalError shouldn’t be used excessively. API surface areas for these types are going to be massive (infinite technically). I assume many people are going to be writing a lot of code would these types and calling many methods and properties which would all essentially have a fatalError. Would you consider it good code if the majority of all your types had methods defined with fatalError calls.

What is the basis for this claim? Probably the majority of standard library methods check preconditions and trap on failure. That is how I write my code as well.

Okay I’ll concede and hope that a sub community, who are forced to use Swift because of the success of this proposal and others to follow, doesn’t form creating their own separate design patterns and beliefs :)

···

On 08 Dec 2017, at 00:06, Paul Cantrell <cantrell@pobox.com> wrote:

On Dec 7, 2017, at 12:37 AM, Letanyan Arumugam <letanyan.a@gmail.com> wrote:

My main objection to the critical responses is that most of the objections are fundamentally cultural, not technical, and are fear-based, not evidence-based.

The goal of this proposal is to bring people from a culture where excessive use of this would be the norm for them. Why would it be so hard to imagine that people would adopt bad principles, knowing or unknowing, because this is what they’ve always done?

Languages bring in new developers who misapply their experience all the time. Look at the early days of Ruby when it was actively working to pull new developers away from Java, developers who were in the habit of using names like AbstractItemManagerFactoryImpl. Look at beginner Swift code posted in Stack Overflow questions, littered with careless force unwraps that are clearly there because that’s the fixit and sort of smells like C or Java, not because they actually thought about what they were doing.

Note in both cases how the center of gravity of the language did •not• move. Note how poorly designed libraries that didn’t fit the language did •not• see adoption. Note how the core community acted as good teachers to the newcomers.

My fear is that a design pattern around dynamic members and calls arise that is used to bypass the perceived initial annoyance of Swifts type system from new developers that come over to Swift and are now starting to try and go native.

That contradicts the historical experience of other languages that have seen “crossover” adoption from developers bringing very different mental models with them.

A Swift library released today that senselessly used dynamic member lookup without good engineering reason would go over just about as well as an AbstractItemManagerFactoryImpl would have gone over with the Ruby community in 2007.

Again, a language feature alone will not erase the good sense of the language’s stewards, or poison its community.

People come to Swift to write Swift. People trying to write Python or Ruby or C in Swift will feel the friction, learn from that, adjust their habits taking a cue from the code they find in the surrounding ecosystem, and learn to think “Swiftly.” This has been the case in every language before Swift; it will not stop being the case now.

Joe hit this nail on the head:

On Dec 7, 2017, at 10:08 AM, Joe DeCapo via swift-evolution <swift-evolution@swift.org> wrote:

When I began writing Python, I initially named all my variables in camel case. And when I used the Subprocess module, I was passing return codes throughout my code base like it was bash. Even though I didn't know what was idiomatic in Python at that time, I could still sense a code smell in what I was writing. I soon learned that snake case was the standard, so I updated my code. And eventually I learned how to use exceptions and I refactored my code to use them instead of return codes. I doubt that this is unusual when coming to a new language with previous experience in other languages. It seems inevitable, and a normal process for becoming familiar with the idioms of a certain language community. I don't think we need to be so fearful of the community fracturing if people from a dynamic language background come to Swift and initially use those idioms. It will always be more burdensome to do things in a non-idiomatic way, and over time people will learn how to write idiomatic Swift.

Exactly.

On Dec 7, 2017, at 12:37 AM, Letanyan Arumugam <letanyan.a@gmail.com> wrote:

Evidence is going to be hard to get since I don’t know any other language like Swift that has done this for the same reasons before. As far as C# goes were they trying to get people from a heavily based dynamic community or help those already in the community?

If a little extra language ceremony helps assuage those fears, I guess I’d consider it. I still think static analysis — starting and mostly ending with boring old syntax coloring — answers most all the concerns people have raised, and this debate is a tempest in a teapot.

I'm unsure of this, but as far as I’m aware Swift language proposals shouldn’t rely on editor features. But like I said I’m unsure of this and if someone could clarify this that would great.

Type inference effectively does, to at least the same degree as this proposal. See my previous post reflecting on why Java chose not to have any sort of type inference:

[swift-evolution] Proposal: Introduce User-defined "Dynamic Member Lookup" Types

• • •

It’s wise to remember Flon’s Law:

“There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code.”

We should design languages to make writing excellent code as pleasant and rewarding as possible. Or more accurately, we should design them so that there exists a way of writing excellent code that is pleasingly well suited to the language and the ecosystem that surrounds it.

Designing languages instead to forcibly prevent or punish bad programming is not merely futile, but in fact actively thwarts that first goal.

Now, how can we use dynamic member lookup in Swift to make its way of writing excellent code more excellent still?

Cheers,

Paul

Matthew was primarily concerned about point of use, in which IUO dereferencing is completely implicit and invisible.

-Chris

···

On Dec 3, 2017, at 10:54 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

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.

The difference is that IUOs are marked by a "!“ whereas dynamic member lookups look just like normal member lookups but unlike them can fail.

We don't even need to bring up IUOs for it to be possible to write code that can fail without visibility at the call site. A contrived example:

func convertToInt(_ val: String) -> Int {
    return Int(val)!
}

let val = "something"
// ... a bunch of code
let i = convertToInt(val) // Fatal error: Unexpectedly found nil while unwrapping an Optional value

This is trivially easy to do, and has been since Swift 1, but it's not something that has become a widespread issue.

···

On Dec 3, 2017, at 12:54 PM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

The difference is that IUOs are marked by a "!“ whereas dynamic member lookups look just like normal member lookups but unlike them can fail.

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.

If that's the concern, then it would be pretty straightforward to restrict
dynamic protocols for stdlib internal use only and expose only PyVal. The
trade-off is that all such bridging code would have to be shipped with
Swift itself.

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.

I imagine we could restrict all such dynamic types from having any
statically available members without losing much.

···

On Sun, Dec 3, 2017 at 2:16 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

On Dec 3, 2017, at 11:36 AM, Chris Lattner <clattner@nondot.org> wrote:
On Dec 2, 2017, at 7:11 PM, Matthew Johnson <matthew@anandabits.com> > wrote:

IUOs are not marked with an "!" by the caller, that's what makes them implicit. They *are* marked at the declaration, but so would dynamic member lookups be.

/Magnus

···

4 Dec. 2017 03:54 Thorsten Seitz via swift-evolution <swift-evolution@swift.org> wrote:

The difference is that IUOs are marked by a "!“ whereas dynamic member lookups look just like normal member lookups but unlike them can fail.

I really don't understand this fear of metamorphosis. People could also be
using emoji for all their variables. So what? Let them do it!

Are you afraid that this kind of code will eventually become idomatic Swift
and soon all the good 3rd party libraries will be written like this? If
yes, that means that Swift has failed as a language, people really wanted
another Javascript. If not, what's the harm? Maybe eventually people doing
this will realize that "proper" Swift is better. Or not.

Right now there are a lot of people writting Swift in an Objective-C style.
e.g. using classes when they should have used structs, using inheritance
when they should have used protocols. Should we add some language feature
to stop them?

···

On Sun, Dec 3, 2017 at 10:16 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

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.

Let's see what disasters were created by people abusing NSProxy, the ObjC moral equivalent of a dynamic member lookup type.

I'm not aware of anything.

···

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Dec 7, 2017, at 7:15 AM, Letanyan Arumugam via swift-evolution <swift-evolution@swift.org> wrote:

On 07 Dec 2017, at 17:02, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Thu, Dec 7, 2017 at 00:37 Letanyan Arumugam via swift-evolution <swift-evolution@swift.org> wrote:

This seems marginally tolerable, but excessive.

Do we mark every usage of a type that can generate precondition failures or fatal errors for reasons other than “no such method?” No, we don’t.

fatalError shouldn’t be used excessively. API surface areas for these types are going to be massive (infinite technically). I assume many people are going to be writing a lot of code would these types and calling many methods and properties which would all essentially have a fatalError. Would you consider it good code if the majority of all your types had methods defined with fatalError calls.

What is the basis for this claim? Probably the majority of standard library methods check preconditions and trap on failure. That is how I write my code as well.

I’m talking specifically about fatalError not precondition. fatalError is something that goes out with production code while precondition is used for debugging. I think you would agree a shipped program that has many states of being unrecoverable is not a good design?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

RPC predates NSProxy. The "type-safe" version of RPC was CORBA: anybody here use that?

Then there was XML-RPC and then SOAP.

The most popular version of RPC is HTTP + JSON, because http isn't blocked at network boundaries and because JSON was friendly to JavaScript in the browser.

So... Typesafe lost, stringly-typed won.

···

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Dec 7, 2017, at 7:39 AM, Gwendal Roué <gwendal.roue@gmail.com> wrote:

Le 7 déc. 2017 à 16:33, C. Keith Ray via swift-evolution <swift-evolution@swift.org> a écrit :

Let's see what disasters were created by people abusing NSProxy, the ObjC moral equivalent of a dynamic member lookup type.

I'm not aware of anything.

I'm sure you are ;-)

I'm not expert at all of early ObjC... But wasn't NSProxy the base of good-old-times RPC?

OK, in 2017 we know that RPC is dangerous. For example, when `() -> Int` relies on a network call, it's almost impossible to handle errors.

But still, is it because an API can be used for bad things that an API is bad?

Gwendal

You are aware that Int traps on overflow and arrays trap on out of bounds, right?

-Chris

···

On Dec 7, 2017, at 7:15 AM, Letanyan Arumugam via swift-evolution <swift-evolution@swift.org> wrote:

On 07 Dec 2017, at 17:02, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

On Thu, Dec 7, 2017 at 00:37 Letanyan Arumugam via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This seems marginally tolerable, but excessive.

Do we mark every usage of a type that can generate precondition failures or fatal errors for reasons other than “no such method?” No, we don’t.

fatalError shouldn’t be used excessively. API surface areas for these types are going to be massive (infinite technically). I assume many people are going to be writing a lot of code would these types and calling many methods and properties which would all essentially have a fatalError. Would you consider it good code if the majority of all your types had methods defined with fatalError calls.

What is the basis for this claim? Probably the majority of standard library methods check preconditions and trap on failure. That is how I write my code as well.

I’m talking specifically about fatalError not precondition. fatalError is something that goes out with production code while precondition is used for debugging. I think you would agree a shipped program that has many states of being unrecoverable is not a good design?

Until, and if, the “resistance” presents some conceptual explanation of how this could cause harm (I’m not asking for anything concrete, just a logical series of events that causes a plausible problem in practice), my belief is that the Swift community will see this as unwarranted fear.

On the server side :
automatically generate an administration api for your model based on introspection. Since swift doesn't provide anything convenient, and people may simply try to "port" approach from python framework (like django), they'll resort on recreating some kind of BaseDynamicObject that you'll have to extend for all your base classe, using some "properties()" and "methods()" functions to define your properties and methods for your model.

Or :
Automatically generate a database schema based on your model. Same idea.

The explicit harm that Chris is looking for is yet to be shown.

The harm isn't in generating the database schema, or the administration api. it's in abandonning all kind of compile-time safety in your model layer (and such by extension in almost every part of your stack) in order to accomplish this. Dynamic language obviously don't have this concern, but thankfully Swift isn't a dynamic language.

Yes, yes, but this has been said dozens of time already in this thread. Chris's question is *how*, not *what*. It's much harder to answer, I agree.

You should not assume that everybody feels an horror thrill by reading such applications of dynamism. As a matter of fact, users of dynamic languages *live* and *enjoy* this. Python and Ruby users, obviously (Rails + Django), but also ours close cousins, the Objective-C developers, who rely on Key-Value coding or validation methods. Those use cases are, I'm sorry to say it, *compelling* use cases for dynamism.

Not sure what field you're working in, but at least on the server the general trend toward more compile-time safety has been pretty obvious for some time now.

I'm not sure you really care about my answer.

Gwendal

···

Le 7 déc. 2017 à 13:59, Benjamin G <benjamin.garrigues@gmail.com> a écrit :
On Thu, Dec 7, 2017 at 1:45 PM, Gwendal Roué <gwendal.roue@gmail.com <mailto:gwendal.roue@gmail.com>> wrote:

Le 7 déc. 2017 à 11:00, Benjamin G via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

This seems marginally tolerable, but excessive.

Do we mark every usage of a type that can generate precondition failures
or fatal errors for reasons other than “no such method?” No, we don’t.

fatalError shouldn’t be used excessively. API surface areas for these
types are going to be massive (infinite technically). I assume many people
are going to be writing a lot of code would these types and calling many
methods and properties which would all essentially have a fatalError. Would
you consider it good code if the majority of all your types had methods
defined with fatalError calls.

What is the basis for this claim? Probably the majority of standard
library methods check preconditions and trap on failure. That is how I
write my code as well.

I’m talking specifically about fatalError not precondition. fatalError is
something that goes out with production code while precondition is used for
debugging. I think you would agree a shipped program that has many states
of being unrecoverable is not a good design?

Precondition checks are active in release code. When a program encounters
conditions that have no obvious recovery, trapping immediately is the only
safe option; this is what Swift means by “safety” and the practice is
encouraged.

···

On Thu, Dec 7, 2017 at 09:15 Letanyan Arumugam <letanyan.a@gmail.com> wrote:

On 07 Dec 2017, at 17:02, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:
On Thu, Dec 7, 2017 at 00:37 Letanyan Arumugam via swift-evolution < > swift-evolution@swift.org> wrote:

Well, mocking was effective and super easy to do proper unit testing with... that must count as a disaster or something ;).

···

Sent from my iPhone

On 7 Dec 2017, at 15:32, C. Keith Ray via swift-evolution <swift-evolution@swift.org> wrote:

Let's see what disasters were created by people abusing NSProxy, the ObjC moral equivalent of a dynamic member lookup type.

I'm not aware of anything.

--
C. Keith Ray

* https://leanpub.com/wepntk <- buy my book?
* http://www.thirdfoundationsw.com/keith_ray_resume_2014_long.pdf
* http://agilesolutionspace.blogspot.com/

On Dec 7, 2017, at 7:15 AM, Letanyan Arumugam via swift-evolution <swift-evolution@swift.org> wrote:

On 07 Dec 2017, at 17:02, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Thu, Dec 7, 2017 at 00:37 Letanyan Arumugam via swift-evolution <swift-evolution@swift.org> wrote:

This seems marginally tolerable, but excessive.

Do we mark every usage of a type that can generate precondition failures or fatal errors for reasons other than “no such method?” No, we don’t.

fatalError shouldn’t be used excessively. API surface areas for these types are going to be massive (infinite technically). I assume many people are going to be writing a lot of code would these types and calling many methods and properties which would all essentially have a fatalError. Would you consider it good code if the majority of all your types had methods defined with fatalError calls.

What is the basis for this claim? Probably the majority of standard library methods check preconditions and trap on failure. That is how I write my code as well.

I’m talking specifically about fatalError not precondition. fatalError is something that goes out with production code while precondition is used for debugging. I think you would agree a shipped program that has many states of being unrecoverable is not a good design?
_______________________________________________
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

When a question is framed so that there is only one possible answer, the question is flawed.

The question is not whether one likes dynamism or not (the answer is pretty obvious for many people here, and we don't learn much).

It isn't if one would use the discussed features if the proposals were accepted (many here would swear they wouldn't, even if many of them will lick those dynamic features like candy, whenever appropriate, as every sane person would).

Currently, it's a static vs. dynamic debate. But we should talk about a precise proposal, and a good one after that, which comes with plenty of information, and even playgrounds to look at!

Gwendal

···

Le 7 déc. 2017 à 16:15, Letanyan Arumugam via swift-evolution <swift-evolution@swift.org> a écrit :

On 07 Dec 2017, at 17:02, Xiaodi Wu <xiaodi.wu@gmail.com <mailto:xiaodi.wu@gmail.com>> wrote:

On Thu, Dec 7, 2017 at 00:37 Letanyan Arumugam via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This seems marginally tolerable, but excessive.

Do we mark every usage of a type that can generate precondition failures or fatal errors for reasons other than “no such method?” No, we don’t.

fatalError shouldn’t be used excessively. API surface areas for these types are going to be massive (infinite technically). I assume many people are going to be writing a lot of code would these types and calling many methods and properties which would all essentially have a fatalError. Would you consider it good code if the majority of all your types had methods defined with fatalError calls.

What is the basis for this claim? Probably the majority of standard library methods check preconditions and trap on failure. That is how I write my code as well.

I’m talking specifically about fatalError not precondition. fatalError is something that goes out with production code while precondition is used for debugging. I think you would agree a shipped program that has many states of being unrecoverable is not a good design?