Without D1-style operator overloads, the `in` operator for classes doesn't make sense
Don
prosthetictelevisions at teletubby.medical.com
Mon Jan 6 17:25:44 UTC 2020
On Monday, 6 January 2020 at 14:14:35 UTC, Steven Schveighoffer
wrote:
> On 1/6/20 6:16 AM, Ontonator wrote:
>> On Monday, 6 January 2020 at 10:55:15 UTC, Don wrote:
>>> In DMD 2.088.0, the D1 operator overloads were deprecated, in
>>> favour of the D2 syntax which has been available for years.
>>>
>>> [...]
>>
>> I’m on my phone right now, so I can’t check, but could you
>> emulate a virtual operator by creating a virtual method (e.g.
>> `contains`) which is called from the operator and which child
>> classes could override? It isn’t as ergonomic, but it should
>> work.
>
> In fact this is exactly why this change was allowed (and this
> exact problem was discussed):
>
> class C
> {
> int* opIn(string key); // virtual
>
> auto opBinaryRight(string op : "in", X)(X key) // wrapper
> {
> return opIn(key);
> }
> }
>
> So when/if the D1 operators get removed, you put this wrapper
> in, and it works.
Indeed, you have implement something like that to support the
'in' syntax on any class.
But it's only a partial workaround.
It's an ugly hack, and since there's no way to do it without
breaking other code (see below), why would you even do that?
You are better off just creating a normal function like
`contains`, the same as you would do in C++.
Note that I am singling out opIn and opCat/opCatAssign. These are
fundamentally different from the normally binary operators.
A large part of the motivation for creating the D2-style
overloads was the recognition that the code for '+' and '-' is
almost always the same. Even '*', '/', '<<', will often share
code with '+'. Merging them gets rid of a lot of code duplication.
But that isn't true for 'in' and '~'. We've made them
syntactically similar, but semantically they are unrelated and
they would normally share no code with the arithmetic and logical
operators. In fact it's pretty rare for an object to define both
'+' and 'in', for example.
They are much more closely related to opIndex and opSlice.
('in' is semantically similar to opIndex, in many ways).
> In fact, you can easily make a mixin template that will
> implement all the D2 style operators when you have defined the
> D1 style ones.
That's blocked as a direct migration path, because deprecation
warnings are generated if you use the D1 names. (And no, you
cannot turn off deprecation warnings, that turns off *all*
deprecation warnings).
So you have to use names which are different from the D1 names.
That creates a new problem. If you've deployed this as a library
(which is very likely in collection classes!), anybody who has
derived a class from your library class, and overridden opIn, now
needs to rename their opIn to use your new name. You'd like to
create a deprecation message to tell them how to do this, but is
there even a way to do that?
(Incidentally, this is a illustration of why a deprecation
process can make things much, much worse than directly removing
something).
In practice, support for the 'in' operator in classes has been
dropped. Pretty much silently.
This is a major breaking change, it's not discussed in the
changelog (the changelog advocates a mechanical substitution
which doesn't work).
To make matters worse, there was no stability branch before this
release. So to get critical security/wrong code bugfixes, you
need to make this complicated change that propagates to code you
don't even control.
I think we've made a mistake here.
More information about the Digitalmars-d
mailing list