[swift-evolution] [Proposal] Explicit Synthetic Behaviour

Vladimir.S svabox at gmail.com
Tue Sep 12 12:02:57 CDT 2017


On 12.09.2017 18:09, Tony Allevato wrote:
> 
> 
> On Tue, Sep 12, 2017 at 3:32 AM Vladimir.S <svabox at gmail.com 
> <mailto:svabox at gmail.com>> wrote:
> 
>     On 12.09.2017 0:35, Tony Allevato wrote:
>      >
>      >
>      > On Mon, Sep 11, 2017 at 2:05 PM Vladimir.S via swift-evolution
>      > <swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>> wrote:
>      >
>      >     On 11.09.2017 21:55, Thorsten Seitz via swift-evolution wrote:
>      >      > I think I do understand Haravikk's argument (actually it seems quite
>      >     straightforward
>      >      > to me).
>      >      >
>      >      > An example should be:
>      >      >
>      >      > struct Foo : Equatable {
>      >      >      var x: Int
>      >      >      var cachedLabel: String? = nil
>      >      >
>      >      >      init(x: Int) {
>      >      >          self.x = x
>      >      >      }
>      >      >
>      >      >      mutating func label() {
>      >      >          if let label = cachedLabel {
>      >      >              return label
>      >      >          }
>      >      >          let label = calculateLabel()
>      >      >          cachedLabel = label
>      >      >          return cachedLabel
>      >      >      }
>      >      > }
>      >      >
>      >      > var foo1 = Foo(x: 1)
>      >      > var foo2 = Foo(x: 1)
>      >      > foo1 == foo2 // true
>      >      > var label = foo1.label()
>      >      > foo1 == foo2 // now false, due to cachedString being falsely included
>     in the
>      >     comparison
>      >      >
>      >      > The problem is that the developer was not required to implement the
>     protocol
>      >     and so
>      >      > might forget it.
>      >      > The difference to other default implementations is that those use the
>     protocol
>      >     itself
>      >      > as building blocks and so are correct with regards to the protocol's
>     semantics,
>      >      > whereas the synthesized equality reaches deeply into the private
>     innards of a
>      >     struct
>      >      > and therefore is much more likely to be wrong as in the example above.
>      >      >
>      >      > Why not just write
>      >      >
>      >      > *struct* Foo : *deriving* Equatable {...}
>      >      >
>      >      > to request the synthesized implementation?
>      >
>      >     FWIW, +100. The same should be required for Codable. I support the opinion
>     that
>      >     'synthesized' methods differs from protocol-default-implementation in what
>     'kind' of
>      >     data they use: defined by protocol itself or internals of the conformed
>     type. And
>      >     this can lead to more un-expected problems.
>      >
>      >     If protocol is able to synthesize its requirements, it should require a
>      >     'deriving'-like marker when type conforms to it to make it absolutely
>     clear what
>      >     happens here. It would be not a confusion point, but clarify the intention
>     to better
>      >     understand the code.
>      >
>      >     Thinking about *future* custom protocols that could implement requirements
>     in default
>      >     implementation by using macros/reflection, for me it seems like such
>     protocol should
>      >     *also* somehow explicitly state that some requirements are
>     auto-synthesized, probably
>      >     by conforming(derive) to some compiler-magic protocol 'AutoSynthesize'.
>      >     (i.e. 'protocol MySynthesizeable: AutoSynthesize {...}')
>      >
>      >     So each built-in protocol like Equatable/Hashable/Codable will conform to
>     it, and
>      >     also, each custom "auto-synthesizeable" protocol - also should explicitly
>     conform to
>      >     AutoSynthesize. So, when type conforms to it - such type should use
>     'deriving'-like
>      >     marker if auto-generation of methods is expected.
>      >
>      >
>      > This doesn't align with how Swift views the role of protocols, though. One of the
>      > criteria that the core team has said they look for in a protocol is "what generic
>      > algorithms would be written using this protocol?" AutoSynthesize doesn't satisfy
>      > that—there are no generic algorithms that you would write with AutoEquatable that
>      > differ from what you would write with Equatable.
>      >
> 
>     OK, got it, it was general thoughts, not exact proposal regarding the AutoSynthesize
>     protocol. Probably it should be @autosynthesize directive for protocol when you
>     define it or other 'marker', so when you conform to this protocol, you *can*
>     explicitely use 'derived'-like keyword to make requirements auto-synthesized,
>     otherwise you'll be asked by compiler for manual implementation.
> 
> 
>      >     I also have a question regarding future direction of 'exclusion' of fields
>     from being
>      >     included into auto-generated implementation of
>     Equatable/Hashable/Codable/other.
>      >
>      >     If we'll have this 'deriving'-like marker, it seems naturally if we mark
>     some member
>      >     with some kind of '@noderiving' marker, like here:
>      >
>      >     struct Foo : deriving Equatable {
>      >             var x: Int
>      >             var y: Int
>      >             var z: Int
>      >             @noderiving var cachedLabel: String? = nil
>      >     }
>      >
>      >     this @noderiving directive will work for protocols based on AutoSynthesize
>     magic
>      >     protocol. I.e., if you construct your own protocol with
>     auto-synthesizeable methods,
>      >     to be able to *know* which members should be 'excluded' for your
>     implementation, you
>      >     should base your protocol on AutoSynthesize protocol.
>      >
>      >
>      > This is something I mention in the original proposal, and I agree that it would be
>      > nice to have added later since there are clear known use cases where it's
>     important.
>      >
>      > However, the feature shouldn't be tied *specifically* to derived implementations
>      > (meaning it shouldn't be named that way). What we're really talking about is
>      > "transient" data—data that exists for the purposes of caching/performance/etc. but
>      > which does not actually contribute to the thing's "value".
>      >
>      > The fact that transient data should not be ignored for equality, hashing, and
>      > serialization just happens to align with the protocols that we auto-synthesize so
>      > far, but it's not necessarily limited to those use cases. If an attribute is added
>      > for something like this, it should be *semantic* rather than speak to
>     implementation
>      > details. In other words, it would be inappropriate to say "exclude this
>     property from
>      > synthesized operations", but it would be fine to say "this property is transient
>      > data" and it just so happens that Equatable, Hashable, and Codable use that
>      > information to control what they synthesize.
>      >
>      > All this is a subtle, but important, distinction. One day, when Swift has the
>     ability
>      > to introspect metadata about a type and its properties, someone may want to use a
>      > hypothetical "transient" attribute for something wholly unrelated to synthesis.
> 
>     I see your points, but is it not possible that we want to exclude some property for
>     Equatable but keep it for Codable, or vise-versa, for example? So, actually, IMO we
>     need a way to exclude property from some specific protocol/protocols. Like
> 
>     @transient var ...
>     @transient(for:Equatable) var ...
>     @transient(for:Codable) var ...
>     @transient(for:SomeOtherAuto) var ...
> 
>     And again, I'm not proposing some concrete syntax/keyword, but think we'll need(in
>     future,yes, but IMO better to discuss now) a way to 'exclude' specific property from
>     specific auto-synthesizeable protocol.
> 
> 
> It's possible, but we shouldn't think of it in terms of "exclude from a protocol". 
> There are some different combinations to consider here:
> 
> * Does it make sense to use a property in a synthesized Hashable but not in the 
> synthesized Equatable? No, because of the contract between those two protocols. Such 
> an exclusion would allow two equal values to hash to different values.
> 
> * Does it make sense to use a property in a synthesized Equatable but not in the 
> synthesized Hashable? Sure; if your data type is large you may only want to hash a 
> subset of its properties. If that's the case, your hash function is probably simple 
> enough that you can just override the property manually, which is more scalable than 
> tagging all the non-hash properties individually.
> 
> * Does it make sense to exclude a property used by synthesized Equatable/Hashable 
> from synthesized Codable? Sure, maybe. If the property is truly transient cached data 
> then it can easily be recomputed on demand, but you could argue that it's worth 
> serializing if doing so is more efficient than performing the computation again.
> 
> The key thing to note here is that "transient" shouldn't mean "exclude from 
> implementations". "Transient", at least as I'm describing it, means "data 
> that does not strictly contribute to something's notion of its 'value'". That's a 
> semantic definition and it's up to the protocols themselves to decide how to 
> interpret it. If there were a need for different "levels" of transience, then the 
> attribute could be extended with more semantic information that lets the protocol 
> decide what to do, or a new attribute could be introduced. The important thing is 
> that you're saying "what does this property mean and how does it behave", not "which 
> specific protocols can or can't do something with this property".
> 
> Regarding "what about some future protocol", we can't really consider those 
> realistically if we don't know what the semantics of that protocol are.

Well, seems like I'm missing something and just can't get it.
Currently, as I understand, we already have(see your reasoning above) two 'groups' of 
protocols(Equatable/Hashable vs Codable) and so will need two kinds of 'transient' 
directive. No?
And then, in _future_,
A) we can(who knows) have more built-in protocols that can auto-synthesize requirements
B) if some custom protocol can auto-synthesize requirements via macros system(for 
example), it is logically that such protocol should be able to have a knowledge what 
fields should be excluded.
Sorry, I still use 'excluded' as I don't understand(don't believe?) the idea of 
"you're saying "what does this property mean and how does it behave".

Also, please consider this code:

struct S: Equatable, Codable
{
   var x = 0
   var y = 0
   @transient var z = 0

   ...
   // a number of lines here.
}

and this:

struct S: deriving Equatable, Codable
{
   var x = 0
   var y = 0
   @transient var z = 0

   ...
   // a number of lines here.
}

In second case it is clear that requirements for Equatable will be generated, and z 
will not participate in it, but Codable is implemented in code manually and we don't 
know if z will participate there.
In second case we have a much clear code that saying more than first case. This is 
what I really like about the 'deriving'-like marker.

Vladimir.

> 
> 
>     Just my 2 cents why I believe we need an explicit 'derived'-like keyword when we want
>     auto-synthesized requirement for protocol:
> 
>     * This will not change the logic/behavior of 'normal' conformance to
>     Equatable/Hashable, i.e. if you conform the type to them - you need to provide an
>     implementation OR (new text in warning message will be added) "use 'derived' keyword
>     to "auto-synthesize" these methods.
>     I.e. auto-synthesize will be something separate, additional, that you can use if you
>     want it, your clear choose.
>     It will not interfere with your 'usual' model of protocol conformance.
> 
>     * You explicitly mark which protocol you want to be synthesized for you. For example,
>     if I see "struct S: derived Equatable, Codable" - I understand that Equatable will be
>     "generated" and Codable will be implemented manually in code.
> 
>     * This makes code more clean, more understandable by reader, less error-prone, more
>     explicit on intention. The code *will* be better.
> 
>     * Without explicit 'derived'-like keyword, the code will be worse : less explicit
>     about intention, more error-prone, hiding important details from reader, etc.
> 
>     * And the 'derived'-like keyword is good price to have better code in this case.
> 
>     Just my IMOs. Thank you for reading.
> 
>     Vladimir.
> 
>      >
>      >
>      >     I hope this makes any sense :-)
>      >
>      >     Vladimir.
>      >
>      >      >
>      >      > -Thorsten
>      >      >
>      >      >
>      >      > Am 09.09.2017 um 19:42 schrieb Xiaodi Wu via swift-evolution
>      >      > <swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>      >     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>>>:
>      >      >
>      >      >>
>      >      >> On Sat, Sep 9, 2017 at 06:41 Haravikk via swift-evolution
>      >      >> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>      >     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>>> wrote:
>      >      >>
>      >      >>>     On 9 Sep 2017, at 09:33, Xiaodi Wu <xiaodi.wu at gmail.com
>     <mailto:xiaodi.wu at gmail.com>
>      >     <mailto:xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>>
>      >      >>>     <mailto:xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>
>     <mailto:xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>>>> wrote:
>      >      >>>
>      >      >>>
>      >      >>>     On Sat, Sep 9, 2017 at 02:47 Haravikk via swift-evolution
>      >      >>>     <swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>      >     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>>> wrote:
>      >      >>>
>      >      >>>
>      >      >>>>         On 9 Sep 2017, at 02:02, Xiaodi Wu <xiaodi.wu at gmail.com
>     <mailto:xiaodi.wu at gmail.com>
>      >     <mailto:xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>>
>      >      >>>>         <mailto:xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>
>     <mailto:xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>>>> wrote:
>      >      >>>>
>      >      >>>>         On Fri, Sep 8, 2017 at 4:00 PM, Itai Ferber via
>      >      >>>>         swift-evolution<swift-evolution at swift.org
>     <mailto:swift-evolution at swift.org>
>      >     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>      >      >>>>         <mailto:swift-evolution at swift.org
>     <mailto:swift-evolution at swift.org>
>      >     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>>>wrote:
>      >      >>>>
>      >      >>>>
>      >      >>>>
>      >      >>>>>             On Sep 8, 2017, at 12:46 AM, Haravikk via swift-evolution
>      >      >>>>>             <swift-evolution at swift.org
>     <mailto:swift-evolution at swift.org> <mailto:swift-evolution at swift.org
>     <mailto:swift-evolution at swift.org>>
>      >     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>>> wrote:
>      >      >>>>>
>      >      >>>>>
>      >      >>>>>>             On 7 Sep 2017, at 22:02, Itai Ferber
>     <iferber at apple.com <mailto:iferber at apple.com>
>      >     <mailto:iferber at apple.com <mailto:iferber at apple.com>>
>      >      >>>>>>             <mailto:iferber at apple.com <mailto:iferber at apple.com>
>     <mailto:iferber at apple.com <mailto:iferber at apple.com>>>> wrote:
>      >      >>>>>>
>      >      >>>>>>             |protocol Fooable : Equatable { // Equatable is just a
>     simple
>      >      >>>>>>             example var myFoo: Int { get } } extension Fooable {
>     static func
>      >      >>>>>>             ==(_ lhs: Self, _ rhs: Self) -> Bool { return lhs.myFoo ==
>      >      >>>>>>             rhs.myFoo } } struct X : Fooable { let myFoo: Int let
>     myName:
>      >      >>>>>>             String // Whoops, forgot to give an implementation of == }
>      >      >>>>>>             print(X(myFoo: 42, myName: "Alice") == X(myFoo: 42,
>     myName:
>      >     "Bob"))
>      >      >>>>>>             // true|
>      >      >>>>>>             This property is/necessary/, but not/sufficient/to
>     provide a
>      >      >>>>>>             correct implementation. A default implementation might
>     be able
>      >      >>>>>>             to/assume/ something about the types that it defines,
>     but it does
>      >      >>>>>>             not necessarily know enough.
>      >      >>>>>
>      >      >>>>>             Sorry but that's a bit of a contrived example; in this
>     case the
>      >      >>>>>             protocol should*not* implement the equality operator if
>     more
>      >      >>>>>             information may be required to define equality. It
>     should only be
>      >      >>>>>             implemented if the protocol is absolutely clear that
>     .myFoo is the
>      >      >>>>>             only part of a Fooable that can or should be compared as
>      >     equatable,
>      >      >>>>>             e.g- if a Fooable is a database record and .myFoo is a
>     primary
>      >     key,
>      >      >>>>>             the data could differ but it would still be a reference
>     to the
>      >     same
>      >      >>>>>             record.
>      >      >>>>>
>      >      >>>>>             To be clear, I'm not arguing that someone can't create
>     a regular
>      >      >>>>>             default implementation that also makes flawed
>     assumptions, but
>      >     that
>      >      >>>>>             synthesised/reflective implementations*by their very
>     nature have
>      >      >>>>>             to*, as they cannot under every circumstance guarantee
>     correctness
>      >      >>>>>             when using parts of a concrete type that they know
>     nothing about.
>      >      >>>>             You can’t argue this both ways:
>      >      >>>>
>      >      >>>>               * If you’re arguing this on principle, that in order for
>      >      >>>>                 synthesized implementations to be correct, they/must/ be
>      >     able to
>      >      >>>>                 —/under every circumstance/ — guarantee correctness,
>     then you
>      >      >>>>                 have to apply the same reasoning to default protocol
>      >      >>>>                 implementations. Given a default protocol
>     implementation, it is
>      >      >>>>                 possible to come up with a (no matter how contrived)
>     case where
>      >      >>>>                 the default implementation is wrong. Since you’re
>     arguing
>      >     this/on
>      >      >>>>                 principle/, you cannot reject contrived examples.
>      >      >>>>               * If you are arguing this/in practice/, then you’re
>     going to have
>      >      >>>>                 to back up your argument with evidence that synthesized
>      >     examples
>      >      >>>>                 are more often wrong than default implementations.
>     You can’t
>      >      >>>>                 declare that synthesized implementations are/by
>      >     nature/incorrect
>      >      >>>>                 but allow default implementations to slide because/in
>      >     practice/,
>      >      >>>>                 many implementations are allowable. There’s a reason why
>      >      >>>>                 synthesis passed code review and was accepted: in the
>      >     majority of
>      >      >>>>                 cases, synthesis was deemed to be beneficial, and
>     would provide
>      >      >>>>                 correct behavior. If you are willing to say that
>     yes, sometimes
>      >      >>>>                 default implementations are wrong but overall
>     they’re correct,
>      >      >>>>                 you’re going to have to provide hard evidence to
>     back up the
>      >      >>>>                 opposite case for synthesized implementations. You
>     stated in a
>      >      >>>>                 previous email that "A synthesised/reflective
>     implementation
>      >      >>>>                 however may return a result that is simply incorrect,
>      >     because it
>      >      >>>>                 is based on assumptions made by the protocol
>     developer, with no
>      >      >>>>                 input from the developer of the concrete type. In
>     this case the
>      >      >>>>                 developer must override it in to provide *correct*
>      >     behaviour." —
>      >      >>>>                 if you can back this up with evidence (say, taking a
>     survey
>      >     of a
>      >      >>>>                 large number of model types and see if in the
>     majority of cases
>      >      >>>>                 synthesized implementation would be incorrect) to
>     provide a
>      >      >>>>                 compelling argument, then this is something that we
>     should in
>      >      >>>>                 that case reconsider.
>      >      >>>>
>      >      >>>>
>      >      >>>>         Well put, and I agree with this position 100%. However, to
>     play devil's
>      >      >>>>         advocate here, let me summarize what I think Haravikk is saying:
>      >      >>>>
>      >      >>>>         I think the "synthesized" part of this is a red herring, if I
>      >     understand
>      >      >>>>         Haravikk's argument correctly. Instead, it is this:
>      >      >>>>
>      >      >>>>         (1) In principle, it is possible to have a default
>     implementation for a
>      >      >>>>         protocol requirement that produces the correct
>     result--though not
>      >      >>>>         necessarily in the most performant way--for all possible
>     conforming
>      >      >>>>         types, where by conforming we mean that the type respects
>     both the
>      >      >>>>         syntactic requirements (enforced by the compiler) and the
>     semantic
>      >      >>>>         requirements (which may not necessarily be enforceable by
>     the compiler)
>      >      >>>>         of the protocol in question.
>      >      >>>>
>      >      >>>>         (2) However, there exist *some* requirements that, by their very
>      >     nature,
>      >      >>>>         cannot have default implementations which are guaranteed to
>     produce the
>      >      >>>>         correct result for all conforming types. In Haravikk's view,
>     no default
>      >      >>>>         implementations should be provided in these cases. (I don't
>     necessarily
>      >      >>>>         subscribe to this view in absolute terms, but for the sake
>     of argument
>      >      >>>>         let's grant this premise.)
>      >      >>>>
>      >      >>>>         (3) Equatable, Hashable, and Codable requirements are, by
>     their very
>      >      >>>>         nature, such requirements that cannot have default
>     implementations
>      >      >>>>         guaranteed to be correct for all conforming types.
>     Therefore, they
>      >     should
>      >      >>>>         not have a default implementation. It just so happens that a
>     default
>      >      >>>>         implementation cannot currently be written in Swift itself
>     and must be
>      >      >>>>         synthesized, but Haravikk's point is that even if they could
>     be written
>      >      >>>>         in native Swift through a hypothetical reflection facility,
>     they should
>      >      >>>>         not be, just as many other protocol requirements currently
>     could have
>      >      >>>>         default implementations written in Swift but should not have
>     them
>      >     because
>      >      >>>>         they cannot be guaranteed to produce the correct result.
>      >      >>>>
>      >      >>>>         My response to this line of argumentation is as follows:
>      >      >>>>
>      >      >>>>         For any open protocol (i.e., a protocol for which the
>     universe of
>      >      >>>>         possible conforming types cannot be enumerated a priori by
>     the protocol
>      >      >>>>         designer) worthy of being a protocol by the Swift standard
>     ("what
>      >     useful
>      >      >>>>         thing can you do with such a protocol that you could not
>      >     without?"), any
>      >      >>>>         sufficiently interesting requirement (i.e., one for which user
>      >     ergonomics
>      >      >>>>         would measurably benefit from a default implementation)
>     either cannot
>      >      >>>>         have a universally guaranteed correct implementation or has an
>      >      >>>>         implementation which is also going to be the most performant
>     one (which
>      >      >>>>         can therefore be a non-overridable protocol extension method
>     rather
>      >     than
>      >      >>>>         an overridable protocol requirement with a default
>     implementation).
>      >      >>>
>      >      >>>         You're close, but still missing key points:
>      >      >>>
>      >      >>>          1. I am not arguing that features like these should*not* be
>      >     provided, but
>      >      >>>             that they should*not* be provided implicitly, and that
>     the developer
>      >      >>>             should actually be allowed to request them. That is
>     exactly what
>      >     this
>      >      >>>             proposal is about, yet no matter what I say everyone
>     seems to be
>      >      >>>             treating me like I'm against these features entirely; *I
>     am not*.
>      >      >>>
>      >      >>>
>      >      >>>     You are entirely against Equatable having a default
>     implementation for ==.
>      >      >>>     This is unequivocally stated. Others favor such a default
>     implementation and
>      >      >>>     feel that in the absence of a way to spell this in Swift itself, it
>      >     should be
>      >      >>>     magic for the time being. For the purposes of this argument it
>     really is not
>      >      >>>     pertinent that you are not also against something else; you're
>     asking us to
>      >      >>>     discuss why you are against a particular thing that others are for.
>      >      >>
>      >      >>     FFS, how much clearer can I make this? *I AM NOT AGAINST THE FEATURE.*
>      >      >>     *
>      >      >>     *
>      >      >>     What I am against is the way in which it is being provided
>     implicitly rather
>      >      >>     than explicitly, in particular as a retroactive change to existing
>      >     protocols in
>      >      >>     a way that introduces potential for bugs that are currently
>     impossible, but
>      >      >>     also in general.
>      >      >>
>      >      >>
>      >      >> You are against a default implementation for ==, i.e. an
>     implementation that is
>      >      >> provided for you if you conform a type to the protocol and do nothing else
>      >      >> ("implicitly rather than explicitly"), and you are against the default
>      >      >> implementation being on the existing protocol Equatable ("retroactive
>      >     change"). So,
>      >      >> to summarize, what you are against is precisely a default
>     implementation for
>      >     the ==
>      >      >> requirement on Equatable.
>      >      >>
>      >      >> This is the topic of discussion here; I am attempting to convince you
>     that you
>      >      >> should be for rather than against these things.
>      >      >>
>      >      >>
>      >      >>>     As repeatedly answered by others, nothing here is specific to
>     synthesized
>      >      >>>     default implementations, as more powerful reflection will gradually
>      >     allow them
>      >      >>>     to be non-synthesised.
>      >      >>
>      >      >>     And as repeatedly stated by me; I am not treating synthesised vs.
>     run-time
>      >      >>     reflection any differently, I specifically included both in the
>     original
>      >     proposal.
>      >      >>
>      >      >>>     As pointed out very cogently by Itai, you assert but offer no
>     evidence,
>      >     either
>      >      >>>     in principle or empirically, that going too far by reflection is
>     worse than
>      >      >>>     going not far enough without reflection in terms of likelihood of
>     a default
>      >      >>>     implementation being inappropriate for conforming types.
>      >      >>
>      >      >>     As I have also repeatedly pointed out it is not an issue of "not
>     going far
>      >      >>     enough" vs. "going too far"; if a default implementation lacks
>      >     information then
>      >      >>     it should not be provided, doing so regardless is a flaw in the
>     protocol
>      >     design
>      >      >>     and not something that this proposal attempts to address (as such
>     a thing is
>      >      >>     likely impossible).
>      >      >>
>      >      >>
>      >      >> Right, one must consider the semantics of the specific protocol
>     requirement
>      >     and ask
>      >      >> whether a reasonable default can be provided for it.
>      >      >>
>      >      >>     Reflective implementations *necessarily* go too far, because they
>     literally
>      >      >>     know *nothing* about the concrete type with any certainty, except
>     for the
>      >      >>     properties that are defined in the protocol (which do not require
>      >     reflection or
>      >      >>     synthesis in the first place).
>      >      >>
>      >      >>
>      >      >> I am confused why you are trying to argue in general terms about the
>     universe of
>      >      >> all possible default implementations that use reflection. This is
>     necessarily a
>      >      >> more difficult argument to make, and if it is to be convincing for all
>     default
>      >      >> implementations it must also be convincing for the two specific protocol
>      >      >> requirements we are talking about here. Start small:
>      >      >>
>      >      >> We have agreed, as a community, that there is a reasonable default
>     implementation
>      >      >> for Equatable.== when certain conditions are met (for value types only
>     at the
>      >      >> moment, I believe). Namely, given two values of a type that has only
>     Equatable
>      >      >> stored properties, those values are equal if their stored properties
>     are all
>      >     equal.
>      >      >> The author of a new value type who wishes to make her type Equatable
>     but chooses
>      >      >> not to implement a custom == then benefits from this default when all
>     stored
>      >      >> properties are Equatable.
>      >      >>
>      >      >>     And precisely what kind of "evidence" am I expected to give? This
>     is a set of
>      >      >>     features that *do not exist yet*, I am trying to argue in favour of an
>      >     explicit
>      >      >>     end-developer centric opt-in rather than an implicit protocol designer
>      >     centric
>      >      >>     one. Yet no-one seems interested in the merits of allowing
>     developers to
>      >     choose
>      >      >>     what they want, rather than having implicit behaviours appear
>     potentially
>      >      >>     unexpectedly.
>      >      >>
>      >      >>
>      >      >> Both options were examined for Codable and for Equatable/Hashable. The
>     community
>      >      >> and core team decided to prefer the current design. At this point, new
>     insights
>      >      >> that arise which could not be anticipated at the time of review could
>     prompt
>      >      >> revision. However, so far, you have presented arguments already
>     considered during
>      >      >> review.
>      >      >>
>      >      >>>     Therefore, your argument reduces to one about which default
>     implementations
>      >      >>>     generally ought or ought not to be provided--that is, that they
>     ought to be
>      >      >>>     provided only when their correctness can be guaranteed for all
>     (rather than
>      >      >>>     almost all) possible conforming types. To which point I sketched a
>      >     rebuttal above.
>      >      >>
>      >      >>     If a protocol defines something, and creates a default
>     implementation based
>      >      >>     only upon those definitions then it must by its very nature be
>     correct. A
>      >      >>     concrete type may later decided to go further, but that is a
>     feature of the
>      >      >>     concrete type, not a failure of the protocol itself which can function
>      >      >>     correctly within the context it created. You want to talk
>     evidence, yet there
>      >      >>     has been no example given that proves otherwise; thus far only
>     Itai has
>      >      >>     attempted to do so, but I have already pointed out the flaws with that
>      >     example.
>      >      >>
>      >      >>     The simple fact is that a default implementation may either be
>     flawed or not
>      >      >>     within the context of the protocol itself; but a reflective or
>     synthetic
>      >      >>     implementation by its very nature goes beyond what the protocol
>     defines
>      >     and so
>      >      >>     is automatically flawed because as it does not rely on the
>     end-developer to
>      >      >>     confirm correctness, not when provided implicitly at least.
>      >      >>
>      >      >>
>      >      >> Again, if it applies generally, it must apply specifically. What is
>      >     "automatically
>      >      >> flawed" about the very reasonable synthesized default implementation
>     of ==?
>      >      >>
>      >      >>>         And all of this continues to be a side-issue to the fact that
>     in the
>      >      >>>         specific case of Equatable/Hashable, which thus far has gone
>     ignored, is
>      >      >>>         that bolting this on retroactively to an existing
>     protocol*hides bugs*.
>      >      >>>         The issue of reflective default implementations is less of a
>     concern on
>      >      >>>         very clearly and well defined*new* protocols, though I still
>     prefer
>      >     more,
>      >      >>>         rather than less, control, but in the specific case of*existing*
>      >     protocols
>      >      >>>         this fucking about with behaviours is reckless and foolish in the
>      >     extreme,
>      >      >>>         yet no-one on the core teams seems willing or able to justify
>     it, which
>      >      >>>         only opens much wider concerns (how am I to have any faith in
>     Swift's
>      >      >>>         development if the core team can't or won't justify the
>     creation of new
>      >      >>>         bugs?).
>      >      >>>
>      >      >>>
>      >      >>>     This has emphatically not gone ignored, as I have myself
>     responded to this
>      >      >>>     point in an earlier thread in which you commented, as well as
>     many others.
>      >      >>>     Crucially, no existing conforming type changes its behavior, as they
>      >     have all
>      >      >>>     had to implement these requirements themselves. And as I said to you
>      >     already,
>      >      >>>     the addition of a synthesized default implementation no more
>     "hides bugs"
>      >      >>>     going forward than the addition of a non-synthesized default
>      >     implementation to
>      >      >>>     an existing protocol, and we do that with some frequency without
>     even Swift
>      >      >>>     Evolution review.
>      >      >>
>      >      >>     Feel free to a supply a non-synthesised default implementation for
>     Equatable
>      >      >>     without the use of reflection. Go-on, I'll wait.
>      >      >>     You insist on suggesting these are the same thing, yet if you can't
>      >     provide one
>      >      >>     then clearly they are not.
>      >      >>
>      >      >>
>      >      >> That is not the argument. The argument is that they are
>     indistinguishable in the
>      >      >> sense that the author of a type who intends to supply a custom
>     implementation but
>      >      >> neglects to do so will have a default implementation supplied for
>     them. It is
>      >      >> plainly true that this is no more or less likely to happen simply
>     because the
>      >      >> default implementation is synthesized.
>      >      >>
>      >      >>>     Put another way, what the proposal about synthesizing
>     implementations for
>      >      >>>     Equatable and Hashable was about can be thought of in two parts:
>     (a) should
>      >      >>>     there be default implementations; and (b) given that it is
>     impossible to
>      >     write
>      >      >>>     these in Swift, should we use magic? Now, as I said above, adding
>     default
>      >      >>>     implementations isn't (afaik) even considered an API change that
>     requires
>      >      >>>     review on this list. Really, what people were debating was (b),
>     whether
>      >     it is
>      >      >>>     worth it to implement compiler-supported magic to make these
>     possible. Your
>      >      >>>     disagreement has to do with (a) and not (b).
>      >      >>
>      >      >>     Wrong. The use of magic in this case produces something else
>     entirely; that's
>      >      >>     the whole point. It is *not the same*, otherwise it wouldn't be
>     needed at
>      >     all.
>      >      >>     It doesn't matter if it's compiler magic, some external script or
>     a native
>      >      >>     macro, ultimately they are all doing something with a concrete
>     type that is
>      >      >>     currently not possible.
>      >      >>
>      >      >>     And once again; *I am not arguing against a default implementation
>     that cuts
>      >      >>     boilerplate*, I am arguing against it being implicit. What I want
>     is to
>      >     be the
>      >      >>     one asking for it, because it is not reasonable to assume that just
>      >     throwing it
>      >      >>     in there is always going to be fine, because it quite simply is not.
>      >      >>
>      >      >>
>      >      >> If you have to ask for it, then it's not a default. You *are* against
>     a default
>      >      >> implementation.
>      >      >>
>      >      >>     _______________________________________________
>      >      >>     swift-evolution mailing list
>      >      >> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>      >     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>>
>      >      >> https://lists.swift.org/mailman/listinfo/swift-evolution
>      >      >>
>      >      >> _______________________________________________
>      >      >> swift-evolution mailing list
>      >      >> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>      >     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>>
>      >      >> https://lists.swift.org/mailman/listinfo/swift-evolution
>      >      >
>      >      >
>      >      > _______________________________________________
>      >      > swift-evolution mailing list
>      >      > swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>      >      > https://lists.swift.org/mailman/listinfo/swift-evolution
>      >      >
>      >     _______________________________________________
>      >     swift-evolution mailing list
>      > swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>     <mailto:swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>      > https://lists.swift.org/mailman/listinfo/swift-evolution
>      >
> 


More information about the swift-evolution mailing list