[Issue 24554] New: Clarrification for bad codegen on postfix operators
https://issues.dlang.org/show_bug.cgi?id=24554 Issue ID: 24554 Summary: Clarrification for bad codegen on postfix operators Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: normal Priority: P1 Component: dlang.org Assignee: nob...@puremagic.com Reporter: alphaglosi...@gmail.com Johan Engelen asked me on the ldc bug ticket to create a ticket to find out what the specification means. All three compilers have differing behavior. DMD: https://github.com/ldc-developers/ldc/issues/4651 GDC: https://forum.dlang.org/post/zybltjuxkbvtvirzw...@forum.dlang.org ldc fe 2.107 as per run.dlang.org ```d void main() { int d = 42; bool o = d > d++; } ``` ``` define i32 @_Dmain({ i64, ptr } %unnamed) #0 { %d = alloca i32, align 4; [#uses = 4, size/byte = 4] %o = alloca i8, align 1 ; [#uses = 1, size/byte = 1] store i32 42, ptr %d, align 4 %1 = load i32, ptr %d, align 4 ; [#uses = 2] %2 = add i32 %1, 1 ; [#uses = 1] store i32 %2, ptr %d, align 4 %3 = load i32, ptr %d, align 4 ; [#uses = 1] %4 = icmp sgt i32 %3, %1; [#uses = 1] %5 = zext i1 %4 to i8 ; [#uses = 1] store i8 %5, ptr %o, align 1 ret i32 0 } ``` Note; the icmp is after the add, which it shouldn't be. Source: https://twitter.com/marcos_don/status/1787629240550150361 --
[Issue 24510] Perfect forwarding and explicit move should be compiler intrinsic and have operators
https://issues.dlang.org/show_bug.cgi?id=24510 kinke changed: What|Removed |Added CC||ki...@gmx.net --- Comment #1 from kinke --- I agree that these should be intrinsics, mainly because the compiler can handle this much much more efficiently than the template bloat of the current library implementations. But I don't think we need new ugly operators for that, simply keeping the self-explanatory `move` and `forward` names. --
[Issue 24510] Perfect forwarding and explicit move should be compiler intrinsic and have operators
https://issues.dlang.org/show_bug.cgi?id=24510 Bolpat changed: What|Removed |Added CC||qs.il.paperi...@gmail.com --
[Issue 24510] New: Perfect forwarding and explicit move should be compiler intrinsic and have operators
https://issues.dlang.org/show_bug.cgi?id=24510 Issue ID: 24510 Summary: Perfect forwarding and explicit move should be compiler intrinsic and have operators Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: enhancement Priority: P1 Component: dmd Assignee: nob...@puremagic.com Reporter: qs.il.paperi...@gmail.com Perfect forwarding parameters of parameters and explicit move requires importing modules (that I have to look up every time and make no sense naming-wise) and is quite unpleasant to look at in code. Last but not least, the current implemenation of explicit move is ctfe-hostile, which makes no sense as the compiler actually can move objects at ctfe. Both operations don’t deserve that; they’re safe and useful. My suggestion would be to make move (and forward, which boils down to either a no-op or an explicit move) a compiler intrinsic. For both of them, there should be unary operators: I suggest `>>` for forward and `<<` for move. ```d f(move(x)); // becomes f(<>xs); // xs can be a pack! ``` They’re both unary prefix operators with the same precedence as the other unary prefix operators. Rationale for the operator symbols: They look very much alike, but that’s happenstance. `>>` looks like the the "fast forward" icon. `<<` looks like an arrow pointing away from the object and indicates: "Whatever is in here goes out of it." --
[Issue 11500] Bringing mixed-in operators and constructors to the overload set
https://issues.dlang.org/show_bug.cgi?id=11500 Iain Buclaw changed: What|Removed |Added Priority|P2 |P3 --
[Issue 11094] Disuniform error messages with overloaded + and ^ operators
https://issues.dlang.org/show_bug.cgi?id=11094 Iain Buclaw changed: What|Removed |Added Priority|P2 |P3 --
[Issue 9786] Allow [non-member|UFCS] implementation of operators
https://issues.dlang.org/show_bug.cgi?id=9786 Iain Buclaw changed: What|Removed |Added Priority|P2 |P4 --
[Issue 14364] Spec is incorrect for opAssign operators.
https://issues.dlang.org/show_bug.cgi?id=14364 Iain Buclaw changed: What|Removed |Added Priority|P1 |P3 --
[Issue 12559] Multi operators with template mixins produces an error
https://issues.dlang.org/show_bug.cgi?id=12559 Iain Buclaw changed: What|Removed |Added Priority|P1 |P3 --
[Issue 21124] Multiple templated is expressions used with logical operators
https://issues.dlang.org/show_bug.cgi?id=21124 Iain Buclaw changed: What|Removed |Added Priority|P1 |P4 --
Re: Blog post on keeping D1 operators for D 2.100
On Saturday, 11 June 2022 at 21:57:36 UTC, Steven Schveighoffer wrote: https://www.schveiguy.com/blog/2022/06/how-to-keep-using-d1-operator-overloads/ -Steve `Good article `,and [chinese version](https://fqbqrr.blog.csdn.net/article/details/125265063)
Blog post on keeping D1 operators for D 2.100
D 2.100.0 removed support for D1 operator overloads. If you have a bunch of code that still uses them, and don't want to spend the time to upgrade to D2 overloads, you can still do it, using a mixin. Here's how it works (and shows off some cool metaprogramming features of D): https://www.schveiguy.com/blog/2022/06/how-to-keep-using-d1-operator-overloads/ -Steve
[Issue 11094] Disuniform error messages with overloaded + and ^ operators
https://issues.dlang.org/show_bug.cgi?id=11094 Ben changed: What|Removed |Added CC||ben.james.jo...@gmail.com --- Comment #2 from Ben --- I took a look at this, and the difference seems to be related to the extra check(s) added at the end of the expressionsem visitors for AddExp vs XorExp: //in xor only if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) return setError(); A couple of questions. This happens earlier in the visitor: Expression e = exp.op_overload(sc); if (e) { result = e; return; } I assume e is null if the op overload doesn't apply (in this case there are constness issues), but putting an error in opover.visitBin seems like maybe the wrong fix? Those extra checks make sense for xor, is it worth trying to add a supplemental error or something that sees if they tried to do op overloading? There's a TON of duplication between the addexp and xorexp visitors in expressionsem, and I assume probably with most binop visitors. Is it worth trying to refactor to reduce the duplication? --
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 17:59:12 UTC, Adam D Ruppe wrote: ooh yeah there's multiple here so the names don't overload and one on the time itself would override the ones from mixin template. You'd have to alias them together on the type. Hello Adam D Ruppe, I see what you mean, thank you very much for your answers! -FA
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 17:33:28 UTC, Steven Schveighoffer wrote: As I mentioned elsewhere, it does work. But the situation I think must be that it's only one mixin template. Probably also you can't have any overloads in the type itself. Note that I also think string mixins would work perfectly fine. And UFCS will never work for operator overloads, but that is by design. -Steve Hello Steve, Thank you very much for your answers, you have been very clear and helpful! -FA
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 16:36:51 UTC, Tejas wrote: Looks like a compiler bug, since substituting the real methods makes the `mixin template` code compile fine Hi Tejas, Thank you very much for your answer! Also, remove the `const`, otherwise the method will word only on `const` instances even if the bug gets fixed And thank you for this advice: I'll definitely remove the `const`! FA
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 17:33:28 UTC, Steven Schveighoffer wrote: As I mentioned elsewhere, it does work. But the situation I think must be that it's only one mixin template. Probably also you can't have any overloads in the type itself. ooh yeah there's multiple here so the names don't overload and one on the time itself would override the ones from mixin template. You'd have to alias them together on the type.
Re: Mixin Templates and Operators
On 4/6/22 12:52 PM, Adam D Ruppe wrote: On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote: Am I doing something wrong or it is impossible to use mixin templates like that? mixin templates can't bring in operator overloads. The spec doesn't really say this I think, but that's the way it has been for a long time. It only checks for operator overloads on the direct thing itself, no UFCS, no mixin template. As I mentioned elsewhere, it does work. But the situation I think must be that it's only one mixin template. Probably also you can't have any overloads in the type itself. Note that I also think string mixins would work perfectly fine. And UFCS will never work for operator overloads, but that is by design. -Steve
Re: Mixin Templates and Operators
On 4/6/22 6:36 AM, francesco.andreetto wrote: I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error: This seems like a bug in the compiler. You can mixin operator overloads using one mixin template, but not multiple. e.g. raylib-d uses this: https://github.com/schveiguy/raylib-d/blob/89733bab9fd1d3588c14f4aa54b62ad45022a105/source/raymathext.d#L75 I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs. This is different from your original. If I do this, it works: ```d mixin template both(T, R) { R opBinary(string op : "+")(T rhs) const { return R(x + rhs.x, y + rhs.y, z + rhs.z); } T opBinary(string op : "-")(R rhs) const { return T(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin both!(vec, point); } ``` If I don't use the mixin templates and, instead, I overload the operations into the structures everything works. It also works to call `opBinary` directly: ```d vec v1 = p1.opBinary!"-"(p2); ``` Which leads me to believe it's not an ambiguity error, but rather just a straight omission on how the operator overloading works. I think you should file a bug. -Steve
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote: Am I doing something wrong or it is impossible to use mixin templates like that? mixin templates can't bring in operator overloads. The spec doesn't really say this I think, but that's the way it has been for a long time. It only checks for operator overloads on the direct thing itself, no UFCS, no mixin template.
Re: Mixin Templates and Operators
On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote: I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error: ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` The output of `dub run` is ``` Performing "debug" build using /usr/bin/dmd for x86_64. query ~master: building configuration "application"... source/app.d(27,13): Error: incompatible types for `(p1) - (p2)`: both operands are of type `point` source/app.d(30,15): Error: incompatible types for `(p1) + (v2)`: `point` and `vec` /usr/bin/dmd failed with exit code 1. ``` I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs. If I don't use the mixin templates and, instead, I overload the operations into the structures everything works. ```d struct point{ float x, y, z; vec opBinary(string op)(point rhs) const if (op == "-") { return vec(x - rhs.x, y - rhs.y, z - rhs.z); } point opBinary(string op)(vec rhs) const if (op == "+") { return point(x + rhs.x, y + rhs.y, z + rhs.z); } } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` Am I doing something wrong or it is impossible to use mixin templates like that? Looks like a compiler bug, since substituting the real methods makes the `mixin template` code compile fine Also, remove the `const`, otherwise the method will word only on `const` instances even if the bug gets fixed ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1.opBinary!"-"(p2); // made - explicit vec v2 = {2,-1,0}; point p3 = p1.opBinary!"+"(v2); // made + explicit }
Mixin Templates and Operators
I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error: ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` The output of `dub run` is ``` Performing "debug" build using /usr/bin/dmd for x86_64. query ~master: building configuration "application"... source/app.d(27,13): Error: incompatible types for `(p1) - (p2)`: both operands are of type `point` source/app.d(30,15): Error: incompatible types for `(p1) + (v2)`: `point` and `vec` /usr/bin/dmd failed with exit code 1. ``` I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs. If I don't use the mixin templates and, instead, I overload the operations into the structures everything works. ```d struct point{ float x, y, z; vec opBinary(string op)(point rhs) const if (op == "-") { return vec(x - rhs.x, y - rhs.y, z - rhs.z); } point opBinary(string op)(vec rhs) const if (op == "+") { return point(x + rhs.x, y + rhs.y, z + rhs.z); } } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` Am I doing something wrong or it is impossible to use mixin templates like that?
Re: Which operators cannot be overloaded and why not?
On Mon, Sep 13, 2021 at 06:19:20PM +, NonNull via Digitalmars-d-learn wrote: > On Monday, 13 September 2021 at 16:12:34 UTC, H. S. Teoh wrote: > > On Mon, Sep 13, 2021 at 02:12:36PM +, NonNull via > > Digitalmars-d-learn wrote: > > > Which operators cannot be overloaded and why not? > > > > Others have already given the list, so I won't repeat that. > > I didn't see unary &. Maybe others are missing. [...] IIRC, unary & cannot be overloaded for the same reasons &&, ||, and ! cannot be overloaded: it leads to hard-to-understand, hard-to-maintain code. Incidentally, C++ *does* allow overloading of &, ostensibly because some wrapper types might want to use it to become transparent. But one of the consequences of this is that now you need a std::address-of pseudo-operator that *actually* takes an address of something when you *really* mean to take the address of the wrapper object instead of the wrapped object. So & loses its original meaning and has to be replaced by a std:: hack. Which, to me, is abundant proof that overloading & was a bad idea in the first place. // BTW, as an aside, as a example of why every-man-for-himself, wild-wild-west operator overloading in C++ is a bad idea, consider these two lines of C++ code: fun(a, b); gun(a, b); What do they mean? Ostensibly, these are function calls to two template functions, specifying explicit template arguments. Unfortunately, that is not the case: only *one* of these lines is a template function call, the other is something else altogether. But nobody can tell the difference unless they read the entire context, as shown below. (Incidentally, this example also shows why C++'s choice of template syntax was a poor one.) Compile and run with a C++ compiler to find out what the actual behaviour is. --- // Totally evil example of why C++ template syntax and free-for-all // operator overloading is a Bad, Bad Idea. #include struct Bad { }; struct B { }; struct A { Bad operator,(B b) { return Bad(); } }; struct D { }; struct Ugly { D operator>(Bad b) { return D(); } } U; struct Terrible { } T; struct Evil { ~Evil() { std::cout << "Hard drive reformatted." << std::endl; } }; struct Nasty { Evil operator,(D d) { return Evil(); } }; struct Idea { void operator()(A a, B b) { std::cout << "Good idea, data saved." << std::endl; } Nasty operator<(Terrible t) { return Nasty(); } } gun; template void fun(A a, B b) { std::cout << "Have fun!" << std::endl; } int main() { A a; B b; // What do these lines do? fun(a, b); gun(a, b); } --- T -- Your inconsistency is the only consistent thing about you! -- KD
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 16:12:34 UTC, H. S. Teoh wrote: On Mon, Sep 13, 2021 at 02:12:36PM +, NonNull via Digitalmars-d-learn wrote: Which operators cannot be overloaded and why not? Others have already given the list, so I won't repeat that. I didn't see unary &. Maybe others are missing. As to the "why": In general, D tries to avoid the wild wild west, every operator for himself situation in C++ that leads to unreadable, unmaintainable code. Thanks for this explanation. The consolidation you mention is great!
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 18:06:42 UTC, NonNull wrote: On Monday, 13 September 2021 at 14:42:42 UTC, jfondren wrote: On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: - condition al expression ` cond ? exp : exp ` And many other boolean operators, unary !, binary && and || https://dlang.org/spec/operatoroverloading.html lists all the overloadable operators, and https://dlang.org/spec/expression.html has all the operators, so "which operators" is a matter of close comparison. Is there no list of such in an article online? It would be good if that work was done for once and for all, with a short explanation in each case, possibly with discussion in some cases of how to achieve results by other means. well this whole thread is certainly the raw material for an article (or D blog post) on D operator overloads. Just, someone has to compile the informations and write the said article.
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 14:42:42 UTC, jfondren wrote: On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: - condition al expression ` cond ? exp : exp ` And many other boolean operators, unary !, binary && and || https://dlang.org/spec/operatoroverloading.html lists all the overloadable operators, and https://dlang.org/spec/expression.html has all the operators, so "which operators" is a matter of close comparison. Is there no list of such in an article online? It would be good if that work was done for once and for all, with a short explanation in each case, possibly with discussion in some cases of how to achieve results by other means.
Re: Which operators cannot be overloaded and why not?
On Mon, Sep 13, 2021 at 02:12:36PM +, NonNull via Digitalmars-d-learn wrote: > Which operators cannot be overloaded and why not? Others have already given the list, so I won't repeat that. As to the "why": In general, D tries to avoid the wild wild west, every operator for himself situation in C++ that leads to unreadable, unmaintainable code. For example, C++ allows you to separately overload <, <=, ==, >, >=, !=. That means the programmer is free to define == and != in a way completely inconsistent with each other, for example. D solves this by combining == and != into a single operator overload, opEquals, where != is the negation of ==. This ensures == and != are always consistent with each other. Same with <, <=, >, >=: C++ lets you overload each one separately, potentially in a completely inconsistent way with each other, so that somebody reading your code has no idea whether x < y implies y >= x, or whether x < y implies y > x. Again, unreadable code. D solves this by combining all these operators into a single overload: opCmp. This ensures consistency between all of these relative comparison operators. Similarly, prefix ++/-- and postfix ++/-- cannot be separately overloaded; they are combined into a single overload, where postfix ++/--, as in `x++`, is simply rewritten by the compiler to the equivalent of: (){ auto tmp = x; x++; return tmp; }() (Of course, this is just to illustrate the semantics. The compiler doesn't actually create a lambda here.) This ensures that prefix and postfix operators behave in the expected way, so that ++x and x++ don't behave in two wildly different, unrelated ways, like it sometimes happens in C++ code because C++ lets you define separate overloads for them. Combining these operator overloads have the additional benefit that less overloads are needed to implement a numerical type: instead of needing to separately implement ==, !=, <, <=, >, >=, you only have to implement two overloads, opEquals and opCmp, and the compiler takes care of the rest. Similarly, ++ and -- only need to be implement once each, and you'll get the postfix varieties for free. Furthermore, the boolean operators !, &&, || are not directly overloadable. Again, C++ lets you separately overload them, which guarantees that when you see (what looks like) a boolean expression in C++, you have no idea what its true semantics are, because && could mean something completely different from the usual meaning. D doesn't let you overload these operators, thereby ensuring that a boolean expression remains a boolean expression: !, &&, || always have the standard semantics. What D *does* let you do is to define opCast!bool yourself, so that you can define how a user-defined type converts to a bool, which can then participate in the !, &&, || operators in the usual way. In general, the philosophy in D is that operator overloading really should be reserved for number-like (or math-like) objects, and overloaded operators are expected to behave more-or-less like their standard, non-overloaded meanings. Operator overloading of the variety that C++ likes to do, like iostream's <<, >> overloads, are frowned upon, because they obscure the surface meaning of the code and make it hard to understand and maintain. (Incidentally, D *does* allow you to overload '<<' and '>>'. It's just frowned upon to overload them in a way that doesn't in someway represent bit-shifting.) Furthermore, overloaded operators are expected to behave analogously w.r.t. each other, e.g., == and != should behave like opposites of each other; < should not have completely unrelated semantics to >, and so on. T -- The right half of the brain controls the left half of the body. This means that only left-handed people are in their right mind. -- Manoj Srivastava
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 14:59:38 UTC, Paul Backus wrote: On Monday, 13 September 2021 at 14:42:42 UTC, jfondren wrote: On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: - condition al expression ` cond ? exp : exp ` And many other boolean operators, unary !, binary && and || https://dlang.org/spec/operatoroverloading.html lists all the overloadable operators, and https://dlang.org/spec/expression.html has all the operators, so "which operators" is a matter of close comparison. "why not" is much harder to answer. I think the intent is for the boolean operators to be handled via `opCast!bool`. I didn't see it was already suggested and answered the same... but yet that's exactly the case.
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 15:29:05 UTC, user1234 wrote: [...] so this is a bit like the postincr case. i.e "prevent the semantics to be hijacked".
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 14:42:42 UTC, jfondren wrote: On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: - condition al expression ` cond ? exp : exp ` And many other boolean operators, unary !, binary && and || They are all indirectly supported if `opCast` is overloaded: ```d unittest { struct S { bool opCast(T = bool)(){return true;} } S s; assert(s && s); } ``` so this is a bit like the postincr case.
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 14:42:42 UTC, jfondren wrote: On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: - condition al expression ` cond ? exp : exp ` And many other boolean operators, unary !, binary && and || https://dlang.org/spec/operatoroverloading.html lists all the overloadable operators, and https://dlang.org/spec/expression.html has all the operators, so "which operators" is a matter of close comparison. "why not" is much harder to answer. Oh! I have never noticed that `&&` and `||`, despite of being quite "ordinary" binary ops are not overloadable. In [styx](https://styx-lang.gitlab.io/styx/attribute.html#operatorattribute) that works because, although inspired by the D way, in the sense that overloads are implemented in custom types, the selection is done using an expression template ```d struct S { @operator(a && b) function andAnd(T other): auto {return false} } ``` So as long as the expression in the attribute argument looks like a valid expression the stuff is found (and the supprot code in the compiler is super simple), e.g with code in a body: ```d e1 && e2; // look if e1 is an aggregate and if it contains @operator(a && b) e1 + e2; // look if e1 is an aggregate and if it contains @operator(a && b) ``` While D uses specific identifier + templates value param for strings. (note that only the equivalent of D opBinary**Right** works...) anyway. zorry for this off-topic.
Re: Which operators cannot be overloaded and why not?
On 9/13/21 10:47 AM, user1234 wrote: On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: what else ? when you have ```d alias AA1 = int[int]; alias AA2 = AA1[int]; ``` then you can write ```d AA2 aa; aa[0] = [0 : 0]; aa[0][0] = 0; ``` The `[0][0]` cannot be expressed using operator overloads (and a custom map type that implements opIndexAssign).But this case is rather due to the fact that druntime seems to do something a bit unusal here (according to an old discussion that happend once on irc). This is because the compiler calls a different hook depending on the usage of the expression `aa[0]`. Which one it calls is not consistent. There isn't an analog for indexing overloads. A further example: ```d int[int] aa; aa[0]++; // ok void foo(ref int x) {x++;} foo(aa[1]); // range violation ``` -Steve
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 14:42:42 UTC, jfondren wrote: On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: - condition al expression ` cond ? exp : exp ` And many other boolean operators, unary !, binary && and || https://dlang.org/spec/operatoroverloading.html lists all the overloadable operators, and https://dlang.org/spec/expression.html has all the operators, so "which operators" is a matter of close comparison. "why not" is much harder to answer. I think the intent is for the boolean operators to be handled via `opCast!bool`.
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: what else ? when you have ```d alias AA1 = int[int]; alias AA2 = AA1[int]; ``` then you can write ```d AA2 aa; aa[0] = [0 : 0]; aa[0][0] = 0; ``` The `[0][0]` cannot be expressed using operator overloads (and a custom map type that implements opIndexAssign).But this case is rather due to the fact that druntime seems to do something a bit unusal here (according to an old discussion that happend once on irc).
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 14:33:03 UTC, user1234 wrote: - condition al expression ` cond ? exp : exp ` And many other boolean operators, unary !, binary && and || https://dlang.org/spec/operatoroverloading.html lists all the overloadable operators, and https://dlang.org/spec/expression.html has all the operators, so "which operators" is a matter of close comparison. "why not" is much harder to answer.
Re: Which operators cannot be overloaded and why not?
On Monday, 13 September 2021 at 14:12:36 UTC, NonNull wrote: Which operators cannot be overloaded and why not? Let's start the list. - `new` and `delete` Because operators are overloaded in aggregates new was supported but not anymore, the idea is that a an aggregate should not be tied a specific allocator. - post incr/decr See [https://dlang.org/spec/operatoroverloading.html#postincrement_postdecrement_operators](explantations). This is an arbitrary limitation imho but the current way enfore that the side effect is not apllied to the expression result. - condition al expression ` cond ? exp : exp ` No idea why it is not supported... nobody has never complained tho ;) - `typeid` Same... the result of typeid has to be a TypeInfoClass, so there's not much to do... exactness is expected - `is` (identity) could be but I suppose that this stuff needs to be correct to keep code consistent what else ?
Which operators cannot be overloaded and why not?
Which operators cannot be overloaded and why not?
Re: Not allowed to globally overload operators?
On Tuesday, 20 July 2021 at 18:32:26 UTC, Ali Çehreli wrote: On 7/19/21 11:20 PM, Tejas wrote: > trying to create the spaceship operator of C++ Just to make sure, D's opCmp returns an int. That new C++ operator was added to provide the same semantics. Ali I know. As I already mentioned, I just wanted the ```<=>``` symbol :(
Re: Not allowed to globally overload operators?
On 7/20/21 11:49 AM, H. S. Teoh wrote: > On Tue, Jul 20, 2021 at 11:32:26AM -0700, Ali Çehreli via Digitalmars-d-learn wrote: >> On 7/19/21 11:20 PM, Tejas wrote: >> >>> trying to create the spaceship operator of C++ >> >> Just to make sure, D's opCmp returns an int. That new C++ operator was >> added to provide the same semantics. > [...] > > FYI, opCmp *may* return float, which may be useful sometimes for > implementing partial orders (return float.nan when two elements are > incomparable). Thanks. For that matter, opCmp can return a UDT (and bool as well as demonstarted below) but then the UDT cannot know what to do in its opCmp: :) import std.stdio; void main() { S a, b; auto result = a < b; // The operator above is reduced to the following: // // a.opCmp(b) < 0; // // (It would be 'a.opCmp(b) >= 0' if we used the >= operator, etc.) // // But because the result of opCmp is an O object in this code // (let's call it 'o'), the reduction is applied to 'o < 0' as well: // // o.opCmp(0); // // where, O.opCmp will receive a 0 'int' value but will never know // operator context we are in. (<, >=, etc.) } struct S { // Weirdly returns an O. O opCmp(const S that) { return O(); } } struct O { bool opCmp(int result) { // result will always be '0' in the case of reduction because it // will be the 0 used in code reduction by dmd. // We might be able to do something here but we don't know the // operator context. Are we inside <, >=, etc? // Extra credit: This is similar to being able to return float.nan // but I can't decipher the semantics at this time. :) return true; } } Ali
Re: Not allowed to globally overload operators?
On Tuesday, 20 July 2021 at 18:49:07 UTC, H. S. Teoh wrote: On Tue, Jul 20, 2021 at 11:32:26AM -0700, Ali Çehreli via Digitalmars-d-learn wrote: On 7/19/21 11:20 PM, Tejas wrote: > trying to create the spaceship operator of C++ Just to make sure, D's opCmp returns an int. That new C++ operator was added to provide the same semantics. [...] FYI, opCmp *may* return float, which may be useful sometimes for implementing partial orders (return float.nan when two elements are incomparable). To be precise about it: `opCmp` must return a value that can be compared with `0` using `<` and `>`. Any integer or floating-point type will satisfy this requirement.
Re: Not allowed to globally overload operators?
On Tue, Jul 20, 2021 at 11:32:26AM -0700, Ali Çehreli via Digitalmars-d-learn wrote: > On 7/19/21 11:20 PM, Tejas wrote: > > > trying to create the spaceship operator of C++ > > Just to make sure, D's opCmp returns an int. That new C++ operator was > added to provide the same semantics. [...] FYI, opCmp *may* return float, which may be useful sometimes for implementing partial orders (return float.nan when two elements are incomparable). T -- "Outlook not so good." That magic 8-ball knows everything! I'll ask about Exchange Server next. -- (Stolen from the net)
Re: Not allowed to globally overload operators?
On 7/19/21 11:20 PM, Tejas wrote: > trying to create the spaceship operator of C++ Just to make sure, D's opCmp returns an int. That new C++ operator was added to provide the same semantics. Ali
Re: Not allowed to globally overload operators?
On Tuesday, 20 July 2021 at 06:34:45 UTC, vit wrote: On Tuesday, 20 July 2021 at 06:20:34 UTC, Tejas wrote: ... Initially, I was trying to create the spaceship operator of C++, but we aren't allowed to create new operators ... D has spaceship operator: opCmp (https://dlang.org/spec/operatoroverloading.html#compare). I know, but I just really wanted the ```<=>``` :(
Re: Not allowed to globally overload operators?
On Tuesday, 20 July 2021 at 06:30:56 UTC, Mike Parker wrote: On Tuesday, 20 July 2021 at 06:20:34 UTC, Tejas wrote: Why isn't it working by default? Initially, I was trying to create the spaceship operator of C++, but we aren't allowed to create new operators, it seems. Then I just wanted to verify whether we can even overload an operator globally, but even that seems to be failing, atleast for me. From the docs: Operator overloading is accomplished by rewriting operators whose operands are class or struct objects into calls to specially named members. https://dlang.org/spec/operatoroverloading.html Note the word "members". Ack. I remember reading the spec but have forgotten that detail multiple times now. See also: https://dlang.org/articles/rationale.html#why-no-global-operator-functions Well, this is new. **sigh** Guess I'll have to find another way to implement spaceship then. I don't disagree with the rationale, but it is a little inconvenient in my case.
Re: Not allowed to globally overload operators?
On Tuesday, 20 July 2021 at 06:20:34 UTC, Tejas wrote: Why isn't it working by default? Initially, I was trying to create the spaceship operator of C++, but we aren't allowed to create new operators, it seems. Then I just wanted to verify whether we can even overload an operator globally, but even that seems to be failing, atleast for me. From the docs: Operator overloading is accomplished by rewriting operators whose operands are class or struct objects into calls to specially named members. https://dlang.org/spec/operatoroverloading.html Note the word "members". See also: https://dlang.org/articles/rationale.html#why-no-global-operator-functions
Re: Not allowed to globally overload operators?
On Tuesday, 20 July 2021 at 06:20:34 UTC, Tejas wrote: ... Initially, I was trying to create the spaceship operator of C++, but we aren't allowed to create new operators ... D has spaceship operator: opCmp (https://dlang.org/spec/operatoroverloading.html#compare).
Not allowed to globally overload operators?
The following doesn't work: ```d import std; int opBinary(string s:"+")(int a, int b){ int result; ab? (result = 1): (result = 0); return result; } void main(){ int f = 1 + 5; writeln(f); } ``` It outputs 6 But if I manually write it as ```d int f = opBinary!"+"(1,5); ``` It works as expected. Why isn't it working by default? Initially, I was trying to create the spaceship operator of C++, but we aren't allowed to create new operators, it seems. Then I just wanted to verify whether we can even overload an operator globally, but even that seems to be failing, atleast for me.
[Issue 2450] Error using operators from named template mixin
https://issues.dlang.org/show_bug.cgi?id=2450 --- Comment #4 from Dlang Bot --- dlang/dmd pull request #12600 "merge stable" was merged into master: - 79a6f7cf9d604eea33b072a9ab30170daeeda696 by Boris Carvajal: Fix Issue 2450 - Error using operators from named template mixin (version 2) https://github.com/dlang/dmd/pull/12600 --
[Issue 2450] Error using operators from named template mixin
https://issues.dlang.org/show_bug.cgi?id=2450 --- Comment #3 from Dlang Bot --- dlang/dmd pull request #12542 "Fix Issue 2450 - Error using operators from named template mixin (version 2)" was merged into stable: - b071e9d04e8db0612d6c3350a6383d7e1ae0eecc by Boris Carvajal: Fix Issue 2450 - Error using operators from named template mixin (version 2) https://github.com/dlang/dmd/pull/12542 --
[Issue 21758] std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and -
https://issues.dlang.org/show_bug.cgi?id=21758 --- Comment #4 from Dlang Bot --- dlang/phobos pull request #8012 "merge stable" was merged into master: - e516ec9351c9897417805a9f2b0839c9c099a97e by Nathan Sashihara: Fix Issue 21758 - std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and - https://github.com/dlang/phobos/pull/8012 --
[Issue 21758] std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and -
https://issues.dlang.org/show_bug.cgi?id=21758 --- Comment #3 from Dlang Bot --- dlang/phobos pull request #7964 "merge stable" was merged into master: - 6f430a7202366c1699618c7fe70f7d7800c7effe by Nathan Sashihara: Fix Issue 21758 - std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and - https://github.com/dlang/phobos/pull/7964 --
Re: How to allow +=, -=, etc operators and keep encapsulation?
On 4/12/21 2:16 PM, Jack wrote: Give this class: ```d class A { int X() { return x; } int X(int v) { return x = v;} private int x; } ``` I'd like to allow use ```+=```, ```-=``` operators on ```X()``` and keep encapsulation. What's a somehow elegant way to do that? It's really hard to do. One problem is lifetime management. There is no way to do something like `ref`, which does not provide a way to make a copy of the original thing (the reference) in @safe code. But the way I'd tackle it is to write a pseudo-reference wrapper that forwards to the getter/setter. I'm sure there's a mixin template solution that works, I just don't have the time to code it out right now. You can take a look at Mike Franklin's unpublished DIP here for inspiration: * [DIP conversation](https://github.com/dlang/DIPs/pull/97) * [DIP text](https://github.com/dlang/DIPs/blob/fdd016a16bf1898fda901b9d716f5bcc6021c1a7/DIPs/DIP1xxx-mvf.md) -Steve
Re: How to allow +=, -=, etc operators and keep encapsulation?
On Monday, 12 April 2021 at 18:16:14 UTC, Jack wrote: Give this class: ```d class A { int X() { return x; } int X(int v) { return x = v;} private int x; } ``` I'd like to allow use ```+=```, ```-=``` operators on ```X()``` and keep encapsulation. What's a somehow elegant way to do that? I assume you know what you are doing, right? In this specific case I would say you can probably stick with it as is since you can have value checks in getter/setter, you can validate and correct values before it mess up the internal state, and calculate X without exposing internal state (today it may be int x, tomorrow you change it to be stored as string, who knows...). But this example doesn't really tell if it's acceptable in what you are trying to achieve. Otherwise: What you need is called abstraction, you provide high level interface to your problem without exposing internal state which is implementation detail, which gives you freedom to modify internal logic without breaking everyone's code that consume your interface. Assuming A is some special scalar type you just implement all operations in a way that makes it only relevant as a whole. Otherwise if you still need to peek on its private members you have leaky abstractions (it is called feature envy).
How to allow +=, -=, etc operators and keep encapsulation?
Give this class: ```d class A { int X() { return x; } int X(int v) { return x = v;} private int x; } ``` I'd like to allow use ```+=```, ```-=``` operators on ```X()``` and keep encapsulation. What's a somehow elegant way to do that?
[Issue 21758] std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and -
https://issues.dlang.org/show_bug.cgi?id=21758 Dlang Bot changed: What|Removed |Added Status|NEW |RESOLVED Resolution|--- |FIXED --- Comment #2 from Dlang Bot --- dlang/phobos pull request #7908 "std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and -" was merged into stable: - 9dc134c8db1f9a547552e471d9b5a5009a6b64b7 by Nathan Sashihara: Fix Issue 21758 - std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and - https://github.com/dlang/phobos/pull/7908 --
[Issue 21758] std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and -
https://issues.dlang.org/show_bug.cgi?id=21758 Dlang Bot changed: What|Removed |Added Keywords||pull --- Comment #1 from Dlang Bot --- @n8sh created dlang/phobos pull request #7908 "std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and -" fixing this issue: - Fix Issue 21758 - std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and - https://github.com/dlang/phobos/pull/7908 --
[Issue 21758] std.experimental.checkedint opBinaryRight with integer left-hand side does not compile for any operators except + and -
https://issues.dlang.org/show_bug.cgi?id=21758 Nathan S. changed: What|Removed |Added Summary|std.experimental.checkedint |std.experimental.checkedint |opBinaryRight with integer |opBinaryRight with integer |left-hand side does not |left-hand side does not |compile for any operations |compile for any operators |except + and - |except + and - --
Re: Unary operators for Variants
On Tuesday, 9 March 2021 at 20:05:07 UTC, Jeff wrote: So, I can't seem to get unary operators to work with variants. For example: Variant x = 10; writeln(-x); // Error: x is not of arithmetic type, it is a VariantN!32LU Obviously binary operators like + work fine. Is there a reason opUnary wasn't implemented as well? Is there a work-around for me to implement it myself outside of the VariantN class? Thanks! Try jsvar https://dpldocs.info/experimental-docs/arsd.jsvar.html
Unary operators for Variants
So, I can't seem to get unary operators to work with variants. For example: Variant x = 10; writeln(-x); // Error: x is not of arithmetic type, it is a VariantN!32LU Obviously binary operators like + work fine. Is there a reason opUnary wasn't implemented as well? Is there a work-around for me to implement it myself outside of the VariantN class? Thanks!
[Issue 21124] New: Multiple templated is expressions used with logical operators
https://issues.dlang.org/show_bug.cgi?id=21124 Issue ID: 21124 Summary: Multiple templated is expressions used with logical operators Product: D Version: D2 Hardware: x86 OS: Linux Status: NEW Severity: enhancement Priority: P1 Component: dmd Assignee: nob...@puremagic.com Reporter: john.michael.h...@gmail.com The code below fails to compile because the template parameter U is in both is statements in isFoo. The code for isFoo2, which changes the U in the second is statement, compiles without error. I see nothing in the specification that would suggest that isFoo should fail to compile, though I may have missed it. Nevertheless, there is a workaround. struct Foo(T) { T x; } struct Foo(T, U) { T x; } enum bool isFoo(T) = is(T : Foo!(U), U) || is(T : Foo!(U, V), U, V); enum bool isFoo2(T) = is(T : Foo!(U), U) || is(T : Foo!(W, V), W, V); void main() { static assert(isFoo!(Foo!(int))); static assert(isFoo!(Foo!(int, int))); static assert(isFoo2!(Foo!(int))); static assert(isFoo2!(Foo!(int, int))); } --
Re: Overload comparison operators for "nullable" types
On Thursday, 30 July 2020 at 14:52:17 UTC, H. S. Teoh wrote: On Thu, Jul 30, 2020 at 01:41:05PM +, Oleg B via Digitalmars-d-learn wrote: [...] Logically we can compare versions, but what must return `opCmp` if one of versions has 'not comparible' state? [...] opCmp is allowed to return float; so you could return float.nan in this case. T Thank you! Simple answer but not in documentation...
Re: Overload comparison operators for "nullable" types
On Thu, Jul 30, 2020 at 01:41:05PM +, Oleg B via Digitalmars-d-learn wrote: [...] > Logically we can compare versions, but what must return `opCmp` if one of > versions has 'not comparible' state? [...] opCmp is allowed to return float; so you could return float.nan in this case. T -- "Real programmers can write assembly code in any language. :-)" -- Larry Wall
Overload comparison operators for "nullable" types
Hello! For example we can imagine struct Version. Version can be old or new and can be 'badly formed' or 'undefined' or other 'not comparible' ('uncompatible') state. Logically we can compare versions, but what must return `opCmp` if one of versions has 'not comparible' state? I think strategy of throwing exception in `opCmp` is bad because some types can be 'not comparible' not because they is `null` or `undefined`, 'not comparible' can be two objects in some working states. If we add `opEquals` we can check 'not comparible' and return `false`, but operators `a <= b` and `a >= b` not expands under the hood as `a < b || a == b`, they only call `opCmp` and if it returns 0 considered arguments are equals. Rewrite `a <= b` as `a < b || a == b` is not intuitive and can get bugs if new user will use code (or old user forgot about this). Checking 'not comparible' state before `a <= b` is not intuitive too. `opBinary` can't overload comparison. We have same type of problem if wrap simple `double` into struct and try overload comparison (double.nan has own behavior). Problem can be solved if we add new `opCmpEx` into language spec that return 4 states: more, less, equal, not equal. Or if we allow `opBinary` overload comparisons. May be I don't understand something important and this problem is not exists? May be in cases where can be 'not comparible' state we should not use overload of comparison operators? But it looks like overloading conception isn't completed and can be improved.
Re: Is it possible to implement operators as ordinary functions?
On Tuesday, 19 May 2020 at 02:42:22 UTC, Adam D. Ruppe wrote: On Tuesday, 19 May 2020 at 02:36:24 UTC, data pulverizer wrote: I was wandering if it possible to implement operators as ordinary functions instead of as member functions of a class or struct for example something like this: nope, it must be done as member functions. Thanks!
Re: Is it possible to implement operators as ordinary functions?
On Tuesday, 19 May 2020 at 02:36:24 UTC, data pulverizer wrote: I was wandering if it possible to implement operators as ordinary functions instead of as member functions of a class or struct for example something like this: nope, it must be done as member functions.
Is it possible to implement operators as ordinary functions?
I was wandering if it possible to implement operators as ordinary functions instead of as member functions of a class or struct for example something like this: ``` import std.stdio: writeln; struct Int{ int data = 0; } Int opBinary(string op)(Int x1, Int x2) { static if((op == "+") || (op == "-") || (op == "*") || (op == "/")) { int ret; mixin("ret = x1.data " ~ op ~ " x2.data"); return ret; }else{ static assert(0, "Operator unknown."); } } void main() { Int x = Int(1); Int y = Int(2); writeln("Output: ", x + y); } ```
Compiler bug ? -preview=intpromote and Integral promotion rules not being followed for unary + - ~ operators
I have a container which provides access to data via a handle. For book keeping I calculate some bitmasks. Previously, when the handle type as well as the constants were uint, everything compiled fine. Today I added a template parameter to be able to specify the handle type and I ran into this problem. I've read the following information on the matter: https://forum.dlang.org/thread/yqfhytyhivltamujd...@forum.dlang.org https://issues.dlang.org/show_bug.cgi?id=18380 https://dlang.org/changelog/2.078.0.html#fix16997 However I still don't see the problem with regards to unsigned types. Why is it necessary to promote a ushort or ubyte to int for the purpose of shifting or the one's complement ? At least the code at the bottom of the post seems to produce correct results. One problem I see with the bug fix is that, AFAIK, the int type in C is not a fixed bit type like it is in D where it is defined to be 32 bit and therefore casting to int in D can't really reproduce the C behavior. What am I missing ? Back to my container. * Using a 32 bit type, i.e. uint, everything compiles fine. * Using a 16 or 8 bit type, i.e. ushort and ubyte, the compiler complains with -preview=intpromote for the pragmas and errors out on assignments of the same types. i.e. e.g. alias handle_t = ushort; enum handle_t MASK = 0x8000; handle_t handle = ~MASK; // the error message is basically: [value is promoted to int and] 32769 can't be assigned to ushort * Using a 64 bit type, i.e. ulong, the whole thing blows up because the compiler pro-, or rather, demotes the ulong to int and int << 40 is obviously violating a constraint of 0..31 for 32bit types. void main() { import std.conv: to; import std.stdio; alias t = ushort; enum t m = 0x8000; pragma (msg, m.to!string(16)); pragma (msg, (~m).to!string(16)); pragma (msg, (cast(int)m).to!string(16)); pragma (msg, (~cast(int)m).to!string(16)); } 2.063 : Success with output: - 8000 7FFF 8000 7FFF - 2.064 to 2.077.1: Success with output: - 8000 7FFF 8000 7FFF - 2.078.1 to 2.084.1: Success with output: - 8000 onlineapp.d(8): Deprecation: integral promotion not done for `~cast(ushort)32768u`, use '-transition=intpromote' switch or `~cast(int)(cast(ushort)32768u)` 7FFF 8000 7FFF - Apart from the fact that I end up with an int, which causes all kinds of havoc and the annoyance that i need to cast a ushort to ushort to be able to assign it to a ushort, it appears to me that all the results are correct.
[Issue 11964] Poor diagnostic in static assert with boolean operators
https://issues.dlang.org/show_bug.cgi?id=11964 Basile-z changed: What|Removed |Added CC|b2.t...@gmx.com | --
[Issue 11964] Poor diagnostic in static assert with boolean operators
https://issues.dlang.org/show_bug.cgi?id=11964 Basile-z changed: What|Removed |Added Keywords||diagnostic Status|NEW |RESOLVED CC||b2.t...@gmx.com Resolution|--- |WORKSFORME --- Comment #3 from Basile-z --- The original expression is maintained now Error: static assert: `1 < 0 && (a < b) && (b < c)` is false --
[Issue 1974] overloaded assignment operators work on non-lvalues
https://issues.dlang.org/show_bug.cgi?id=1974 RazvanN changed: What|Removed |Added Status|NEW |RESOLVED Resolution|--- |INVALID --- Comment #2 from RazvanN --- Closing on the basis of: https://forum.dlang.org/post/hyacdnjwraldlnmdl...@forum.dlang.org --
[Issue 20210] version blocks with boolean operators
https://issues.dlang.org/show_bug.cgi?id=20210 anonymous4 changed: What|Removed |Added Status|NEW |RESOLVED Resolution|--- |DUPLICATE --- Comment #2 from anonymous4 --- see workaround in issue 19495 *** This issue has been marked as a duplicate of issue 7417 *** --
[Issue 2450] Error using operators from named template mixin
https://issues.dlang.org/show_bug.cgi?id=2450 Dlang Bot changed: What|Removed |Added Status|NEW |RESOLVED Resolution|--- |FIXED --- Comment #2 from Dlang Bot --- dlang/dmd pull request #10406 "Fix Issue 2450 - Error using operators from named template mixin" was merged into master: - dd79b0cb45ef8686978f6b5896cb829af8120ff7 by RazvanN7: Fix Issue 2450 - Error using operators from named template mixin https://github.com/dlang/dmd/pull/10406 --
[Issue 2450] Error using operators from named template mixin
https://issues.dlang.org/show_bug.cgi?id=2450 Dlang Bot changed: What|Removed |Added Keywords||pull --- Comment #1 from Dlang Bot --- @RazvanN7 created dlang/dmd pull request #10406 "Fix Issue 2450 - Error using operators from named template mixin" fixing this issue: - Fix Issue 2450 - Error using operators from named template mixin https://github.com/dlang/dmd/pull/10406 --
[Issue 20210] version blocks with boolean operators
https://issues.dlang.org/show_bug.cgi?id=20210 --- Comment #1 from KnightMare --- this issue comes from https://issues.dlang.org/show_bug.cgi?id=20211 where I tried to determine probably existing version "OT:" comes from issue:20211 too. then I decided to split issues. so just ignore "OT:" in header --
[Issue 20210] New: version blocks with boolean operators
https://issues.dlang.org/show_bug.cgi?id=20210 Issue ID: 20210 Summary: version blocks with boolean operators Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: enhancement Priority: P1 Component: dmd Assignee: nob...@puremagic.com Reporter: blac...@bk.ru OT: add to version check blocks some boolean operators cuz next is more clear than indented monster at the bottom version (Dip1000 || DIP1000 || dip1000) { pragma( msg, "D1000"); } else { pragma( msg, "no D1000"); } // current state only supports && and !&& version(A) version(B) { // replacement only for A && B } else { /* !A || !B */ } version (Dip1000) { pragma( msg, "D1000"); // same logic many times } else { version (DIP1000) { pragma( msg, "D1000"); } else { version (dip1000) { pragma( msg, "D1000"); } else { pragma( msg, "no D1000"); } } } --
[Issue 1974] overloaded assignment operators work on non-lvalues
https://issues.dlang.org/show_bug.cgi?id=1974 RazvanN changed: What|Removed |Added CC||razvan.nitu1...@gmail.com --- Comment #1 from RazvanN --- This is a bit problematic because there are 2 points of view on this: 1. From a high-level point of view, the bug report is valid, you are trying to assign to an rvalue (x.test() = x.test() + 1337) which should an error. 2. From a lowering point of view you are basically calling the member function of a temporary object (x.test.opAddAssign(1337)), which by the current rules is valid behavior. I guess that what could be implemented is something along the lines of: if the opAssign/op*Assign function is pure, then you can error/warn because the call has no effect, otherwise it is possible that the assign function has side effects so calling it is correct. Anyhow, maybe I am over-engineering this? --
Re: Do @property attributes not allow postincrement operators
On Sunday, 14 April 2019 at 02:11:52 UTC, Mike Franklin wrote: On Sunday, 14 April 2019 at 01:54:39 UTC, Jamie wrote: Do @property attributes not allow postincrement operators? ... It's a long standing issue (going on 7 years old) ... I plan on getting to it, but there are other pressing things I'm trying to get out of the way. Mike Thanks Mike -- appears I didn't do a thorough enough search for this behaviour. Looking forward to it being implemented, cheers.
Re: Do @property attributes not allow postincrement operators
On Sunday, 14 April 2019 at 01:54:39 UTC, Jamie wrote: Do @property attributes not allow postincrement operators? import std.stdio; struct Foo { @property bar() { return 10; } @property bar(int x) { writeln(x); } } void main() { Foo foo; writeln(foo.bar); // actually calls foo.bar(); foo.bar = 10; // calls foo.bar(10); // following doesn't work foo.bar++; // would expect this to call foo.bar(foo.bar() + 1); // have to use: foo.bar = foo.bar + 1; writeln(foo.bar); } It's a long standing issue (going on 7 years old) https://issues.dlang.org/show_bug.cgi?id=8006 There's an implementation at https://github.com/dlang/dmd/pull/7079 It requires a DIP, which you can find at https://github.com/dlang/DIPs/pull/97 However, in preparing that DIP other issues were discovered with @property, so we need to create a DIP to fix those issues first. I plan on getting to it, but there are other pressing things I'm trying to get out of the way. Mike
Do @property attributes not allow postincrement operators
Do @property attributes not allow postincrement operators? import std.stdio; struct Foo { @property bar() { return 10; } @property bar(int x) { writeln(x); } } void main() { Foo foo; writeln(foo.bar); // actually calls foo.bar(); foo.bar = 10; // calls foo.bar(10); // following doesn't work foo.bar++; // would expect this to call foo.bar(foo.bar() + 1); // have to use: foo.bar = foo.bar + 1; writeln(foo.bar); }
[Issue 11500] Bringing mixed-in operators and constructors to the overload set
https://issues.dlang.org/show_bug.cgi?id=11500 Basile-z changed: What|Removed |Added See Also||https://issues.dlang.org/sh ||ow_bug.cgi?id=19729 --
[Issue 19200] Variant operators don't overload correctly
https://issues.dlang.org/show_bug.cgi?id=19200 github-bugzi...@puremagic.com changed: What|Removed |Added Status|NEW |RESOLVED Resolution|--- |FIXED --
[Issue 19200] Variant operators don't overload correctly
https://issues.dlang.org/show_bug.cgi?id=19200 --- Comment #1 from github-bugzi...@puremagic.com --- Commits pushed to master at https://github.com/dlang/phobos https://github.com/dlang/phobos/commit/71fc01cc63ee28648bdcd19faf8255c4dfeaf290 Fix issue 19200 https://github.com/dlang/phobos/commit/4873119553666819b4810a1318998eaad7476b08 Merge pull request #6684 from Biotronic/issue-19200 Fix issue 19200 - Variant operators don't overload correctly merged-on-behalf-of: Petar Kirov --
[Issue 19200] New: Variant operators don't overload correctly
https://issues.dlang.org/show_bug.cgi?id=19200 Issue ID: 19200 Summary: Variant operators don't overload correctly Product: D Version: D2 Hardware: x86 OS: Windows Status: NEW Severity: normal Priority: P1 Component: phobos Assignee: nob...@puremagic.com Reporter: simen.kja...@gmail.com There are issues when using Variant with types that have their own overloaded operators: struct S { static int opBinaryRight(string op : "|", T)(T rhs) { return 3; } } unittest { import std.variant; S s; Variant v; auto b = v | s; } std\variant.d(1004): Error: no property min for type S In addition, Variant's operator overloads are of the old kind (opAdd, opMul, and so on). These should be updated anyway. --
Re: Tired by deprecation message for unary operators on 8/16 bit vars ? A simple solution
On Thu, Jun 07, 2018 at 05:02:09PM +, Johan Engelen via Digitalmars-d wrote: > On Thursday, 7 June 2018 at 15:18:49 UTC, H. S. Teoh wrote: > > > > Now all you have to do is to add operator overloading to make the > > wrapper type infectious, and a convenience function that can be > > easily typed, and you get: > > [...] > > I'd like to have this in the stdlib, what are the chances? [...] Just copy-n-paste my code into your local Phobos repo and submit a PR. ;-) T -- Creativity is not an excuse for sloppiness.
Re: Tired by deprecation message for unary operators on 8/16 bit vars ? A simple solution
On Thursday, 7 June 2018 at 15:18:49 UTC, H. S. Teoh wrote: Now all you have to do is to add operator overloading to make the wrapper type infectious, and a convenience function that can be easily typed, and you get: [...] I'd like to have this in the stdlib, what are the chances? -Johan
Re: Tired by deprecation message for unary operators on 8/16 bit vars ? A simple solution
On Thu, Jun 07, 2018 at 03:52:10PM +, Basile B. via Digitalmars-d wrote: > On Thursday, 7 June 2018 at 15:18:49 UTC, H. S. Teoh wrote: > > On Thu, Jun 07, 2018 at 01:42:17PM +, Basile B. via Digitalmars-d > > wrote: > > > [...] > > [...] > > > > You're on the right track. Now all you have to do is to add operator > > overloading to make the wrapper type infectious, and a convenience > > function that can be easily typed, and you get: > > > > [...] > > Yeah nice, but it can be more simply used _just_ when the unary > operator would lead to the message (with ctor: ~SomeType(...). The same deprecation message appears when doing simple arithmetic with narrow int types, like `byte b = cast(byte) 10 + cast(byte) 20;`. The .np wrapper gets rid of all that, with the added bonus of documenting the programmer's intent in the code. T -- English is useful because it is a mess. Since English is a mess, it maps well onto the problem space, which is also a mess, which we call reality. Similarly, Perl was designed to be a mess, though in the nicest of all possible ways. -- Larry Wall
Re: Tired by deprecation message for unary operators on 8/16 bit vars ? A simple solution
On Thursday, 7 June 2018 at 15:18:49 UTC, H. S. Teoh wrote: On Thu, Jun 07, 2018 at 01:42:17PM +, Basile B. via Digitalmars-d wrote: [...] [...] You're on the right track. Now all you have to do is to add operator overloading to make the wrapper type infectious, and a convenience function that can be easily typed, and you get: [...] Yeah nice, but it can be more simply used _just_ when the unary operator would lead to the message (with ctor: ~SomeType(...).
Re: Tired by deprecation message for unary operators on 8/16 bit vars ? A simple solution
On Thu, Jun 07, 2018 at 01:42:17PM +, Basile B. via Digitalmars-d wrote: > I don't know if this is a bug but this works: > > ``` > module runnable; > > struct Byte { byte value; alias value this;} > > void main() > { > {Byte b; auto c = ~b;} // no message > {byte b; auto c = ~b;} // deprecation... > } > ``` [...] You're on the right track. Now all you have to do is to add operator overloading to make the wrapper type infectious, and a convenience function that can be easily typed, and you get: --- /** * Truncating wrapper around built-in narrow ints to work around stupid casts. */ module nopromote; enum isNarrowInt(T) = is(T : int) || is(T : uint); /** * A wrapper around a built-in narrow int that truncates the result of * arithmetic operations to the narrow type, overriding built-in int promotion * rules. */ struct Np(T) if (isNarrowInt!T) { T impl; alias impl this; /** * Truncating binary operator. */ Np opBinary(string op, U)(U u) if (is(typeof((T x, U y) => mixin("x " ~ op ~ " y" { return Np(cast(T) mixin("this.impl " ~ op ~ " u")); } /** * Truncating unary operator. */ Np opUnary(string op)() if (is(typeof((T x) => mixin(op ~ "x" { return Np(cast(T) mixin(op ~ " cast(int) this.impl")); } /** * Infectiousness: any expression containing Np should automatically use Np * operator semantics. */ Np opBinaryRight(string op, U)(U u) if (is(typeof((T x, U y) => mixin("x " ~ op ~ " y" { return Np(cast(T) mixin("u " ~ op ~ " this.impl")); } } /** * Returns: A lightweight wrapped type that overrides built-in arithmetic * operators to always truncate to the given type without promoting to int or * uint. */ auto np(T)(T t) if (isNarrowInt!T) { return Np!T(t); } // Test binary ops @safe unittest { ubyte x = 1; ubyte y = 2; auto z = x.np + y; static assert(is(typeof(z) : ubyte)); assert(z == 3); byte zz = x.np + y; assert(zz == 3); x = 255; z = x.np + y; assert(z == 1); } @safe unittest { byte x = 123; byte y = 5; auto z = x.np + y; static assert(is(typeof(z) : byte)); assert(z == byte.min); byte zz = x.np + y; assert(zz == byte.min); } @safe unittest { import std.random; short x = cast(short) uniform(0, 10); short y = 10; auto z = x.np + y; static assert(is(typeof(z) : short)); assert(z == x + 10); short s = x.np + y; assert(s == x + 10); } // Test unary ops @safe unittest { byte b = 10; auto c = -b.np; static assert(is(typeof(c) : byte)); assert(c == -10); ubyte ub = 16; auto uc = -ub.np; static assert(is(typeof(uc) : ubyte)); assert(uc == 0xF0); } --- T -- Public parking: euphemism for paid parking. -- Flora
Tired by deprecation message for unary operators on 8/16 bit vars ? A simple solution
I don't know if this is a bug but this works: ``` module runnable; struct Byte { byte value; alias value this;} void main() { {Byte b; auto c = ~b;} // no message {byte b; auto c = ~b;} // deprecation... } ``` --- Baz
Re: lazy evaluation of logical operators in enum definition
On Wednesday, 18 April 2018 at 10:19:20 UTC, Atila Neves wrote: On Wednesday, 18 April 2018 at 04:44:23 UTC, Shachar Shemesh wrote: On 17/04/18 13:59, Simen Kjærås wrote: [...] Also, extremely dangerous. Seriously, guys and gals. __traits(compiles) (and its uglier sibling, is(typeof())) should be used *extremely* sparingly. [...] A very good rule of thumb. I've lost of how many times I've had a bug because of __traits(compiles) being false, but not in the way I expected it to be! Let me third that. Although this would not be as big of a problem if we had a way of printing out the values for failed template constraints (isn't this already done for static if now?)
Re: lazy evaluation of logical operators in enum definition
On 18.04.2018 09:18, Walter Bright wrote: On 4/15/2018 10:57 PM, Shachar Shemesh wrote: It seems that the && evaluation does not stop when the first false is found. Evaluation does stop, semantic analysis does not. For example: bool foo() { return 0 && undefined_variable; } does not compile. I'd speculate that most would consider this code compiling successfully as surprising behavior. It would also be difficult to specify, as just when is e1 of (e1 && e2) statically known at compile time (i.e. how much flow analysis is the compiler expected to do to determine this?). His use case is `enum x = 0 && undefined_variable;`, for which at least your second concern does not apply. It is also surprising that a `static if` condition cannot be hoisted out: --- static if(expression){ ... } --- --- // not necessarily the same as the above enum c = expression; static if(c){ ... } --- I think the suggestion is to do lazy semantic analysis for all standalone expressions that need to be evaluated at compile-time (and not just for `static if`/`static assert` conditions).
Re: lazy evaluation of logical operators in enum definition
On Wednesday, 18 April 2018 at 04:44:23 UTC, Shachar Shemesh wrote: On 17/04/18 13:59, Simen Kjærås wrote: [...] Also, extremely dangerous. Seriously, guys and gals. __traits(compiles) (and its uglier sibling, is(typeof())) should be used *extremely* sparingly. [...] A very good rule of thumb. I've lost of how many times I've had a bug because of __traits(compiles) being false, but not in the way I expected it to be!
Re: lazy evaluation of logical operators in enum definition
On 4/15/2018 10:57 PM, Shachar Shemesh wrote: It seems that the && evaluation does not stop when the first false is found. Evaluation does stop, semantic analysis does not. For example: bool foo() { return 0 && undefined_variable; } does not compile. I'd speculate that most would consider this code compiling successfully as surprising behavior. It would also be difficult to specify, as just when is e1 of (e1 && e2) statically known at compile time (i.e. how much flow analysis is the compiler expected to do to determine this?).
Re: lazy evaluation of logical operators in enum definition
On 17/04/18 13:59, Simen Kjærås wrote: There's a kinda neat (and kinda ugly) way to implement prop in one line: enum prop(T) = __traits(compiles, { static assert(T.member == 3); }); Now, that's not the same as short-circuiting, and only useful in some cases, but for those cases, it's useful. Also, extremely dangerous. Seriously, guys and gals. __traits(compiles) (and its uglier sibling, is(typeof())) should be used *extremely* sparingly. The problem is that just about any use of __traits(compiles) I know of is seeking to weed out one particular reason for the compilation failure. There is a known bug in D, however, that the compiler consistently fails to read the programmer's mind. The compiler only knows that the code as provided does not compile, and that in that case you asked for something to happen. The usual outcome is that 80-90% of the times your code does what you expect, but then something comes along that throws you off the beaten track. In those cases, instead of getting an error message, you get one of the sides of the "if", which results in random behavior by your code. If you're lucky, you will get an error message much further down the compilation line, and then start having a fun day of trying to figure out what the !*#()%&!@#)!@( just happened. If you're less lucky, the code will actually compile. My personal rule of thumb is this: If there is *any* way of achieving the result I want without __traits(compiles), do it that way. Shachar
Re: lazy evaluation of logical operators in enum definition
On Monday, 16 April 2018 at 05:57:01 UTC, Shachar Shemesh wrote: Consider the following program: struct S1 { enum member = 3; } struct S2 { enum member = 2; } struct S3 { } enum prop(T) = __traits(hasMember, T, "member") && T.member==3; pragma(msg, prop!S1); pragma(msg, prop!S2); pragma(msg, prop!S3); When compiled, it produces: true false test.d(12): Error: no property member for type S3 test.d(16): Error: template instance `test.prop!(S3)` error instantiating test.d(16):while evaluating pragma(msg, prop!(S3)) If I change the definition of "prop" to: template prop(T) { static if( __traits(hasMember, T, "member") && T.member==3 ) enum prop = true; else enum prop = false; } then everything compiles as expected. It seems that the && evaluation does not stop when the first false is found. There's a kinda neat (and kinda ugly) way to implement prop in one line: enum prop(T) = __traits(compiles, { static assert(T.member == 3); }); Now, that's not the same as short-circuiting, and only useful in some cases, but for those cases, it's useful. -- Simen
Re: lazy evaluation of logical operators in enum definition
On Monday, 16 April 2018 at 05:57:01 UTC, Shachar Shemesh wrote: Consider the following program: struct S1 { enum member = 3; } struct S2 { enum member = 2; } struct S3 { } enum prop(T) = __traits(hasMember, T, "member") && T.member==3; pragma(msg, prop!S1); pragma(msg, prop!S2); pragma(msg, prop!S3); When compiled, it produces: true false test.d(12): Error: no property member for type S3 test.d(16): Error: template instance `test.prop!(S3)` error instantiating test.d(16):while evaluating pragma(msg, prop!(S3)) If I change the definition of "prop" to: template prop(T) { static if( __traits(hasMember, T, "member") && T.member==3 ) enum prop = true; else enum prop = false; } then everything compiles as expected. It seems that the && evaluation does not stop when the first false is found. I think the issue is better illustrated with a function: bool prop(T)() { if (__traits(hasMember, T, "member")) { if (T.member == 3) return true; } return false; } In this function there's no way to tell if the function is going to be executed at compile time or at runtime. Therefore the semantics of the whole function need to be valid. Replacing the `if` with a `static if` would solve the problem, as you mentioned. This works because the semantic analysis of `static if` and CTFE evaluation of a function occurs at different phases in the compiler. This post explains this better and in more detail [1]. The issue is that the compiler will do the semantic analysis of `T.member` before it has run CTFE or constant folding on the expression. Although, one could argue that in your case it's clear that the expression only will be evaluated at compile time, but that's not how the compiler works currently. [1] https://wiki.dlang.org/User:Quickfur/Compile-time_vs._compile-time -- /Jacob Carlborg
Re: lazy evaluation of logical operators in enum definition
On Monday, 16 April 2018 at 05:57:01 UTC, Shachar Shemesh wrote: Consider the following program: struct S1 { enum member = 3; } struct S2 { enum member = 2; } struct S3 { } enum prop(T) = __traits(hasMember, T, "member") && T.member==3; pragma(msg, prop!S1); pragma(msg, prop!S2); pragma(msg, prop!S3); When compiled, it produces: true false test.d(12): Error: no property member for type S3 test.d(16): Error: template instance `test.prop!(S3)` error instantiating test.d(16):while evaluating pragma(msg, prop!(S3)) If I change the definition of "prop" to: template prop(T) { static if( __traits(hasMember, T, "member") && T.member==3 ) enum prop = true; else enum prop = false; } then everything compiles as expected. It seems that the && evaluation does not stop when the first false is found. Hello, i've encountered a similar issue recently (see https://issues.dlang.org/show_bug.cgi?id=18115#c13). There are explanations in the last comments.
lazy evaluation of logical operators in enum definition
Consider the following program: struct S1 { enum member = 3; } struct S2 { enum member = 2; } struct S3 { } enum prop(T) = __traits(hasMember, T, "member") && T.member==3; pragma(msg, prop!S1); pragma(msg, prop!S2); pragma(msg, prop!S3); When compiled, it produces: true false test.d(12): Error: no property member for type S3 test.d(16): Error: template instance `test.prop!(S3)` error instantiating test.d(16):while evaluating pragma(msg, prop!(S3)) If I change the definition of "prop" to: template prop(T) { static if( __traits(hasMember, T, "member") && T.member==3 ) enum prop = true; else enum prop = false; } then everything compiles as expected. It seems that the && evaluation does not stop when the first false is found.
DIP: Binary assignment operators for properties -- Draft Review
The DIP process is on again. I'll be publishing a blog post soon describing the changes and their motivation. In the meantime, the primary candidate to become DIP 1013 [1] needs a good going over for the Draft Review to shake out any structural or technical issues. Please see the new Procedure document [2] for a description of the Draft Review's purpose. Please keep any comments regarding the DIP itself in the PR thread, rather than this announcement thread. Thanks! [1] https://github.com/dlang/DIPs/pull/97 [2] https://github.com/dlang/DIPs/blob/master/PROCEDURE.md#draft-review
[Issue 14489] Deprecate Floating point NCEG operators
https://issues.dlang.org/show_bug.cgi?id=14489 Iain Buclawchanged: What|Removed |Added Status|NEW |RESOLVED CC||ibuc...@gdcproject.org Resolution|--- |FIXED --- Comment #1 from Iain Buclaw --- This has been removed from the spec, and is currently and error in the compiler. Not aware of any "gone" status, but that's outside scope of original issue. --