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