August 21, 2002
Walter wrote:

> "Burton Radons" <loth@users.sourceforge.net> wrote in message
> news:3D63BB45.3040706@users.sourceforge.net...
> 
>>I don't have a problem with making this change, but I think it should be
>>consistent or it'll cause more confusion than enlightenment.  Always
>>returning float from cmp is actually helpful, since it can then be used
>>if eq isn't provided, which it almost universally won't be, and it
>>handles "long - long" properly.  Better yet would be to remove eq and
>>see how many complaints there are.
>>
> 
> Always returning float has a problem for embedded systems which may want to
> use an integer-only subset of D, and also it would be a problem in general
> for machines which have arbitrarilly slow floating point.


Uh, okay, but if float is supported in comparison then float will be used practically everywhere, and the embedded problem is not eased at all.

Besides which, this is poppycock.  Comparison against zero is a trivial operation whether you have hardware support or not.

Zero: v == 0
Negative: v & 0x80000000
NaN: (v & 0x7FFF0000) == 0x7FFF0000 && (v & 0xFFFF)
Positive: none of the above

I'm sure that bit twiddlers could bring that down to fewer operations, but it's clearly not of any consequence.


> The reason for a separate eq from cmp is that for many objects there is no
> concept of "less than", although there is a concept for "equals".

In which case they'll only return 0 or float.nan.

August 22, 2002
On Wed, 21 Aug 2002 14:27:33 -0700, "Walter" <walter@digitalmars.com> wrote:

>
>"Toyotomi" <io219@attbi.com> wrote in message news:oll7mu4nat45gi1gjfvslh7mriv0b3jer7@4ax.com...
>> I'm scared of voting... it's too much like a committee...
>
>I think democratically designed languages tend to be failures <g>. Nevertheless, ignoring feedback from users is equally perilous. These kinds of discussions help me to understand what things are important and what are not.
>

Glad you see the first bit that way.
Ignoring is a bit _less_ perilous in my opinion though. ;-p

I think I can see I don't have too much to fear. Thanks.
August 22, 2002
Have cmp() return an enum:

enum CmpResult
{
    LessThan = -1,
    EqualTo = 0,
    GreaterThan = 1,
    Undefined = 1<<31,
}

So this will work:

float a = sqrt(-1); // generate NaN
float b = 1;
if (a.cmp(b) != 0)
    printf("they're different\n");

Using the old cmpresult < 0 and cmpresult > 0 checks will mistakenly think that NaN comparisons are less than, but that shouldn't be a big problem. And we can leave cmp() defined to return int.

Sean

"Pavel Minayev" <evilone@omen.ru> wrote in message
news:CFN374900566370602@news.digitalmars.com...
On Wed, 21 Aug 2002 22:11:45 +0100 "Martin M. Pedersen"
<mmp@www.moeller-pedersen.dk> wrote:

> If floating point isn't supported by hardware, it would cause a major performance hit.

Then, let's define a standard "fp-comparison" interface in object.d:

interface CompareFP
{
float cmp();
}

Now process() would be:

process(CompareFP a, CompareFP b)
{
...
}

And all problems are gone.


August 22, 2002
On Thu, 22 Aug 2002 10:26:54 -0700 "Sean L. Palmer" <seanpalmer@earthlink.net> wrote:

> Have cmp() return an enum:
> 
> enum CmpResult
> {
>     LessThan = -1,
>     EqualTo = 0,
>     GreaterThan = 1,
>     Undefined = 1<<31,
> }

A nice idea.
August 22, 2002
Hi,

"Pavel Minayev" <evilone@omen.ru> wrote in message news:CFN374909708268634@news.digitalmars.com...
> > enum CmpResult
> A nice idea.

I agree.

Regards,
Martin M. Pedersen



August 23, 2002
"Burton Radons" <loth@users.sourceforge.net> wrote in message news:3D640B7D.5000603@users.sourceforge.net...
> > Always returning float has a problem for embedded systems which may want
to
> > use an integer-only subset of D, and also it would be a problem in
general
> > for machines which have arbitrarilly slow floating point.
> Uh, okay, but if float is supported in comparison then float will be
> used practically everywhere, and the embedded problem is not eased at all.

Float is only necessary for supporting NaN comparisons. Other comparisons most likely will stick to simple int returns of <0, 0, or >0.

> Besides which, this is poppycock.  Comparison against zero is a trivial operation whether you have hardware support or not.
>
> Zero: v == 0
> Negative: v & 0x80000000
> NaN: (v & 0x7FFF0000) == 0x7FFF0000 && (v & 0xFFFF)
> Positive: none of the above
> I'm sure that bit twiddlers could bring that down to fewer operations,
> but it's clearly not of any consequence.

I disagree, in loops especially it can be extremely sensitive to comparison time.



August 23, 2002
"Sean L. Palmer" <seanpalmer@earthlink.net> wrote in message news:ak36cs$23d7$1@digitaldaemon.com...
> Have cmp() return an enum:
>
> enum CmpResult
> {
>     LessThan = -1,
>     EqualTo = 0,
>     GreaterThan = 1,
>     Undefined = 1<<31,
> }
>
> So this will work:
>
> float a = sqrt(-1); // generate NaN
> float b = 1;
> if (a.cmp(b) != 0)
>     printf("they're different\n");
>
> Using the old cmpresult < 0 and cmpresult > 0 checks will mistakenly think that NaN comparisons are less than, but that shouldn't be a big problem. And we can leave cmp() defined to return int.

The behavior of < and > is defined for NaNs, so there would have two be two comparisons for every cmp. The CPU handles this by setting the P flag for NaN comparisons, but that isn't accessible to functions.


November 14, 2003
Should we vote this again? I mean, there're some complaining about how overloaded operators should work...

"Burton Radons" <loth@users.sourceforge.net> wrote in message
news:3D5278B0.1000508@users.sourceforge.net...
| I've accidentally implemented operator overloading in my port.  It was
| kind of incidental to other work, so I thought "what the hell" and threw
| it in.  But this brings up the whole issue of syntax, and I think that
| should be voted on to specify the syntax on my side and to influence
| Walter when he decides to do this topic.
|
| I'd like Apache-style voting to be used, where the voting is either -1,
| -0, 0, +0, or +1 for any option, which is a good bellweather of how
| people think about something.
|
| First off, the naming scheme:
|
| 1) "add", "mul", "div", etc.  (my vote: +1)
|
|      Vector mul (Vector b);
|      Vector div (Vector b);
|
| 2) "op_add", "op_mul", "op_div", etc.  (my vote: +1)
|
|      Vector op_sub (Vector b);
|      Vector op_mod (Vector b);
|
| 3) "operator +".  (my vote: -1)  My vote is because I find this syntax
| confusing in C++, particularly with its wide expressiveness, and I
| admire any syntax which doesn't require a change to tools, as the above
| don't.
|
|      Vector operator + (Vector b);
|
| 4) 'operator "+"'.  (my vote: -0)  For some reason I find this less
| visually disconcerting.
|
|      Vector operator "*" (Vector b);
|
| 5) 'operator (a - b)' or 'operator (this - b)'.  (my vote: +0)  If I had
| to put in any new syntax I would prefer it to be this one.
|
|      static Vector operator (a - b) (Vector a, Vector b);
|
| Now, where overloaded operators are defined:
|
| 1) Operators are normal, possibly virtual methods in classes, normal
| nonvirtual methods in structs (My vote: +1).
|
|      Vector add (Vector b);
|
| 2) Overloaded operators are always static methods with both left and
| right arguments defined (My vote: 0).
|
|      static Vector add (Vector a, Vector b);
|
| 3) Overloaded operators are global functions, using both arguments (My
| vote: -1).
|
|      Vector add (Vector a, Vector b);
|
| 4) Operator overloading shouldn't be put in (My vote: -1).
|
| Now, reverse operator handling, where you want the right-side expression
| to handle the evaluation, such as with the form "int * Vector":
|
| 1) A second set of potential functions (My vote: +1).
|
| 2) Automatic reorganization of the expression.  This makes assumptions
| about what the operators do and can't handle "1 / Vector" (My vote: -1).
|   For example, "1-A" could become "-A+1".
|
| Now for the operations covered.  Please be temperate with your votes -
| operations can be added later, but they can't be removed as easily.
|
| 1) a + b, a - b, a * b, a / b, a % b, -a, +a.  (my vote: +1)
|
| 2) a & b, a | b, a ^ b, ~a, !a.  (my vote: +1)
|
| 3) a++, a--, --a, ++a.  (my vote: 0)
|
| 4) a = b.  (my vote: 0)
|
| 5) a << b, a >> b, a >>> b.  (my vote: +1)
|
| 6) a += b, a -= b, a *= b, a %= b, etc.  (my vote: -1)
|
| 7) new, delete.  (my vote: -0)
|
| 8) a || b, a && b.  (my vote: -1)
|
| 9) explicit a >= b, a > b, a <= b, a < b.  (my vote: -1)
|
| 10) a [b].  (my vote: +1)
|
| 10a) a [b] = c.  (my vote: +0)
|
| 11) a [b .. c].  (my vote: +1)
|
| 12) &a, *a.  (my vote: -1)
|
| 13) a.b, a.b = c.  Retrieve and assign property.  (my vote: +1)  Note
| that this won't allow just anything in b.
|
| 13a) a . b, where b can be any type.  (my vote: -1)
|
| 14) a ? b : c.  (my vote: -1)
|
| 15) a === b, a !== b.  (my vote: 0)
|
| 16) a !<> b, a <> b, a !> b, a !< b, a !<= b, a !>= b.  (my vote: 0)
| IMO this is an eq/cmp combination issue.
|
| 17) a in b.  (my vote: +1)
|
| 18) cast (b) a.  (my vote: -0)  I haven't had any good experiences with
| cast overloading in C++.
|
| 19) (a, b).  (my vote: -1)
|
| And miscellaneous:
|
| 1) Operator overloading should be allowed on basic types as global
| functions.  (my vote: -1)
|
|      int operator "a - b" (int a, int b);
|
| 2) Definition of new operators is allowed.  I'll ignore this one if it
| goes positive.  (my vote: -1)
|
|      Vector operator (this dot b) (Vector b);
|
| 2a) Setting precedence of new operators is allowed.  I'll ignore this
| one if it goes positive.  (my vote: -1)
|
|      operator (a dot b) above (a >= b) below (a * b);
|
| I think that's about it.
|


---

Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.538 / Virus Database: 333 - Release Date: 2003-11-10


November 14, 2003
1) "add", "mul", "div", etc.
-1
it can be used for own functions very nice, wich should NOT be operators then.

2) "op_add", "op_mul", "op_div", etc.  (my vote: +1)
-0
less chance to get used as normal func wich should NOT be operator.. but opAdd
would be the D way then. doesn't mather.. i don't like it

3) "operator +".
+1
definitely best. its an unambiguous name, not to use for anything else.. except
possibly +(a,b) or operator+(a,b).. but the issues of 1) and 2) are not there.

4) 'operator "+"'.
-1
its not an operator on a string token

5) 'operator (a - b)' or 'operator (this - b)'.
0
never seen it before.. and directly the suggested way, -1, but the idea is
something we could think about..
Vector operator(Vector a - Vector b) {
return sub(a,b);
}
_could_ be a nice way..



next:


1) Operators are normal, possibly virtual methods in classes, normal nonvirtual
methods in structs
+1
they _can_ be
2) Overloaded operators are always static methods with both left and right
arguments defined
-1
not always.
3) Overloaded operators are global functions, using both arguments
+1
definitely way to go. if you know oo, if you know encapsulation, you have to
allow that. if not, read more on www.cuj.com (thats the link?).
its the only way to make operators extendable, just "adding another layer". the
whole very dynamic stream concept of c++ would have never worked without that.
and there's more.. (end of text)
4) Operator overloading shouldn't be put in
-2
it definitely has to be in.



next
1) A second set of potential functions
+0
acceptable, the way c++ did it, too
2) Automatic reorganization of the expression.
-1
this defeats the way to define them with new behaviour.

and a new one:
3) specify by some token.. like
Vector operator+ (Vector a,Vector b) reversible {
return add(a,b);
}
(reversible isn't the mathematical term.. but i'm too tierd currently to use my
brain for remembering that term..)
oh, and..
+1
it saves the additional typing. why not?


next



1) a + b, a - b, a * b, a / b, a % b, -a, +a.
+1
2) a & b, a | b, a ^ b, ~a, !a.
!a doesn't fit in this list as the rest are binary ops.. for binary ops:
+1
for !
0
3) a++, a--, --a, ++a.
for --a and ++a, yes. a++,a-- should be autoimplemented.. its just a changing of
the order.. but they can be useful for iterator thingies..
+0
4) a = b.  (my vote: 0)
+0
i think yes.
but as a binary operator, not the way c++ does with possibility of a
constructor, or an operator AType()
void operator = (TypeA a,TypeB b) {
a.set(b);
}
5) a << b, a >> b, a >>> b.  (my vote: +1)
+1
6) a += b, a -= b, a *= b, a %= b, etc.
if we have them, we don't need 1) actually..
+0
7) new, delete.
+1
if the way they are done now.. they can be useful.
8) a || b, a && b.
-1
9) explicit a >= b, a > b, a <= b, a < b
0
i don't need them. but i've seen people who'd like to have them, and for
reasons..
10) a[b].
+1
10a) a[b] = c.
uhm?
11) a[b..c]
+1
12) &a, *a.
-1
13) a.b, a.b = c.
-1 we have properties for such things
14) a ? b : c.  (my vote: -1)
-1
15) a === b, a !== b.
-1
this is defined to be the comparison if its the identical object. not
overloadable.
16) a !<> b, a <> b, a !> b, a !< b, a !<= b, a !>= b.  (my vote: 0)
hm?
-0
17) a in b.
+1
18) cast (b) a.
hm.. hm...
0
19) (a, b).
hm..
-1


next
1) Operator overloading should be allowed on basic types as global functions.
-1
2) Definition of new operators is allowed.  I'll ignore this one if it goes
positive.
-1
2a) Setting precedence of new operators is allowed.  I'll ignore this one if it
goes positive.
+0
actually this could get interesting for the standard operators, too.. but not
that syntax, and it can be dangerous.. but the idea still makes a lot of sence..




(so, final statement:D)

binary operators should be functions, not member functions or anything (but could be, and should be possible to be).

reasoning:

Vector operator*(Vector a,Quaternion q);

that belongs to who? to class Vector? or class Quaternion?. to NONE. its a
mathermatical function on BOTH. it is linking them together with some operation.
but it does not belong to any of those. thus, it should not be member of any.
this helps encapsulation. operator* in this case doesn't have direct access to
Vector and Quaternion. (they both would be structs with public members in THIS
case, but anyways). this means implementation can change, operator doesn't
bother about it.
else, it would say belong to Vector. it would not have the possibility to access
Quaternion. but it could access Vector. this is an unfair situation, and doesn't
make sence.


unary operators should be members. but of course, they don't have to.. reasoning
is, they only belong to one variable of one type, so that fits well..
class Vector {
Vector operator-() {
return negated(this);
}
}




the great thing about having them as global functions is the ability to ADD them afterwards. you get a library, say like a D3DX library. they have nice functions like D3DXMatrixMultiply(D3DXVector* out,D3DXMatrix* m,D3DXVector* in); or similar.

all you need to do then is write..
D3DXVector operator*(D3DXMatrix m,D3DXVector v) {
D3DXVector ret;
D3DXMatrixMultiply(&ret,&m,&v);
return ret;
}

and you added the functionality. without touching the D3DX library at all.



same for say streams..
Stream operator<<(Stream s,Type obj) {
return s<<obj.foo<<obj.bla<<obj.bar;
}


this adds a lot of functionality. a lot of freedom. and a lot of savety. it eases our tasks as well by much..







oh, and you forgot operator() :D


November 14, 2003
I don't care too much about what they're called (although I don't like the current naming conventions much).

What's really important is that operators be not always bound to instances, i.e. we can (and should) declare binary operators as free functions, and we should have the right to do so with unary operators.

I'm not sure it's necessary to vote on this, because I think this will be change that will be forced on D (i.e. on Walter) at some point, as the problems associated with the current approach become too great to ignore.

IMO, if that change does not happen, D will founder

"Carlos Santander B." <carlos8294@msn.com> wrote in message news:bp1fs0$2oat$1@digitaldaemon.com...
> Should we vote this again? I mean, there're some complaining about how overloaded operators should work...
>
> "Burton Radons" <loth@users.sourceforge.net> wrote in message
> news:3D5278B0.1000508@users.sourceforge.net...
> | I've accidentally implemented operator overloading in my port.  It was
> | kind of incidental to other work, so I thought "what the hell" and threw
> | it in.  But this brings up the whole issue of syntax, and I think that
> | should be voted on to specify the syntax on my side and to influence
> | Walter when he decides to do this topic.
> |
> | I'd like Apache-style voting to be used, where the voting is either -1,
> | -0, 0, +0, or +1 for any option, which is a good bellweather of how
> | people think about something.
> |
> | First off, the naming scheme:
> |
> | 1) "add", "mul", "div", etc.  (my vote: +1)
> |
> |      Vector mul (Vector b);
> |      Vector div (Vector b);
> |
> | 2) "op_add", "op_mul", "op_div", etc.  (my vote: +1)
> |
> |      Vector op_sub (Vector b);
> |      Vector op_mod (Vector b);
> |
> | 3) "operator +".  (my vote: -1)  My vote is because I find this syntax
> | confusing in C++, particularly with its wide expressiveness, and I
> | admire any syntax which doesn't require a change to tools, as the above
> | don't.
> |
> |      Vector operator + (Vector b);
> |
> | 4) 'operator "+"'.  (my vote: -0)  For some reason I find this less
> | visually disconcerting.
> |
> |      Vector operator "*" (Vector b);
> |
> | 5) 'operator (a - b)' or 'operator (this - b)'.  (my vote: +0)  If I had
> | to put in any new syntax I would prefer it to be this one.
> |
> |      static Vector operator (a - b) (Vector a, Vector b);
> |
> | Now, where overloaded operators are defined:
> |
> | 1) Operators are normal, possibly virtual methods in classes, normal
> | nonvirtual methods in structs (My vote: +1).
> |
> |      Vector add (Vector b);
> |
> | 2) Overloaded operators are always static methods with both left and
> | right arguments defined (My vote: 0).
> |
> |      static Vector add (Vector a, Vector b);
> |
> | 3) Overloaded operators are global functions, using both arguments (My
> | vote: -1).
> |
> |      Vector add (Vector a, Vector b);
> |
> | 4) Operator overloading shouldn't be put in (My vote: -1).
> |
> | Now, reverse operator handling, where you want the right-side expression
> | to handle the evaluation, such as with the form "int * Vector":
> |
> | 1) A second set of potential functions (My vote: +1).
> |
> | 2) Automatic reorganization of the expression.  This makes assumptions
> | about what the operators do and can't handle "1 / Vector" (My vote: -1).
> |   For example, "1-A" could become "-A+1".
> |
> | Now for the operations covered.  Please be temperate with your votes -
> | operations can be added later, but they can't be removed as easily.
> |
> | 1) a + b, a - b, a * b, a / b, a % b, -a, +a.  (my vote: +1)
> |
> | 2) a & b, a | b, a ^ b, ~a, !a.  (my vote: +1)
> |
> | 3) a++, a--, --a, ++a.  (my vote: 0)
> |
> | 4) a = b.  (my vote: 0)
> |
> | 5) a << b, a >> b, a >>> b.  (my vote: +1)
> |
> | 6) a += b, a -= b, a *= b, a %= b, etc.  (my vote: -1)
> |
> | 7) new, delete.  (my vote: -0)
> |
> | 8) a || b, a && b.  (my vote: -1)
> |
> | 9) explicit a >= b, a > b, a <= b, a < b.  (my vote: -1)
> |
> | 10) a [b].  (my vote: +1)
> |
> | 10a) a [b] = c.  (my vote: +0)
> |
> | 11) a [b .. c].  (my vote: +1)
> |
> | 12) &a, *a.  (my vote: -1)
> |
> | 13) a.b, a.b = c.  Retrieve and assign property.  (my vote: +1)  Note
> | that this won't allow just anything in b.
> |
> | 13a) a . b, where b can be any type.  (my vote: -1)
> |
> | 14) a ? b : c.  (my vote: -1)
> |
> | 15) a === b, a !== b.  (my vote: 0)
> |
> | 16) a !<> b, a <> b, a !> b, a !< b, a !<= b, a !>= b.  (my vote: 0)
> | IMO this is an eq/cmp combination issue.
> |
> | 17) a in b.  (my vote: +1)
> |
> | 18) cast (b) a.  (my vote: -0)  I haven't had any good experiences with
> | cast overloading in C++.
> |
> | 19) (a, b).  (my vote: -1)
> |
> | And miscellaneous:
> |
> | 1) Operator overloading should be allowed on basic types as global
> | functions.  (my vote: -1)
> |
> |      int operator "a - b" (int a, int b);
> |
> | 2) Definition of new operators is allowed.  I'll ignore this one if it
> | goes positive.  (my vote: -1)
> |
> |      Vector operator (this dot b) (Vector b);
> |
> | 2a) Setting precedence of new operators is allowed.  I'll ignore this
> | one if it goes positive.  (my vote: -1)
> |
> |      operator (a dot b) above (a >= b) below (a * b);
> |
> | I think that's about it.
> |
>
>
> ---
>
> Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.538 / Virus Database: 333 - Release Date: 2003-11-10
>
>