On 13.09.2017 20:48, Tony Allevato wrote:
On Wed, Sep 13, 2017 at 10:21 AM Vladimir.S via swift-evolution <[email protected] <mailto:[email protected]>> wrote:

    On 13.09.2017 19:08, Ondrej Barina via swift-evolution wrote:
     > Maybe something like this as middle ground.
     >
     > protocol Equatable {
     >      @syntetic static func ==(_ lhs: Self, _ rhs: Self) -> Bool
     > }
     >
     > protocol itself contains default implementation, but without real body.
    Instead the
     > function is marked that the real body is generated by compiler.
     > There is explicit mentions of default impl (by compiler magic), but it 
does not
     > affects users as they would still use protocol in normal way:
     >
     > struct Foo: Equatable { .... }

    Yes, I also thought about this. And personally for me it is also good 
solution, while
    `struct S: Equatable {/*nothing*/}` will *still* lead to compiler's error 
or at least
    warning about not implemented requirements.
    So, I'll be explicit regarding my intention: do I want requirements to be
    auto-generated or I want to do this manually.

    But still. If you see

    struct S: Equatable, Codable {
        // a lot of lines
    }

    you can't say right now if requirements for Equatable and/or Codable was 
implemented
    manually or will be auto-generated without checking all the code of a type. 
This
    knowledge can help to faster solve issues related to comparison/archiving.
    So for me the best solution is still 'deriving'-like keyword, which adds 
clarity and
    show intention without any boilerplate code:


The sentences above apply equally to non-synthesized default protocol 
implementations:

struct S: Foo {
   // a lot of lines
}

I can't say if the requirements for Foo were implemented manually by S or by a default implementation in Foo (which could be in a different module that I don't have source access to) without checking all the code for S. So this can't be used as a basis to rationalize special-casing synthesized implementations.

As was noted in this thread, some people believe that protocol synthesizing its requirements by accessing type's fields is of a different kind than 'usual' protocol with default implementation. I belong to that camp. So, from my point of view, it is important to have 'deriving'-like marker for 'auto-senthesizeable' protocols as described above.

Also, some 'usual' protocol Foo can have no default implementations at the moment of *writing* the code, but can have them at the moment of *compilation* via protocol extension in separate file in project. So it is not possible to require similar marker for such protocol. But Equatable/Hashable/Codable protocols has auto-generation feature already at the moment of writing the code and we can request that marker.

Vladimir.



    struct S: Equatable, deriving Codable {
        // all clear:
        // manually implemented Equatable
        // auto-generated Codable

        // a lot of lines
    }

    Vladimir.

     >
     > Ondrej B.
     >
     > On Wed, Sep 13, 2017 at 4:14 PM, Haravikk via swift-evolution
     > <[email protected] <mailto:[email protected]>
    <mailto:[email protected] <mailto:[email protected]>>> 
wrote:
     >
     >
     >>     On 13 Sep 2017, at 03:26, Xiaodi Wu <[email protected]
    <mailto:[email protected]>
     >>     <mailto:[email protected] <mailto:[email protected]>>> wrote:
     >>
     >>     On Tue, Sep 12, 2017 at 11:43 AM, Haravikk via
     >>     swift-evolution<[email protected]
    <mailto:[email protected]> <mailto:[email protected]
    <mailto:[email protected]>>>wrote:
     >>
     >>
     >>>         On 12 Sep 2017, at 12:08, Xiaodi Wu <[email protected]
    <mailto:[email protected]>
     >>>         <mailto:[email protected] <mailto:[email protected]>>> 
wrote:
     >>>
     >>>>         On Mon, Sep 11, 2017 at 06:03 Haravikk via swift-evolution
     >>>>         <[email protected] <mailto:[email protected]>
    <mailto:[email protected] <mailto:[email protected]>>> 
wrote:
     >>>>
     >>>>             See, this is another flawed assumption; you are assuming 
that
     >>>>             omitting a custom implementation of == is always 
intentional rather
     >>>>             than an oversight, which is not guaranteed. This is one 
of my
    gripes
     >>>>             with the retroactive change to Equatable, as it is
     >>>>             currently*impossible* to omit an implementation.
     >>>
     >>>
     >>>         Again, this applies equally to the addition of _any_ default
     >>>         implementation. And again, such changes don’t even require 
Swift
    Evolution
     >>>         approval.
     >>
     >>         So what? Because the Swift Evolution process is currently 
deficient we
     >>         should just give up on discussing problems with features and 
the language
     >>         altogether?
     >>
     >>
     >>     I don't claim that it's a deficiency; I claim it's reflective of 
Swift's
     >>     opinionated take on default implementations. Are you, after all, 
saying that
     >>     you have a problem with the addition of _any_ default 
implementation to an
     >>     existing protocol? If so, this conversation isn't about
    synthesis/reflection at
     >>     all.
     >
     >     No, and you should know that by now. I suggest actually reading some 
of what I
     >     have written as I am sick of repeating myself.
     >
     >>>>>>             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.
     >>>>
     >>>>             And so far all I have heard about this is how it was 
"decided";
     >>>>             no-one seems interested in showing how any of these 
concerns were
     >>>>             addressed (if at all), so as far as I can tell they were 
not,
    or they
     >>>>             were wilfully ignored.
     >>>
     >>>
     >>>         They were addressed by being considered.
     >>
     >>         And yet no-one can apparently summarise what those 
"considerations" might
     >>         be, suggesting that they were either *not* considered at all, 
or that the
     >>         "consideration" was so weak that no-one is willing to step 
forward to
     >>         defend it. Either way it is not sufficient by any reasonable 
measure.
     >>
     >>         If I were to run over your foot in my car, would you be happy 
to accept
     >>         that I "considered" it first?
     >>
     >>
     >>     How do you mean? People wrote in with their opinions. Then, taking 
into
    account
     >>     the community's response, the proposal was approved.
     >
     >     I mean because not once have you summarised what these alleged
    "considerations"
     >     were; if they exist then you should be able do so, yet all I am hearing 
is "it
     >     was considered", which frankly is not an argument at all as it is 
entirely
     >     without substance.
     >
     >     If it was genuinely considered then someone should be able to say 
what points
     >     were considered and what conclusions were reached and why. And even 
if there
     >     *was* an earlier decision, that doesn't necessarily make it right. 
We are
     >     discussing it now, and it is clear that any decision that has been 
made
    has been
     >     made poorly at best.
     >
     >     And if you're talking about the discussion on Equatable/Hashable 
specifically,
     >     I'm afraid your memory of the "considerations" is radically 
different to
    mine; as
     >     the concerns I raised were essentially ignored, as not a single 
person gave a
     >     justification more substantial than "but, but Codable!" which 
frankly isn't a
     >     justification at all.
     >
     >>>>>>                 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 ==?
     >>>>
     >>>>             It makes the assumption that every equatable property of 
a type is
     >>>>             necessarily relevant to its equality.
     >>>
     >>>
     >>>         No necessarily, only provisionally and rebuttably. If it’s not 
the case,
     >>>         override the default.
     >>
     >>         So… entirely unlike standard default implementations
     >>         which*cannot* "provisionally" assume something is relevant at 
all,
     >>
     >>
     >>     Why not?
     >
     >     Because they can only act upon properties/methods that they 
themselves (or a
     >     parent protocol) define. FFS, what is so unclear about that? Or are 
you
    arguing
     >     on this subject without every having actually used a protocol before?
     >
     >>         thereby making them entirely different from 
synthesised/reflective
     >>         implementations!
     >>
     >>         I'm sorry, but you keep trying to argue that they're the same, 
but then
     >>         admitting that they're not. You can't have it both ways.
     >>
     >>
     >>     Well, certainly, synthesized default implementations differ from
     >>     non-synthesized ones in key respects. However, they do not differ 
in terms of
     >>     the user experience of conforming to the protocol and having to 
override the
     >>     default.
     >
     >     Except that that's not true at all, is it?
     >
     >     Synthesised default implementations go much further in how they 
attempt (and
     >     potentially fail) to implement those defaults, and in the specific 
case of
     >     Equatable/Hashable they are fully implementing a protocol without a 
single
     >     property of method being raised as a requirement; they are utterly
    different at a
     >     fundamental level, no amount of mental contortion changes that fact.
     >
     >>>>             Consider for example if a type stores a collection index 
for
     >>>>             performance reasons; this isn't an intrinsic part of the 
type, nor
     >>>>             relevant to testing equality, yet this default 
implementation will
     >>>>             treat it as such because it*knows nothing about the 
concrete type's
     >>>>             properties*. If a protocol does not define a property 
then any
    action
     >>>>             taken upon such a property is necessarily based upon an 
assumption;
     >>>>             just because it might be fine some of the time, does not 
make
    it any
     >>>>             less flawed.
     >>>>
     >>>>             The big difference here between explicit and implicit 
synthetic
     >>>>             implementations is where this assumption originates; if a 
method is
     >>>>             synthesised implicitly then the assumption is made by the 
protocol
     >>>>             designer alone, with no real involvement by the end 
developer. If I
     >>>>             explicitly opt-in to that default however I am signalling 
to the
     >>>>             protocol that it is okay to proceed. In the former case 
the
     >>>>             assumption is unreasonable, in the latter it is explicitly
     >>>>             authorised. It is a difference between "I want to make 
the decision
     >>>>             on what's correct" and "I am happy for you (the protocol
    designer) to
     >>>>             decide".
     >>>>
     >>>>             Right now, when I conform to Equatable, it is a declaration of 
"I
     >>>>             will implement this", but with this retroactive implicit 
change
    it is
     >>>>             now a declaration of "implement this for me", these are 
two
    entirely
     >>>>             different things. Consider; what if I'm working on a 
piece of code
     >>>>             that requires types to be Equatable, but one of the types 
I'm using
     >>>>             currently isn't, so I quickly throw Equatable conformance 
onto
    it and
     >>>>             go back to what I was doing, with the intention of 
completing
     >>>>             conformance later. With this change that type may now 
receive a
     >>>>             default implementation that is wrong, and I've lost the 
safety net
     >>>>             that currently exists.
     >>>
     >>>
     >>>         Right now, it still wouldn’t compile, so I don’t see why you 
would do
     >>>         that. In the future, if you want to make it not compile, there 
is
    nothing
     >>>         stopping you from conforming to a non-existent 
“NotYetEquatable”.
    This was
     >>>         something that you asked about earlier and it was answered.
     >>
     >>         So your solution is to intentionally write invalid code to work
    around the
     >>         fact that a feature is being implemented badly?
     >>
     >>
     >>     You stated a use case where you *want* the compiler to stop your 
code from
     >>     compiling by stating a conformance to Equatable without 
implementing its
     >>     requirements. You then stated that the major problem you have with
    synthesized
     >>     `==` is that the compiler will now use a default implementation 
that you
    might
     >>     forget about instead of stopping compilation. Therefore, I 
demonstrated
    how you
     >>     could continue to have the compiler stop your code from compiling. 
It's
    not my
     >>     solution that is intentionally writing invalid code; your stated 
aim was
    to be
     >>     able to do so.
     >
     >     My stated aim was nothing of the sort.
     >
     >     I was pointing out that right now conforming to Equatable means 
something
     >     entirely different from what it will mean in future if this idiotic 
change
    makes
     >     it into release. Please actually read what I write before deciding 
for
    yourself
     >     what my 'stated aim' is.
     >
     >     I am *not* asking for workarounds to circumvent a ridiculously flawed
    change to
     >     the language, I am arguing why it is flawed and must be changed. If 
I wanted a
     >     workaround I'd do what I'm now seriously considering, which is 
ditching Swift
     >     completely, as I will not use a language if I can no longer trust 
the team
     >     developing it or the decisions that they make.
     >
     >>>>             A non-synthesised/reflective implementation cannot 
strictly be
     >>>>             incorrect, because as long as it is implemented properly 
it will
     >>>>             always be correct within the context of the protocol 
itself. It may
     >>>>             not go quite as far as an end developer might want, but 
that is
     >>>>             because they want to add something onto the protocol, not
    because the
     >>>>             protocol is wrong.
     >>>>
     >>>>             A synthesised/reflective implementation differs because 
if it goes
     >>>>             too far it is wrong not only within the context of the 
concrete
    type,
     >>>>             but also the protocol itself, it is simply incorrect.
     >>>
     >>>
     >>>         Again, this is an assertion that misses the mark. If the 
default
     >>>         implementation is unsuitable for a type, it’s unsuitable 
whether it
     >>>         “doesn’t go quite as far” or “goes too far.”
     >>
     >>         Because not going quite far enough is not a failure of the 
protocol, as
     >>         protocols by their very nature can only go as far as what they
    define. If a
     >>         protocol Foo defines two properties, a method which uses those 
two
     >>         properties correctly, then the method is correct. A developer 
of a
    concrete
     >>         type might want to add more information or tailor the 
behaviour, but that
     >>         doesn't make the default implementation incorrect, it's just 
considering
     >>         the type only within the context of being an instance of Foo.
     >>
     >>         Going too far is the opposite; it's the protocol designer 
messing around
     >>         with stuff they do not define at all. It's only ever right by 
chance, as
     >>         it's operating within the context of the concrete type, about 
which the
     >>         protocol does not know anything with certainty.
     >>
     >>
     >>     Yes, you have defined "not going far enough" and "going too far" 
based on
     >>     whether an implementation uses only protocol requirements or not.
    However, you
     >>     haven't at all demonstrated why this distinction is at all 
meaningful in
    terms
     >>     of the issue you describe with a user conforming to a protocol. If 
there is a
     >>     default implementation, either it returns the expected result for 
the
     >>     conforming type or it does not--those are the only two choices. Are 
you
    arguing
     >>     that, empirically, the default implementation for Equatable will 
more
    often be
     >>     unsuitable for conforming types? If so, what's your evidence?
     >
     >     What's yours? If this issue was as "considered" as you constantly 
claim then
     >     where is the evidence that there is no meaningful distinction? 
Surely such
     >     evidence exists, or else the issue hasn't been considered at all, 
has it?
     >
     >     Frankly I am sick of being asked to provide evidence when you are 
seemingly
     >     unwilling to do anything in return, especially when you have 
conveniently
    ignored
     >     every single example that I have already given.
     >
     >     It cuts both ways; you claim that "going too far" and "not going far
    enough" are
     >     the same thing? Well prove it.
     >
     >>>         You state but do not give any rationale for the claim that the 
former is
     >>>         not wrong in some context while the latter is always wrong.
     >>>
     >>>         By this line of argumentation, you’d be perfectly content if 
instead we
     >>>         simply had the default implementation of == as “return true” 
because it
     >>>         would be somehow not wrong.
     >>
     >>         Only if return true were a reasonable default to give in the 
context
    of the
     >>         protocol, which it clearly is not, as it's not performing any 
kind of
     >>         comparison of equality.
     >>
     >>
     >>     Sure it is; `return true` satisfies all the semantic requirements 
for
    equality:
     >>     reflexivity, symmetry, transitivity; and, in the context of the 
protocol
    which
     >>     only provides for this one facility (determination of equality or
    inequality),
     >>     any two instances that compare equal _are_ completely interchangeable 
"within
     >>     the context of the protocol itself," as you would say.
     >
     >     The purpose of Equatable is to identify types that can be compared 
for
    equality;
     >     returning true does not satisfy that aim because no such comparison 
is
    occurring,
     >     so your example is intentionally ridiculous. Even a less contrived 
example
    such
     >     as comparing memory addresses doesn't fulfil the purpose of 
Equatable,
    which is
     >     all about comparing equality of different instances that might still 
be
    the same.
     >
     >>>>>                 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.
     >>>
     >>>             A default implementation is an implementation that I, as 
the
    concrete
     >>>             type developer, do not have to provide myself. If you want
    default to
     >>>             mean only "automatic" then your attempt to pigeon-hole 
what I am
     >>>             arguing is incorrect, because what I am arguing is then 
neither
    about
     >>>             default implementations nor the means of actually 
implementing
    it, but
     >>>             something else entirely.
     >>>
     >>>             But as far as I'm concerned it still absolutely still a 
default
     >>>             implementation whether it is requested or not; the 
difference is
    I, as
     >>>             the end developer, am able to refine what type of defaults 
that
    I want.
     >>>
     >>>
     >>>         The word “default” indicates something that arises in the 
absence of a
     >>>         user indication otherwise.
     >>
     >>         Then this proposal is just for a different mechanism for 
"indicating
     >>         otherwise".
     >>
     >>         You keep trying to argue that a synthesised/reflective default
     >>         implementation is the same as a normal default implementation, 
yet
    you seem
     >>         to be consistently forgetting that even if that is true without 
this
     >>         proposal, that the very proposal itself is to change that, 
effectively
     >>         causing a category of default implementation to become 
explicitly
     >>         opted-into, rather than implicitly. They're still 
implementations
    that will
     >>         be provided automatically, just only when they are permitted to 
do-so.
     >>
     >>
     >>     So to be clear, you are *against* them being the *default*: you 
wish them
    to be
     >>     the *otherwise*.
     >
     >     You seem to be insisting upon a narrow definition of default; what I 
want is
     >     control over which types of default implementations are provided. 
Just because
     >     they must be opted-into explicitly does not stop them being 
"default", as they
     >     are still implementations that I myself do not need to implement. The
    difference
     >     is that I want to actually *want* them rather than have provided 
through
     >     potentially flimsy assumptions made by a protocol designer. Just 
because
    there's
     >     an extra step doesn't make them any less automatic, otherwise having 
to
    conform
     >     to a protocol in the first place would also prevent them from being 
defaults.
     >
     >     Asking *for* something is more like a middle-ground between the two; 
the
     >     synthetic implementations are still possible defaults, they just 
aren't
    provided
     >     unless you allow them, while omitting the necessary 
keyword/attribute prevents
     >     them being used.
     >
     >>>>             On 9 Sep 2017, at 23:17, Gwendal Roué 
<[email protected]
    <mailto:[email protected]>
     >>>>             <mailto:[email protected]
    <mailto:[email protected]>>> wrote:
     >>>>
     >>>>             All right, I'll be more positive: our science, IT, is a
     >>>>             *constructive* science, by *essence*. If there is a 
problem, there
     >>>>             must be a way to show it.
     >>>>             It you can't, then there is no problem.
     >>>
     >>>             You mean just as I have asked for examples that prove
     >>>             non-synthetic/reflective default implementations are as 
dangerous as
     >>>             synthetic/reflective ones? Plenty have suggested this is 
the
    case yet
     >>>             no reasonable examples of that have been given either.
     >>>
     >>>             However, examples highlighting problems with the 
synthesised
    behaviour
     >>>             are simple:
     >>>
     >>>                 structFoo :Equatable{vardata:String}// Currently an 
error, won't
     >>>                 be in future
     >>>
     >>>
     >>>             Or something a bit more substantial:
     >>>
     >>>                 structKeyPair :Equatable{
     >>>                 staticvarcount:Int=0
     >>>
     >>>                 varcount:Int
     >>>                 letkey:String// This is the only property that should 
be
    equatable
     >>>                 varvalue:String
     >>>
     >>>                 init(key:String, value:String) {
     >>>                 letcount =KeyPair.count&+1
     >>>                 KeyPair.count= count;self.count= count
     >>>                 self.key= key;self.value= value
     >>>                 }
     >>>                 }
     >>>
     >>>             Here the only important property in the key pair is the 
key, the
    value
     >>>             isn't important (only the keys are to be considered 
unique) and the
     >>>             count is just a throwaway value. The synthesised default
     >>>             implementation for this concrete type will therefore be 
completely
     >>>             wrong, likewise for Hashable, which will likely produce 
radically
     >>>             different results for instances that should be the same.
     >>
     >>         I notice that despite asking endlessly for examples, the ones 
I've given
     >>         are being ignored. In future I shall remind people asking for 
examples
     >>         where they can shove them.
     >
     >     And once again, totally ignored. You seem to love asking for 
"evidence"
    but why
     >     exactly should I bother giving anything if you ignore it when I try 
to?
     >
     >     _______________________________________________
     >     swift-evolution mailing list
     > [email protected] <mailto:[email protected]>
    <mailto:[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] <mailto:[email protected]>
     > https://lists.swift.org/mailman/listinfo/swift-evolution
     >
    _______________________________________________
    swift-evolution mailing list
    [email protected] <mailto:[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