www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Overload of ! operator

reply "Eric" <eric makechip.com> writes:
Is there a way to overload the ! operator?  I can't seem to get
it to work with the standard unaryOp method.  I need this because
I am making a wrapper for a C++ API that has ! overloaded.

-Eric
Jun 25 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Eric:

 Is there a way to overload the ! operator?  I can't seem to get
 it to work with the standard unaryOp method.  I need this 
 because
 I am making a wrapper for a C++ API that has ! overloaded.
D is not a superset of C++ and I think there is no way to overload the ! alone. This is by design. But you can define a "bang" property method. Maybe other people can give you a better answer. Bye, bearophile
Jun 25 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, June 26, 2013 04:50:44 Eric wrote:
 Is there a way to overload the ! operator?  I can't seem to get
 it to work with the standard unaryOp method.  I need this because
 I am making a wrapper for a C++ API that has ! overloaded.
TDPL does not list it as an overloadable operator, so it probably can't be overloaded (especially if you've tried it, and it doesn't work). But you should be able to simply have a wrapper function which is a normal function rather than an overloaded operator. - Jonathan M Davis
Jun 25 2013
prev sibling parent reply "cal" <callumenator gmail.com> writes:
On Wednesday, 26 June 2013 at 02:50:51 UTC, Eric wrote:
 Is there a way to overload the ! operator?  I can't seem to get
 it to work with the standard unaryOp method.  I need this 
 because
 I am making a wrapper for a C++ API that has ! overloaded.

 -Eric
According to http://dlang.org/operatoroverloading.html#Cast, the following are rewritten: if (e) => if (e.opCast!(bool)) if (!e) => if (!e.opCast!(bool)) So perhaps you need to override opCast!(bool).
Jun 25 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, June 26, 2013 05:35:03 cal wrote:
 On Wednesday, 26 June 2013 at 02:50:51 UTC, Eric wrote:
 Is there a way to overload the ! operator?  I can't seem to get
 it to work with the standard unaryOp method.  I need this
 because
 I am making a wrapper for a C++ API that has ! overloaded.
 
 -Eric
According to http://dlang.org/operatoroverloading.html#Cast, the following are rewritten: if (e) => if (e.opCast!(bool)) if (!e) => if (!e.opCast!(bool)) So perhaps you need to override opCast!(bool).
Yeah, that should work for the conditions in if, while, and for loops but won't work for anything else (_maybe_ ternary operators, but I'm not sure). So, if you need to be able to do !obj in the general case, that's not going to work, but if you only need it for conditions, then it would. And of course this all assumes that the C++ code is overloading ! to do something sane with bool rather than redefining it to mean something completely different. - Jonathan M Davis
Jun 25 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/25/2013 09:05 PM, Jonathan M Davis wrote:

 On Wednesday, June 26, 2013 05:35:03 cal wrote:
 On Wednesday, 26 June 2013 at 02:50:51 UTC, Eric wrote:
 Is there a way to overload the ! operator?  I can't seem to get
 it to work with the standard unaryOp method.  I need this
 because
 I am making a wrapper for a C++ API that has ! overloaded.

 -Eric
According to http://dlang.org/operatoroverloading.html#Cast, the following are rewritten: if (e) => if (e.opCast!(bool)) if (!e) => if (!e.opCast!(bool)) So perhaps you need to override opCast!(bool).
Yeah, that should work for the conditions in if, while, and for loops but won't work for anything else (_maybe_ ternary operators, but I'm not
sure). Works for ternary as well. The other option is 'alias this' but it is a little dangerous because bool is an arithmetic type. So, opCast would be better. import std.stdio; struct S { int i; bool truth() const { return i == 42; } alias truth this; } void foo(bool b) { writeln(b); } void main() { auto s = S(42); if (s){ } while (s) { break; } int i = s ? 4 : 5; foo(s); // What does it mean? writeln(s + 2); writeln(!s - 7); }
 So, if you need to be able to do !obj in the general case, that's not 
going to
 work
It surprisingly works both with opCast and 'alias this'. Ali
Jun 25 2013
parent "Eric" <eric makechip.com> writes:
On Wednesday, 26 June 2013 at 04:16:30 UTC, Ali Çehreli wrote:
 On 06/25/2013 09:05 PM, Jonathan M Davis wrote:

 On Wednesday, June 26, 2013 05:35:03 cal wrote:
 On Wednesday, 26 June 2013 at 02:50:51 UTC, Eric wrote:
 Is there a way to overload the ! operator?  I can't seem to
get
 it to work with the standard unaryOp method.  I need this
 because
 I am making a wrapper for a C++ API that has ! overloaded.

 -Eric
According to http://dlang.org/operatoroverloading.html#Cast,
the
 following are rewritten:

 if (e) => if (e.opCast!(bool))
 if (!e) => if (!e.opCast!(bool))

 So perhaps you need to override opCast!(bool).
Yeah, that should work for the conditions in if, while, and
for loops but
 won't work for anything else (_maybe_ ternary operators, but
I'm not sure). Works for ternary as well. The other option is 'alias this' but it is a little dangerous because bool is an arithmetic type. So, opCast would be better. import std.stdio; struct S { int i; bool truth() const { return i == 42; } alias truth this; } void foo(bool b) { writeln(b); } void main() { auto s = S(42); if (s){ } while (s) { break; } int i = s ? 4 : 5; foo(s); // What does it mean? writeln(s + 2); writeln(!s - 7); }
 So, if you need to be able to do !obj in the general case,
that's not going to
 work
It surprisingly works both with opCast and 'alias this'. Ali
Thanks for all the insignt. But I think I'm just going to fudge this one with a "bang()" method... Incidently, for this project I figured out an interesting use of alias. The C++ classes I am wrapping have a lot of virtual methods with all primitive arguments. So I create an D-interface for them, and wrap the rest with C methods. The wrapper class then makes methods that call the C methods, and then aliases the interface reference to "this" so that the wrapper class instance points to both the C++ native methods as well as the C-wrapped methods. -Eric
Jun 25 2013
prev sibling parent reply "cal" <callumenator gmail.com> writes:
On Wednesday, 26 June 2013 at 04:06:05 UTC, Jonathan M Davis 
wrote:
 Yeah, that should work for the conditions in if, while, and for 
 loops but
 won't work for anything else (_maybe_ ternary operators, but 
 I'm not sure).
 So, if you need to be able to do !obj in the general case, 
 that's not going to
 work
... import std.stdio; struct S { int x; bool opCast(T)() if (is(T == bool)) { return x == 0; } } void main() { auto s = S(1); auto b = !s; writeln(b); // true } Is this not supposed to work?
Jun 25 2013
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, June 26, 2013 06:59:14 cal wrote:
 On Wednesday, 26 June 2013 at 04:06:05 UTC, Jonathan M Davis
 
 wrote:
 Yeah, that should work for the conditions in if, while, and for
 loops but
 won't work for anything else (_maybe_ ternary operators, but
 I'm not sure).
 So, if you need to be able to do !obj in the general case,
 that's not going to
 work
... import std.stdio; struct S { int x; bool opCast(T)() if (is(T == bool)) { return x == 0; } } void main() { auto s = S(1); auto b = !s; writeln(b); // true } Is this not supposed to work?
No, it's not. That would require an implicit cast (which requires using alias this). opCast gives you an explicit cast only. Where that becomes confusing is the fact that the compiler inserts explicitly casts to bool in conditions for if statements, loops, and the ternary operator. e.g. if(foo) {...} becomes if(cast(bool)foo) {...} So, if you've overloaded opCast to bool, then it'll get used in the conditions for if statements, loops, and the ternary operator. But no explicit cast is added just for putting ! in front of a variable. It works with something like if(!foo) {...} simply because that becomes if(!cast(bool)foo) {...} But nothing special is done for !, and !a will not call opCast. - Jonathan M Davis
Jun 25 2013
parent reply "cal" <callumenator gmail.com> writes:
On Wednesday, 26 June 2013 at 05:08:07 UTC, Jonathan M Davis 
wrote:
 On Wednesday, June 26, 2013 06:59:14 cal wrote:
 On Wednesday, 26 June 2013 at 04:06:05 UTC, Jonathan M Davis
 
 wrote:
 Yeah, that should work for the conditions in if, while, and 
 for
 loops but
 won't work for anything else (_maybe_ ternary operators, but
 I'm not sure).
 So, if you need to be able to do !obj in the general case,
 that's not going to
 work
... import std.stdio; struct S { int x; bool opCast(T)() if (is(T == bool)) { return x == 0; } } void main() { auto s = S(1); auto b = !s; writeln(b); // true } Is this not supposed to work?
No, it's not. That would require an implicit cast (which requires using alias this). opCast gives you an explicit cast only. Where that becomes confusing is the fact that the compiler inserts explicitly casts to bool in conditions for if statements, loops, and the ternary operator. e.g. if(foo) {...} becomes if(cast(bool)foo) {...} So, if you've overloaded opCast to bool, then it'll get used in the conditions for if statements, loops, and the ternary operator. But no explicit cast is added just for putting ! in front of a variable. It works with something like if(!foo) {...} simply because that becomes if(!cast(bool)foo) {...} But nothing special is done for !, and !a will not call opCast. - Jonathan M Davis
But that code I posted does work, and gives the output shown. Am I misunderstanding?
Jun 25 2013
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, June 26, 2013 07:14:36 cal wrote:
 But that code I posted does work, and gives the output shown. Am
 I misunderstanding?
Then my understanding of how ! is handled is wrong. Apparently !s does get replaced with !cast(bool)s, or it couldn't work. But note that bool b = s; doesn't work, so as I said, it's not the case that opCast gives you an implicit cast. It's just the cases where cases where the compiler inserts an explicit cast for you that it looks like it gives you an implicit cast. But apparently, there was a case that it inserts an explicit cast of which I was not aware. - Jonathan M Davis
Jun 25 2013
prev sibling parent reply "Eric" <eric makechip.com> writes:
On Wednesday, 26 June 2013 at 04:59:19 UTC, cal wrote:
 On Wednesday, 26 June 2013 at 04:06:05 UTC, Jonathan M Davis 
 wrote:
 Yeah, that should work for the conditions in if, while, and 
 for loops but
 won't work for anything else (_maybe_ ternary operators, but 
 I'm not sure).
 So, if you need to be able to do !obj in the general case, 
 that's not going to
 work
... import std.stdio; struct S { int x; bool opCast(T)() if (is(T == bool)) { return x == 0; } } void main() { auto s = S(1); auto b = !s; writeln(b); // true } Is this not supposed to work?
I should have also added that the overloaded ! method returns a class instance and not a bool. -Eric
Jun 25 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, June 26, 2013 07:15:19 Eric wrote:
 I should have also added that the overloaded ! method returns a
 class instance and not a bool.
Well, at that point, you're completely out of luck with regards to overloading !. In general, D doesn't really support overloading operators in a manner that doesn't match how the built-in types work. It does things like assume that <, <=, >=, and > will act the same way that they do with the built-in types and uses opCmp to extrapolate all of those operators. In some cases, you _can_ make overloaded operators return types that make it so that they don't function anything like the built-in types (e.g. opBinary with + could return a completely unrelated type that had nothing to do with the original type or with addition), but in pretty much any case where the compiler can get away with using the same overloaded operator for multiple operators, it does it. So, a number of decisions were made to better support correctness with types that actually try and overload operators to match what the built-in types do without caring about how that would affect types that would try and overload them to do unrelated stuff. - Jonathan M Davis
Jun 25 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 26 June 2013 at 05:29:49 UTC, Jonathan M Davis 
wrote:
 On Wednesday, June 26, 2013 07:15:19 Eric wrote:
 I should have also added that the overloaded ! method returns a
 class instance and not a bool.
Well, at that point, you're completely out of luck with regards to overloading !. In general, D doesn't really support overloading operators in a manner that doesn't match how the built-in types work. It does things like assume that <, <=, >=, and > will act the same way that they do with the built-in types and uses opCmp to extrapolate all of those operators. In some cases, you _can_ make overloaded operators return types that make it so that they don't function anything like the built-in types (e.g. opBinary with + could return a completely unrelated type that had nothing to do with the original type or with addition), but in pretty much any case where the compiler can get away with using the same overloaded operator for multiple operators, it does it. So, a number of decisions were made to better support correctness with types that actually try and overload operators to match what the built-in types do without caring about how that would affect types that would try and overload them to do unrelated stuff. - Jonathan M Davis
Yeah, basically, you define: * opCast(bool) //to test both "true" and "false" * opEqual //test equality (both == and !=) * opCmp //Comparison (< > <= >=) And everything gets defined from these. It also works that way for operators: op++ is defined in terms or ++op. And if you define "op+", then defining op++ becomes entirely optional! This is a cool feature, although there are those *very* rare cases where it gets in your way. For example, the other day, I was trying to implement a "tribool": http://www.boost.org/doc/libs/1_53_0/doc/html/tribool/tutorial.html It did not work, I mean: AT ALL! This is because for a tribool, being "not true" does not imply being "false"...
Jun 25 2013