Bug 3188 – remove opIndexAssign from the language

Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2009-07-17T07:12:00Z
Last change time
2015-06-09T01:28:07Z
Assigned to
nobody
Creator
k-foley

Comments

Comment #0 by k-foley — 2009-07-17T07:12:27Z
Despite being redundant, my main gripe with opIndexAssign is that it can even get in the way. For instance: --- import std.stdio; struct Arr(size_t W, size_t H, T) { T[W * H] arr; this(T[W*H] rhs) { arr = rhs; } ref T opIndex(size_t row, size_t col) { return arr[row + W*col]; } } int main() { auto a = Arr!(2, 2, int)( [1, 2, 3, 4] ); writeln( "a[1, 1] = ", a[1, 1] ); // a[1, 1] = 4 a[1, 1] += 2; writeln( "a[1, 1] = ", a[1, 1] ); // a[1, 1] = 6 // This requires opIndexAssign, but for no good reason //a[1, 1] = 42; //writeln( "a[1, 1] = ", a[1, 1] ); return 0; }
Comment #1 by smjg — 2009-07-17T10:24:56Z
(In reply to comment #0) > Despite being redundant, my main gripe with opIndexAssign is that it can even > get in the way. For instance: opIndexAssign isn't redundant, just as property setters aren't redundant. > // This requires opIndexAssign, but for no good reason > //a[1, 1] = 42; Given that opIndexAssign doesn't occur in your code, removing opIndexAssign from the language isn't going to magically make this work. Here's the compiler output (DMD 2.031 Win): ---------- C:\Users\Stewart\Documents\Programming\D\Tests\bugs>dmd bz3188.d bz3188.d(28): Error: operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i) ---------- Really, the problem is that opIndex is only meant to work on op=, ++ and --, not = itself. http://www.digitalmars.com/d/2.0/operatoroverloading.html "Note: To use array index overloading with the op=, ++, or -- operators, have the opIndex function return a reference type. This reference is then used as the lvalue for those operators." The way resolving = ought to work: - first look for a matching opIndexAssign - if none, look for an opIndex with a ref return
Comment #2 by k-foley — 2009-07-17T12:12:06Z
> Given that opIndexAssign doesn't occur in your code, removing opIndexAssign > from the language isn't going to magically make this work. I don't see why not. "a[1, 1] = 42;" should just become "a.opIndex(1, 1) = 42;" rather than do something special because the "=" is there. I am under the impression that opIndexAssign is there only because return by reference was not available at the time of designing operator overloads. But I would be satisfied with your proposed fix anyways.
Comment #3 by smjg — 2009-07-17T12:35:45Z
(In reply to comment #2) >> Given that opIndexAssign doesn't occur in your code, removing >> opIndexAssign from the language isn't going to magically make this >> work. > > I don't see why not. "a[1, 1] = 42;" should just become > "a.opIndex(1, 1) = 42;" rather than do something special because > the "=" is there. Welcome to D. The expansion of a given expression form is by no means fixed. Already an example of this is that many operators can be overloaded either by the left operand's type (using the regular op* methods) or the right operand's type (using the op*_r methods). In the same way, the existence of opIndexAssign does nothing whatsoever to prevent the compiler from expanding it to something else instead if the type in question has no opIndexAssign. And even then, that something else would have to be implemented, which is another piece of work. > I am under the impression that opIndexAssign is there only because > return by reference was not available at the time of designing > operator overloads. That's one reason. The other reason is that it can do many things that a ref return can't, such as - converting the value to an internal representation - validating the set value - calling some external API to set the value - triggering side effects beyond setting the value in memory It's the exact same reason that we have properties.
Comment #4 by schveiguy — 2009-07-17T12:55:21Z
(In reply to comment #3) > That's one reason. The other reason is that it can do many things that a ref > return can't, such as > - converting the value to an internal representation > - validating the set value > - calling some external API to set the value > - triggering side effects beyond setting the value in memory All of these things are doable from a returned struct which contains opAssign. I agree with the reporter that opIndexAssign is a feature that we could do without, although you are correct in that removing opIndexAssign doesn't solve his problem.
Comment #5 by k-foley — 2009-07-17T13:19:31Z
(In reply to comment #3) > Welcome to D. Thank you :) > In the same way, the existence of > opIndexAssign does nothing whatsoever to prevent the compiler from expanding it > to something else instead if the type in question has no opIndexAssign. What else could it be? > > I am under the impression that opIndexAssign is there only because > > return by reference was not available at the time of designing > > operator overloads. > > That's one reason. The other reason is that it can do many things that a ref > return can't, such as > - converting the value to an internal representation > - validating the set value > - calling some external API to set the value > - triggering side effects beyond setting the value in memory > > It's the exact same reason that we have properties. But properties are not operators. If opIndexAssign must exist, then why doesn't, for example, opStarAssign also exist?
Comment #6 by smjg — 2009-07-25T05:03:46Z
(In reply to comment #5) > (In reply to comment #3) >> In the same way, the existence of opIndexAssign does nothing >> whatsoever to prevent the compiler from expanding it to something >> else instead if the type in question has no opIndexAssign. > > What else could it be? The opIndex with ref return already being talked about, of course. > But properties are not operators. If opIndexAssign must exist, > then why doesn't, for example, opStarAssign also exist? To be honest, I'm not sure either. Aside from the fact that "star" doesn't describe the semantics of any D operator, at least it would enable bit pointers that use the same notation as normal pointers.
Comment #7 by dfj1esp02 — 2009-07-27T02:18:02Z
opMulAssign exists and return by ref was meant to solve an unrelated problem, I believe. It's not a replacement for assign operators.
Comment #8 by witold.baryluk+d — 2009-07-27T04:52:22Z
I just want to comment about this controversial issue. I'm using opAssignIndex, and in any way changing it to opIndex + ref return, will make my code impossible to write or very slow. opIndex and opAssignIndex isn't only usefull for arrays!
Comment #9 by k-foley — 2009-07-27T07:43:43Z
(In reply to comment #7) > opMulAssign exists and return by ref was meant to solve an unrelated problem, I > believe. It's not a replacement for assign operators. The problem is that opIndex and opIndexAssign use the same syntax, whereas the others (e.g. opMul and opMulAssign) use a distinct syntax: opMul is * and opMulAssign is *=. Now that ref return is available, I see no reason to keep opIndexAssign around. The added complexity is not necessary.
Comment #10 by schveiguy — 2009-07-27T08:20:13Z
(In reply to comment #7) > opMulAssign exists and return by ref was meant to solve an unrelated problem, I > believe. It's not a replacement for assign operators. You are confusing opMul with opStar. opStarAssign would be for dereferencing. For example: *ptr = 5; And currently it's not necessary, since the return value from opStar is a reference.
Comment #11 by smjg — 2009-07-27T09:22:16Z
(In reply to comment #4) > (In reply to comment #3) >> That's one reason. The other reason is that it can do many things that a ref >> return can't, such as >> - converting the value to an internal representation >> - validating the set value >> - calling some external API to set the value >> - triggering side effects beyond setting the value in memory > > All of these things are doable from a returned struct which contains opAssign. But it would make code unnecessarily complex, and make the compiler have to work harder to optimise it to something as well-performing as a simple opIndexAssign. (In reply to comment #10) > You are confusing opMul with opStar. Yet another reason opStar was the wrong choice of name, besides inconsistency.
Comment #12 by dfj1esp02 — 2009-07-28T02:27:44Z
opStarAssign sounds just like *= so I though it is it.
Comment #13 by witold.baryluk+d — 2010-02-05T05:36:12Z
I again want to say that returning ref is no possible in case of my ussages opIndexAssign. For example I would like to log assigments. Or keep internal caching system. Also it is possible that i have datastructure which needs to know size of the object (string) which i put there, to allocate and rebalance this datastructure. When i would return ref, it would not be possible to perform any such thinkg. Leave opIndexAssign it is very usefull.
Comment #14 by witold.baryluk+d — 2010-02-05T05:41:54Z
(In reply to comment #11) > (In reply to comment #4) > > (In reply to comment #3) > >> That's one reason. The other reason is that it can do many things that a ref > >> return can't, such as > >> - converting the value to an internal representation > >> - validating the set value > >> - calling some external API to set the value > >> - triggering side effects beyond setting the value in memory > > > > All of these things are doable from a returned struct which contains opAssign. > > But it would make code unnecessarily complex, and make the compiler have to > work harder to optimise it to something as well-performing as a simple > opIndexAssign. Well only real problem with opIndexAssign is code duplication and return value of opIndexAssign. But this is easly solved: - duplicated code can be easly moved to private auxilary method used both by opIndex and opIndexAssign - return value can be void if one doesn't want to use chaining (a[2] = a[3] = 5 will be then invalid, becuase (a[3] = 5) have no value). Other solution is to use opIndexAssign for assigment if it is implemented, then try opIndex and check if it returns ref, if yes, perform opIndex + returned ref dereferencing assigment, if both is not possible emit compile error. If automatisation is not good, label opIndex by some kind of property (@implicitIndexAssign ?) > > (In reply to comment #10) > > You are confusing opMul with opStar. > > Yet another reason opStar was the wrong choice of name, besides inconsistency. Bad name indeed.
Comment #15 by andrei — 2011-01-08T22:03:26Z
Fixed in the new design.