New operators opStaticIndex and friends
Q. Schroll
qs.il.paperinik at gmail.com
Sat May 18 01:23:51 UTC 2019
On Friday, 17 May 2019 at 19:52:53 UTC, Exil wrote:
> On Friday, 17 May 2019 at 17:41:26 UTC, Q. Schroll wrote:
>> On Thursday, 16 May 2019 at 22:26:34 UTC, Exil wrote:
>>> This doesn't help with the explanation, what special syntax?
>>> Maybe an example that works with opStaticIndex and that
>>> wouldn't work with opIndex would help. Otherwise I still
>>> don't see a problem.
>>
>> Simple answer is: You cannot overload opIndex aliasing a data
>> member and opIndex being a function. If it is a function
>> somewhere, it *must* always be a function in that aggregate
>> (struct/union/class/interface).
>
> That's what template specialization is exactly for. Exactly how
> it can be used:
Do you really mean specialization? I'm asking as you don't use it
in your following example. Maybe you mean instantiation? I just
want to make sure we're talking about the same thing.
> struct A {
>
> template opIndex(int i) {
> static if (i == 0) alias opIndex = member1;
> else alias opIndex = member2;
> }
>
> int member1;
> double member2;
>
>
> int opIndex(int a, int b) { return 0; }
>
> int opIndex(T...)(T a) { return 1; }
>
> }
>
> void main() {
> A a;
>
> a[0,0];
> a[0];
>
> a.opIndex!0 = 10; // a[0] = 10
> a.opIndex!1 = 10.1; // a[1] = 10.1
>
> writeln(a.member1, a.member2);
> }
I'm sorry, but I don't get what you want to show me. I strongly
believe that you have a point somewhere and I'm just not seeing
it. I've just tried out that code piece and it worked to my
surprise.
I honestly think now, it's actually possible. The question
remaining is: Is it really better or rather too complicated?
In the current form of the DIP, if you'd use a type as index,
it'd compile. I'll change that, because that's not how it's meant
to be.
I find it really difficult to say if widening the abilities of
opIndex to opStaticIndex can be done. There are so many corner
cases. That's mainly why I proposed a new compiler-recognized
name: It's the safe option.
In the current state of D, opIndex must be callable to trigger
the rewrite; being present as member is insufficient. As a simple
example, if you use std.typecons.Tuple with a member namend
"opIndex" of type int, you still can do everything you'd expect
from a tuple with reasonable field names. Notably, it doesn't
invalidate static indexing. But make "opIndex" of type `int
delegate(/*whatever you like*/)`, and the Tuple is unusable:
https://run.dlang.io/is/BuiT2a
It's somewhat artificial and not a reason for the DIP. Sure,
naming a member "opStaticIndex" would break the tuple, too.
>> It is more flexible not having a name clash. It's easier to
>> learn and reason about, too. To me, it has literally no
>> benefit using opIndex for static indexing.
>>
>> Part of a working example: https://run.dlang.io/is/274pNN
>
> So what if you have 2 parameters, one is a runtime value and
> the other is a compile time value? Would it be a compile error
> then? But then you can implement opIndex and opStaticIndex, so
> you can use two runtime values and two compile time values but
> if for some reason you need one, instead you will need some
> hacky work around to get it to work:
>
> arr[ 0, someRunTimeIndex() ] = 10; // error mixing
> compile-time and run-time
>
> int i = 0;
> arr[ i, someRunTimeIndex() ] = 10; // ok
To use a template, you need *all* arguments at compile-time.
Otherwise it's lowered to a run-time indexing operation no matter
how many arguments are present at compile-time.
The first call (// error mixing) is not a problem. The fact that
some values could be used as a template parameter is irrelevant.
The question is: Does the template instantiation work? And the
answer is no. That's where double indexing, e.g. tup[0][1] versus
tup[0,1] makes a real difference. If you really need mixing sorts
of arguments, that's the way I'd do it.
Mixing is not an error. Mixing is just run-time.
More information about the Digitalmars-d
mailing list