www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Request - opNot, opOr, opAndAnd

reply Arcane Jill <Arcane_member pathlink.com> writes:
It says in the D manual: "The operators ., &&, ||, ?:, and a few others will
likely never be overloadable".

I now have a class (Bool) which could really benefit from operator overloads for
! ||, and &&.

Walter, is there any reason why they will "likely never be overloadable", beyond
your dislike of not-arithmetic truth values?

Obviously, ||, && and ?: are shortcut operators. In order to preserve this
behavior, it would be necessary for the compiler to rewrite:

       (a || b)

as:
       (a ? a : a.opOrOr(b))

and
       (a && b)

as:
       (a ? a.opAndAnd(b) : a)

and to decree that:
       (a ? b : c)

is valid only if typeof(b) == typeof(c), and effectively does:
       // pseudocode
       B f(A a, B b, B c)
       {
           if (a) return b;
           else return c;
       }

with if (a) working exactly as it does now. This would preserve the shortcut semantics, would be type-safe, and (important to me) would allow my Bool type to do this:
       Bool a, b, c;
       a = b || c;

Jill
Jun 03 2004
next sibling parent reply "Jan-Eric Duden" <jeduden whisset.com> writes:
How about just introducing a _real_ boolean type to D?
Then you don't need the overloads, do you?

-- 
Jan-Eric Duden
"Arcane Jill" <Arcane_member pathlink.com> wrote in message
news:c9mkha$1pbr$1 digitaldaemon.com...
 It says in the D manual: "The operators ., &&, ||, ?:, and a few others

 likely never be overloadable".

 I now have a class (Bool) which could really benefit from operator

 ! ||, and &&.

 Walter, is there any reason why they will "likely never be overloadable",

 your dislike of not-arithmetic truth values?

 Obviously, ||, && and ?: are shortcut operators. In order to preserve this
 behavior, it would be necessary for the compiler to rewrite:

       (a || b)

as:
       (a ? a : a.opOrOr(b))

and
       (a && b)

as:
       (a ? a.opAndAnd(b) : a)

and to decree that:
       (a ? b : c)

is valid only if typeof(b) == typeof(c), and effectively does:
       // pseudocode
       B f(A a, B b, B c)
       {
           if (a) return b;
           else return c;
       }

with if (a) working exactly as it does now. This would preserve the

 semantics, would be type-safe, and (important to me) would allow my Bool

 do this:

       Bool a, b, c;
       a = b || c;

Jill

Jun 03 2004
parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <c9mlgd$1qik$1 digitaldaemon.com>, Jan-Eric Duden says...
How about just introducing a _real_ boolean type to D?
Then you don't need the overloads, do you?

Whom are you asking, Jan-Eric? You replied to me - Arcane Jill. Sorry, but I don't have the power you suggest. It's Walter's compiler, not mine. I can't introduce new types, only new structs, classes and so forth. Same as you. Along with many other people, I asked Walter for a non-arithmetic boolean type a while back. He said no. End of story. Now I'm asking him for some operator overloads so that my new class can work better. Can we just wait until he answers, please? Ta. Jill
Jun 03 2004
parent "Jan-Eric Duden" <jeduden whisset.com> writes:
How about just introducing a _real_ boolean type to D?
Then you don't need the overloads, do you?

Whom are you asking, Jan-Eric? You replied to me - Arcane Jill. Sorry, but

 don't have the power you suggest. It's Walter's compiler, not mine. I

 introduce new types, only new structs, classes and so forth. Same as you.

boolean type, wouldn't you?".
 Along with many other people, I asked Walter for a non-arithmetic boolean

 while back. He said no. End of story. Now I'm asking him for some operator
 overloads so that my new class can work better. Can we just wait until he
 answers, please? Ta.

overloads. Or do you have other good applications for these overloads other than simulating a boolean type? Even if Walter said no once, that doesn't mean that the topic cannot be discussed again.
Jun 03 2004
prev sibling next sibling parent reply Ilya Minkov <minkov cs.tum.edu> writes:
Arcane Jill schrieb:

 I now have a class (Bool) which could really benefit from operator overloads
for
 ! ||, and &&.

Why the hell a CLASS??? Making bool a reference type would make it either nearly unusable, or would be a huge performance penalty! (likely both) You have to make sure you .dup it every time you touch it, unless you want to be changing half of your Bools at random! What's wrong with bit? What's wrong with bool? What's wrong with Matthew's boolean, if you really dislike bit? I'm not sure seem to recall that Bjarne Stroustrup once wrote, that making short-cut operators overloadable was totally useless, or perhaps even dangerous. -eye
Jun 03 2004
next sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <c9mr63$229r$1 digitaldaemon.com>, Ilya Minkov says...
 I now have a class (Bool) which could really benefit from operator overloads
for
 ! ||, and &&.

Why the hell a CLASS??? Making bool a reference type would make it either nearly unusable, or would be a huge performance penalty! (likely both) You have to make sure you .dup it every time you touch it, unless you want to be changing half of your Bools at random!

You are wrong. Please take time to check the facts before criticising my work. You cannot construct nor dup Bools. Period. If anyone is interested in implementation details, I'll be happy to explain, but, please do not make unwarranted assumptions like this. I know what I'm doing. Jill
What's wrong with bit? What's wrong with bool?

Perhaps you missed the recent discussions on this thread? I have no wish to repeat them.
What's wrong with Matthew's boolean, if you really dislike bit?

boolean b = 1; is not a compile error. Bool b = 1; is.
I'm not sure seem to recall that Bjarne Stroustrup once wrote, that 
making short-cut operators overloadable was totally useless, or perhaps 
even dangerous.

Maybe he did. But I just said the opposite, and I have a counterexample to demonstrate it. Jill
Jun 03 2004
parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Arcane Jill wrote:

 In article <c9mr63$229r$1 digitaldaemon.com>, Ilya Minkov says...
 I now have a class (Bool) which could really benefit from operator
 overloads for ! ||, and &&.

Why the hell a CLASS??? Making bool a reference type would make it either nearly unusable, or would be a huge performance penalty! (likely both) You have to make sure you .dup it every time you touch it, unless you want to be changing half of your Bools at random!

You are wrong. Please take time to check the facts before criticising my work. You cannot construct nor dup Bools. Period. If anyone is interested in implementation details, I'll be happy to explain,

I would really be interested there. Maybe it is just my lack imagination, but a class really seem to be a strange tool for that purpose. Class objects are always handled by reference in D. How do you avoid reference semantics for your Bool??
What's wrong with Matthew's boolean, if you really dislike bit?

boolean b = 1; is not a compile error. Bool b = 1; is.

Is that a practical problem? Strong typing is nice if it serves a purpose. Compiler errors are desirable if they prevent bugs. But writing your own Bool because the simple solution allows too much seems a bit pedantic to me?
Jun 03 2004
next sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <c9no4v$bi2$1 digitaldaemon.com>, Norbert Nemec says...
 If anyone is interested in implementation details, I'll be happy to
 explain,

I would really be interested there. Maybe it is just my lack imagination, but a class really seem to be a strange tool for that purpose. Class objects are always handled by reference in D.

Ok - this is a singleton class. When the module is loaded, static this() is run, which constructs the one and only instance of the class. It does this using a super-private hidden type. Once constructed, Bool.TRUE is initialized to be a reference to that singleton, and Bool.FALSE is left uninitialized, and therefore null. If anyone else tries to construct a Bool using new, they will get a compile time error, regardless of how they attempt it. When the compiler encounters a test such as
       if (b)

and b is a reference to a class, then the condition is held to be true if b is non-null, false if b is null. Thus, Bool.TRUE will pass the test, and Bool.FALSE will fail it.
How do you avoid reference semantics for your Bool??

Simple. Just don't de-reference the reference. The reference /is/ the object. The D compiler thinks it's passing around a reference to an object, but actually the reference ITSELF is the thing that gets tested, not whatever it points to. Code like:
       Bool a = Bool.TRUE;
       Bool b = a;

etc., looks like non-reference semantics, but only because I'm passing around an actual reference and playing with it like it was an int. It's just like using (void*) really, except that using a class gives you an elegant syntax for the constants Bool.TRUE and Bool.FALSE;
 boolean b = 1; is not a compile error.
 Bool b = 1; is.

Is that a practical problem? Strong typing is nice if it serves a purpose. Compiler errors are desirable if they prevent bugs. But writing your own Bool because the simple solution allows too much seems a bit pedantic to me?

Personal preference. But how do you define "simple"? It only took me a few minutes to write this. It has taken me way, way longer to talk about it than it took to write it. The way I see it is, if I can write something in ten minutes which gives me strong typing, then, pedantic or no, why not? And I believe it does prevent bugs. I'm still interested to know if || etc. could be overloaded. Thinking about it, I suspect I'm going to get a "no" on that one, in which case - ah well, never mind. Jill
Jun 03 2004
parent Ilya Minkov <Ilya_member pathlink.com> writes:
Ok i see. Sorry.

In article <c9nq61$epk$1 digitaldaemon.com>, Arcane Jill says...
[...]
Jun 04 2004
prev sibling parent Roberto Mariottini <Roberto_member pathlink.com> writes:
In article <c9no4v$bi2$1 digitaldaemon.com>, Norbert Nemec says...
Arcane Jill wrote:

What's wrong with Matthew's boolean, if you really dislike bit?

boolean b = 1; is not a compile error. Bool b = 1; is.

Is that a practical problem? Strong typing is nice if it serves a purpose. Compiler errors are desirable if they prevent bugs. But writing your own Bool because the simple solution allows too much seems a bit pedantic to me?

In C I've found some bugs when a function that used to return a boolean value was changed to return an aritmetic value (normally from a found/not-found value to an index represented by an int or a pointer). Not all the code that looked like: if (find(...)) { .. } was changed to: if (find(...) != -1) { .. } thus leading to bugs. The compiler wouldn't notice the change, that is _logical_ rather than _implementative_. There are many ways to workaround this kind of bugs (such as making the function return 0 or NULL when it before returned FALSE), but it happened again and again for various reasons (inexperienced/lazy/uncollaborative programmers, etc), until we switched to Java. Ciao
Jun 04 2004
prev sibling parent "Matthew" <matthew.hat stlsoft.dot.org> writes:
"Ilya Minkov" <minkov cs.tum.edu> wrote in message
news:c9mr63$229r$1 digitaldaemon.com...
 Arcane Jill schrieb:

 I now have a class (Bool) which could really benefit from operator overloads


 ! ||, and &&.

Why the hell a CLASS??? Making bool a reference type would make it either nearly unusable, or would be a huge performance penalty! (likely both) You have to make sure you .dup it every time you touch it, unless you want to be changing half of your Bools at random! What's wrong with bit? What's wrong with bool? What's wrong with Matthew's boolean, if you really dislike bit? I'm not sure seem to recall that Bjarne Stroustrup once wrote, that making short-cut operators overloadable was totally useless, or perhaps even dangerous.

That's covered in chapter 30 of "Imperfect C++"! :-) Martin the Maudlin Author: "Imperfect C++", Addison-Wesley, 2004 (http://www.imperfectcplusplus.com) Contributing editor, C/C++ Users Journal (http://www.synesis.com.au/articles.html#columns) Director, Synesis Software (www.synesis.com.au) STLSoft moderator (http://www.stlsoft.org) -----------------------------------------------------
Jun 04 2004
prev sibling next sibling parent reply Ben Hinkle <bhinkle4 juno.com> writes:
Arcane Jill wrote:

 It says in the D manual: "The operators ., &&, ||, ?:, and a few others
 will likely never be overloadable".
 
 I now have a class (Bool) which could really benefit from operator
 overloads for ! ||, and &&.
 
 Walter, is there any reason why they will "likely never be overloadable",
 beyond your dislike of not-arithmetic truth values?
 
 Obviously, ||, && and ?: are shortcut operators. In order to preserve this
 behavior, it would be necessary for the compiler to rewrite:
 
       (a || b)

as:
       (a ? a : a.opOrOr(b))

and
       (a && b)

as:
       (a ? a.opAndAnd(b) : a)

and to decree that:
       (a ? b : c)

is valid only if typeof(b) == typeof(c), and effectively does:
       // pseudocode
       B f(A a, B b, B c)
       {
           if (a) return b;
           else return c;
       }

with if (a) working exactly as it does now. This would preserve the shortcut semantics, would be type-safe, and (important to me) would allow my Bool type to do this:
       Bool a, b, c;
       a = b || c;

Jill

I assume the class has two singletons (twotons?),say, True and False, so either you can write a = (b is True) || (c is True); or if there is a cast to bit operator a = Bool(cast(bit)b || cast(bit)c); or if there is a bool property a = Bool(b.bool || c.bool); The first option seems pretty readable to me and doesn't require any operator overloading.
Jun 03 2004
parent Arcane Jill <Arcane_member pathlink.com> writes:
In article <c9n2u7$2d59$1 digitaldaemon.com>, Ben Hinkle says...
I assume the class has two singletons (twotons?)

Just the one.
say, True and False, so

Bool.TRUE is a refence to the singleton's instance. Bool.FALSE is a null reference of the same type.
either you can write
 a = (b is True) || (c is True);

You can write a = b || c;
or if there is a cast to bit operator
 a = Bool(cast(bit)b || cast(bit)c);

Well, I guess it depends on what the type of a is. If a is an int or a bit, you can write a = b || c, because the || operator is defined by D itself to return one of Walter's arithmetic types. My Bools don't auto-convert from ints (that was a design goal, so I can hardly complain about it now), so it gets a bit more awkward if you want to store a D "boolean" expression in a Bool. Basically, you have to do: Bool.test(expression). That's ok for me, but obviously it would be nicer if I could say Bool a = b || c; (where b and c are themselves Bools) - but that would require overloading ||. Hence the request. Of course, ideally, I'd prefer a D-native boolean type, but Walter has said no on that one. So it goes:
 Bool b = Bool.TRUE;
 Bool b = Bool.FALSE;
 Bool b = Bool.Test(x < 5);
 if (b) { ... }

or if there is a bool property
 a = Bool(b.bool || c.bool);

If a was a Bool, it would be:
 a = Bool.test(b || c);

(because I didn't overload static opCall). On the other hand, if a was a bit, you'd have to do:
 bit a = b ? 1 : 0;

The first option seems pretty readable to me and doesn't require any
operator overloading.

Well again, it depends on the type of a. If you want a to be an arithmetic type then no, you don't. If you want a to be anything else, you do. But even having to write Bool a = Bool.test(b || c); is not the end of the world - so even if Walter says no, I can live with it. Basically - I've got my compile-time checks, so I'm happy. All the rest is about trying to get the syntax looking neater. Arcane Jill
Jun 03 2004
prev sibling next sibling parent reply Mike Swieton <mike swieton.net> writes:
On Thu, 03 Jun 2004 07:38:18 +0000, Arcane Jill wrote:

 It says in the D manual: "The operators ., &&, ||, ?:, and a few others will
 likely never be overloadable".
 
 I now have a class (Bool) which could really benefit from operator overloads
for
 ! ||, and &&.

In C++ it is considered extremely bad practice to overload the logical &&/|| operators. The reason is that it is impossible for an overload to allow short-circuit evaluation. I think this is a good reason to not allow it. Mike Swieton __ God made the world and He saw that it was good. Not fair. Not happy. Nor perfect. Good. - Mary Doria Russel, "Children of God"
Jun 03 2004
parent Arcane Jill <Arcane_member pathlink.com> writes:
In article <pan.2004.06.03.22.21.31.708194 swieton.net>, Mike Swieton says...
In C++ it is considered extremely bad practice to overload the logical &&/||
operators. The reason is that it is impossible for an overload to allow
short-circuit evaluation. I think this is a good reason to not allow it.

Yep, I agree, as I don't need it now. Jill
Jun 03 2004
prev sibling parent reply Antti =?iso-8859-1?Q?Syk=E4ri?= <jsykari gamma.hut.fi> writes:
In article <c9mkha$1pbr$1 digitaldaemon.com>, Arcane Jill wrote:
 Obviously, ||, && and ?: are shortcut operators. In order to preserve this
 behavior, it would be necessary for the compiler to rewrite:
 
       (a || b)

as:
       (a ? a : a.opOrOr(b))

and
       (a && b)

as:
       (a ? a.opAndAnd(b) : a)


There must be some reason why they didn't come up with this in C++ and instead went for the scheme that loses the shortcut behavior. Hmmm... you'd need a conversion from the overloading type to 'bool' to resolve the ?: operator... at least in a boolean-wise sane language. (On the other hand, you wouldn't have to write Bool in that language.) _But_ then you could write funny boolean classes for (for instance) fuzzy truth values. And D language would probably be the first language to feature shortcut && and || on a _fuzzy_ truth value! Now how cool is that! -Antti (P.S. I'm only partially joking.)
Jun 06 2004
next sibling parent Kevin Bealer <Kevin_member pathlink.com> writes:
In article <slrncc756f.pd5.jsykari pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?=
says...
In article <c9mkha$1pbr$1 digitaldaemon.com>, Arcane Jill wrote:
 Obviously, ||, && and ?: are shortcut operators. In order to preserve this
 behavior, it would be necessary for the compiler to rewrite:
 
       (a || b)

as:
       (a ? a : a.opOrOr(b))

and
       (a && b)

as:
       (a ? a.opAndAnd(b) : a)


There must be some reason why they didn't come up with this in C++ and instead went for the scheme that loses the shortcut behavior. Hmmm... you'd need a conversion from the overloading type to 'bool' to resolve the ?: operator... at least in a boolean-wise sane language. (On the other hand, you wouldn't have to write Bool in that language.) _But_ then you could write funny boolean classes for (for instance) fuzzy truth values. And D language would probably be the first language to feature shortcut && and || on a _fuzzy_ truth value! Now how cool is that! -Antti (P.S. I'm only partially joking.)

I think the logic goes like this: A && B .. becomes opAndAnd(A,B); A is evaluated. B is evaluated. opAndAnd is executed: A is false... oops, too late to shortcut, we already evaluated B! Function parameters are evaluated before the function is run. "&&" and "||" are flow control operators. Trying to write opAndAnd() is like having a function that evaluates "half-inside" an if statement. --- Now, this could still be done... But it requires a complete reinvention of the function to allow it to call back somehow when it needs the second parameter. In other words, opAndAnd() would tell the language when it was done with B, and the code to evaluate B would be called back, then control returns to opAndAnd. Would doing so break all C and C++ call-compatibility? What if B is a complex function? What if B throws an exception. Also, evaluation of B really has to be done in the original stack frame. It's easy to see why C++ designers just said No, once you understand the implementation issue. A more practical technique is to evaluate A in a "boolean context", whatever that is defined to mean, then shortcut (or not), then evaluate B in a boolean context: this isnt really a "custom" opAndAnd. Kevin
Jun 07 2004
prev sibling parent Kevin Bealer <Kevin_member pathlink.com> writes:
In article <slrncc756f.pd5.jsykari pulu.hut.fi>, Antti =?iso-8859-1?Q?Syk=E4ri?=
says...
In article <c9mkha$1pbr$1 digitaldaemon.com>, Arcane Jill wrote:
 Obviously, ||, && and ?: are shortcut operators. In order to preserve this
 behavior, it would be necessary for the compiler to rewrite:
 
       (a || b)

as:
       (a ? a : a.opOrOr(b))

and
       (a && b)

as:
       (a ? a.opAndAnd(b) : a)


There must be some reason why they didn't come up with this in C++ and instead went for the scheme that loses the shortcut behavior. Hmmm... you'd need a conversion from the overloading type to 'bool' to resolve the ?: operator... at least in a boolean-wise sane language. (On the other hand, you wouldn't have to write Bool in that language.) _But_ then you could write funny boolean classes for (for instance) fuzzy truth values. And D language would probably be the first language to feature shortcut && and || on a _fuzzy_ truth value! Now how cool is that! -Antti (P.S. I'm only partially joking.)

I think the logic goes like this: A && B .. becomes opAndAnd(A,B); A is evaluated. B is evaluated. opAndAnd is executed: A is false... oops, too late to shortcut, we already evaluated B! Function parameters are evaluated before the function is run. "&&" and "||" are flow control operators. Trying to write opAndAnd() is like having a function that evaluates "half-inside" an if statement. --- Now, this could still be done... But it requires a complete reinvention of the function to allow it to call back somehow when it needs the second parameter. In other words, opAndAnd() would tell the language when it was done with B, and the code to evaluate B would be called back, then control returns to opAndAnd. Would doing so break all C and C++ call-compatibility? What if B is a complex function? What if B throws an exception. Also, evaluation of B really has to be done in the original stack frame. It's easy to see why C++ designers just said No, once you understand the implementation issue. A more practical technique is to evaluate A in a "boolean context", whatever that is defined to mean, then shortcut (or not), then evaluate B in a boolean context: this isnt really a "custom" opAndAnd. Kevin
Jun 07 2004