> Am 09.06.2016 um 19:24 schrieb Austin Zheng via swift-evolution 
> <[email protected]>:
> 
> On Thu, Jun 9, 2016 at 9:42 AM, Dave Abrahams via swift-evolution 
> <[email protected] <mailto:[email protected]>> wrote:
> 
> on Thu Jun 09 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote: 
> >
> >>
> >>> Introducing a language (not library) mechanism that exposes members on
> >>> generalized existentials in a way that relies on runtime traps for
> >>> type safety feels to me like a pretty dramatic turn agains the stated
> >>> priority of safety.  It will mean you must understand exactly what is
> >>> going on and be extremely careful to use generalized existentials
> >>> without causing crashes.  This will either make Swift code much more
> >>> crashy or will scare people away from using generalized existentials
> >>> (and maybe both).
> >>
> >> I don't accept either of those statements without seeing some analysis
> >> of the use-cases.  For example, I don't believe that AnyCollection et al
> >> are particularly crash-prone.  The likelihood that you'll use the wrong
> >> index type with a collection is very, very low.  I'm less certain of
> >> what happens with Self requirements in real cases.
> >
> > But again, I believe this is an exceptional case as the precondition
> > is explicitly stated in the semantics of the protocol.
> 
> IIUC, it has been cited by Doug as the exemplar of the
> predominantly-requested case by a 10:1 ratio!
> 
> At the risk of sounding waffly, I see both sides of the argument.
> 
> Java is typesafe in the formal sense (can't perform an operation on a type 
> that doesn't actually support it); almost certainly moreso than Swift (which 
> lets you do wonderful things like reinterpret casting, C-style direct memory 
> manipulation...).
> 
> However, in many cases Swift provides better compile-time assurances than 
> Java. In Java, any reference might actually be a null reference waiting to 
> cause a NullPointerException unless you explicitly check it in code (and what 
> if you forget to check it somewhere?). In Swift, (aside from IUOs and a few 
> other features) if your program compiles successfully the type checker has 
> proven that your software will never try calling a method upon nil. And if 
> you do use IUOs the postfix exclamation marks clearly mark spots in your code 
> that might cause trouble.
> 
> In the same way I don't think trapping at runtime if an existential 
> satisfying a generic type parameter causes a type error is the best solution 
> to this problem. What we are doing is allowing a type that makes a weak 
> guarantee to stand in for a type that makes a strong guarantee, and catching 
> mismatches between those guarantees if/when they pop up. There's no easy way 
> for someone perusing the code to tell that such a mismatch might occur, 
> equivalent to IUO's postfix !.
> 
> What I prefer is to explicitly "promote" the type with the weak guarantee to 
> a type with the stronger guarantee using the existential opening mechanism 
> that we've been throwing around. That way, it's very clear what is going on: 
> if the existentials in question can't serve as generic parameters to the 
> function you want to pass them to, you can fatalError() or do something else. 
> Or you can try force-opening with `as!` and mark a potential trouble spot in 
> the same way an IUO does. Once it succeeds you know you have the strong 
> guarantees that will cause your generic member to alway work the way it 
> should.

Yes, there should never be crashes for calling a wrong method. That is what 
*type* safety means.
You still can have crashes when calling a method with wrong arguments. To make 
that type safe you would need a type system with dependent typing.

I think that Swift should not only always be safe but that it should always be 
type safe, too.

-Thorsten


> 
> With the proposed mechanism, I expect that Any<Collection where .Element == 
> T> should be less prone to runtime trapping than AnyCollection<T>, because we 
> can reify the concept that each instance of the existential has a concrete 
> Index type associated with it, rather than relying upon a type-erased 
> AnyIndex shared among all AnyCollections. (That being said, I don't know if 
> AnyCollection is particularly problematic in practical use. I also don't know 
> if other type-erased wrappers users might define might be more or less prone 
> to this type of issue.)
> 
> 
> > IMO the burden of proof should be on the side that proposes a
> > mechanism to introduce traps, not the side that proposes avoiding
> > them.
> 
> If you really want to make this about sides and burdens, the burden of
> proof always rests with the side proposing to extend the language.  We
> shouldn't be making changes without understanding how they will play out
> in real use-cases.
> 
> 
> Yes, I really want to see real-world use cases.
>  
> >>
> >> Neither of these look like they actually make *use* of the fact that
> >> there's type erasure involved (and therefore should probably be written
> >> as generics?).  The interesting cases with Any<Collection...>, for the
> >> purposes of this discussion, arise when you have multiple instances of
> >> the same existential type that wrap different concrete types.
> >
> > One use case I have found is to work around the lack of higher-kinder
> > types.
> 
> Really, now: a use-case for feature A that is a workaround for the lack
> of feature B hardly justifies adding feature A!  We do want to add
> higher-kinded types eventually.
> 
> I just want to say, this made my day.
> 
> Most of the examples in the document Matthew linked were meant to be 
> didactic, not practical. I would love to swap them out for more useful ones. 
> 
> 
> >>
> >> Another problem I see: in this new world, what is the model for choosing
> >> whether to write a function as a protocol extension/generic, or as a
> >> regular function taking existential parameters?  Given that either of
> >> the above could have been written either way, we need to be able to
> >> answer that question.  When existentials don't conform to their
> >> protocols, it seems to me that the most general thing to do is use
> >> existentials whenever you can, and only resort to using generics when
> >> forced by the type system.  This does not seem like a particularly good
> >> programming model to me, but I might be convinced otherwise.
> >
> > That doesn’t seem like a particularly good programming model to me either.
> >
> > The rule of thumb I am operating with for protocols with Self or
> > associated type requirements is to prefer generics and use type
> > erasure / existentials when that isn’t possible.  For example, when
> > heterogeneity is required or when you can’t form the necessary type in
> > a protocol requirement (as in the preceding example).
> >
> > This heuristic has been working out pretty well for me thus far.
> 
> I do worry a bit that people will choose the opposite heuristic.
> 
> If we are to introduce this feature, I expect that the community would go 
> through another "reference vs value types - which is right for you?" type 
> discussion. It's true you can model a lot of things with classes where 
> structs would be more appropriate, but this doesn't seem to be a big issue.
> 
> I would be very interested in affordances that can steer people towards using 
> generics when the dynamic nature of existentials isn't necessary.
>  
> 
> 
> ______________________________________
> swift-evolution mailing list
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to