www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - PROPOSAL: Operator overloading by static member function

reply oldrev <oldrev gmail.com> writes:
It's a simple way to avoid using the ugly "opAdd_r", eg:

struct Currency
{
  private int m_value;

  public static Currency opAdd(Currency lhs, Currency rhs) {
    return Currency(lhs.m_value + rhs.m_value);
  }
}
Oct 13 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
oldrev wrote:
 It's a simple way to avoid using the ugly "opAdd_r", eg:
 
 struct Currency
 {
   private int m_value;
 
   public static Currency opAdd(Currency lhs, Currency rhs) {
     return Currency(lhs.m_value + rhs.m_value);
   }
 }
And how are you going to overload static opAdd_r, then? I really don't see any need for this; opAdd_r is perfectly fine. -- Daniel
Oct 13 2007
parent reply oldrev <oldrev gmail.com> writes:
Daniel Keep Wrote:

 
 
 oldrev wrote:
 It's a simple way to avoid using the ugly "opAdd_r", eg:
 
 struct Currency
 {
   private int m_value;
 
   public static Currency opAdd(Currency lhs, Currency rhs) {
     return Currency(lhs.m_value + rhs.m_value);
   }
 }
And how are you going to overload static opAdd_r, then? I really don't see any need for this; opAdd_r is perfectly fine. -- Daniel
We do not need opAdd_r anymore, it will be overloaded by static opAdd. static A opAdd(A a, int i); static A opAdd(int i, A a); a+100 // it equals to opAdd(a, 100); 100+a //opAdd(100, a) Regards, - oldrev
Oct 13 2007
next sibling parent Nathan Reed <nathaniel.reed gmail.com> writes:
oldrev wrote:
 Daniel Keep Wrote:
 
 oldrev wrote:
 It's a simple way to avoid using the ugly "opAdd_r", eg:

 struct Currency
 {
   private int m_value;

   public static Currency opAdd(Currency lhs, Currency rhs) {
     return Currency(lhs.m_value + rhs.m_value);
   }
 }
And how are you going to overload static opAdd_r, then? I really don't see any need for this; opAdd_r is perfectly fine. -- Daniel
We do not need opAdd_r anymore, it will be overloaded by static opAdd. static A opAdd(A a, int i); static A opAdd(int i, A a); a+100 // it equals to opAdd(a, 100); 100+a //opAdd(100, a) Regards, - oldrev
I like the idea of a non-member function for overloading operators, since the definition looks more symmetric and avoids giving undue 'emphasis' to one of the values involved. On the other hand, this would be a breaking change and I'm not sure it's worth it. Also, one advantage of the current way of doing overloaded operators is that it enforces that operators that are supposed to be commutative, like +, can't be redefined to be noncommutative. Thanks, Nathan Reed
Oct 13 2007
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
oldrev wrote:
 Daniel Keep Wrote:
 
 oldrev wrote:
 It's a simple way to avoid using the ugly "opAdd_r", eg:

 struct Currency
 {
   private int m_value;

   public static Currency opAdd(Currency lhs, Currency rhs) {
     return Currency(lhs.m_value + rhs.m_value);
   }
 }
And how are you going to overload static opAdd_r, then? I really don't see any need for this; opAdd_r is perfectly fine. -- Daniel
We do not need opAdd_r anymore, it will be overloaded by static opAdd. static A opAdd(A a, int i); static A opAdd(int i, A a); a+100 // it equals to opAdd(a, 100); 100+a //opAdd(100, a) Regards, - oldrev
You didn't answer the first question. You haven't said how we're going to do this: struct Meters { real value; } struct m { static Meters opMul_r(real value) { return Meters(value); } } auto distance = 20*m; In your system, there's no way to have that since you can't have type arguments. And *yes*, there are people who use this kind of thing. Also, as Nathan pointed out, this would break basically *all* code that overloads any operators and for what? So we don't have to type "_r" and can no longer have static operator overloads? -- Daniel
Oct 13 2007
next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 10/14/07, Daniel Keep <daniel.keep.lists gmail.com> wrote:
 auto distance = 20*m;
Oh that is cool!
Oct 13 2007
prev sibling next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 10/14/07, Janice Caron <caron800 googlemail.com> wrote:
 On 10/14/07, Daniel Keep <daniel.keep.lists gmail.com> wrote:
 auto distance = 20*m;
Oh that is cool!
I guess you could generalise that... auto area = 100*m*m; auto velocity = 50*m/s; const G = 6.673e-11*m*m*m*/kg/s/s; ...and even do unit conversions... auto distance = 15*miles; /*converts to meters*/ Super duper. OK, I'm all in favor of keeping thing the way they are, coz that's just so brilliant.
Oct 13 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Janice Caron wrote:
 On 10/14/07, Janice Caron <caron800 googlemail.com> wrote:
 On 10/14/07, Daniel Keep <daniel.keep.lists gmail.com> wrote:
 auto distance = 20*m;
Oh that is cool!
I guess you could generalise that... auto area = 100*m*m; auto velocity = 50*m/s; const G = 6.673e-11*m*m*m*/kg/s/s; ....and even do unit conversions... auto distance = 15*miles; /*converts to meters*/ Super duper. OK, I'm all in favor of keeping thing the way they are, coz that's just so brilliant.
I did something similar in Python once (called it "Units") but got caught up on how exactly to encode transforms between different systems. Actually, I believe someone's done something like this for D before. Their goal, however, was *compile-time* checking of units. So, for example, you couldn't do this: auto v = 3*m/s; auto a = 9.81*m/(s*s); auto huh = v+a; -- Daniel
Oct 13 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 10/14/07, Daniel Keep <daniel.keep.lists gmail.com> wrote:
 Actually, I believe someone's done something like this for D before.
 Their goal, however, was *compile-time* checking of units.  So, for
 example, you couldn't do this:

 auto v = 3*m/s;
 auto a = 9.81*m/(s*s);
 auto huh = v+a;
Well yeah. That's what I'd want - compile time dimension checking. And it seems reasonably achievable with your system. And not to mention unit conversion, eg. auto d = 15*miles + 20*km; writefln(d.cm,"cm"); /* prints d in centimeters */ Of course, you'd really want it to be clever enough to understand when the units cancel out, e.g. auto n = (3*s) * (30*Hertz); /* n is real */ Could be we're looking for some sort of template struct, eg. struct SIUnit(int m,int s,int kg) { real r; } SIUnit!(1,0,0) x; // meters SIUnit!(1,-2,0) y; // meters per second per second SIUnit!(2,-2,1) z; // joules; Hmm...
Oct 14 2007
parent reply Reiner Pope <some address.com> writes:
Janice Caron wrote:
 On 10/14/07, Daniel Keep <daniel.keep.lists gmail.com> wrote:
 Actually, I believe someone's done something like this for D before.
 Their goal, however, was *compile-time* checking of units.  So, for
 example, you couldn't do this:

 auto v = 3*m/s;
 auto a = 9.81*m/(s*s);
 auto huh = v+a;
Well yeah. That's what I'd want - compile time dimension checking. And it seems reasonably achievable with your system. And not to mention unit conversion, eg. auto d = 15*miles + 20*km; writefln(d.cm,"cm"); /* prints d in centimeters */ Of course, you'd really want it to be clever enough to understand when the units cancel out, e.g. auto n = (3*s) * (30*Hertz); /* n is real */ Could be we're looking for some sort of template struct, eg. struct SIUnit(int m,int s,int kg) { real r; } SIUnit!(1,0,0) x; // meters SIUnit!(1,-2,0) y; // meters per second per second SIUnit!(2,-2,1) z; // joules; Hmm...
Oskar Linde wrote one already: http://www.csc.kth.se/~ol/physical.d But you don't actually need static opMul for that. To quote two lines of it: const Length meter = {1}; ... Length l = 0.1 * meter; As you can see, it uses instance opMul. But still very cool. -- Reiner
Oct 14 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 10/14/07, Reiner Pope <some address.com> wrote:
 But you don't actually need static opMul for that. To quote two lines of it:
That's true. Put like that, static opAdd(), static opSub(), etc., do start to sound a bit silly. I can't see why you would ever need to write: x = A + y; where A was a type. Surely, any time you can imagine a use for that, you could probably do the same thing with A just being a variable? (The only one I can think of that has any real use is static opCall() -- and even that need would disappear if structs had constructors)
Oct 14 2007
parent Reiner Pope <some address.com> writes:
Janice Caron wrote:
 On 10/14/07, Reiner Pope <some address.com> wrote:
 But you don't actually need static opMul for that. To quote two lines of it:
That's true. Put like that, static opAdd(), static opSub(), etc., do start to sound a bit silly. I can't see why you would ever need to write: x = A + y; where A was a type. Surely, any time you can imagine a use for that, you could probably do the same thing with A just being a variable? (The only one I can think of that has any real use is static opCall() -- and even that need would disappear if structs had constructors)
Well, here's a ... good ... use: struct foo { static bool opMul(foo* x) { return true;} } void main() { foo* p; assert(foo* p); // just checking that we declared p correctly foo* null; // hey, look! null really can be an identifier } Of course, you could do most of it with foo being a variable, but it's not anywhere near as expressive. :D -- Reiner
Oct 14 2007
prev sibling next sibling parent oldrev <oldrev gmail.com> writes:
Daniel Keep Wrote:

 
 
 oldrev wrote:
 Daniel Keep Wrote:
 
 oldrev wrote:
 It's a simple way to avoid using the ugly "opAdd_r", eg:

 struct Currency
 {
   private int m_value;

   public static Currency opAdd(Currency lhs, Currency rhs) {
     return Currency(lhs.m_value + rhs.m_value);
   }
 }
And how are you going to overload static opAdd_r, then? I really don't see any need for this; opAdd_r is perfectly fine. -- Daniel
We do not need opAdd_r anymore, it will be overloaded by static opAdd. static A opAdd(A a, int i); static A opAdd(int i, A a); a+100 // it equals to opAdd(a, 100); 100+a //opAdd(100, a) Regards, - oldrev
You didn't answer the first question. You haven't said how we're going to do this: struct Meters { real value; } struct m { static Meters opMul_r(real value) { return Meters(value); } } auto distance = 20*m; In your system, there's no way to have that since you can't have type arguments. And *yes*, there are people who use this kind of thing. Also, as Nathan pointed out, this would break basically *all* code that overloads any operators and for what? So we don't have to type "_r" and can no longer have static operator overloads? -- Daniel
Awesome! Thanks to point it out! Regards, - oldrev
Oct 14 2007
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Daniel,


 struct Meters
 {
 real value;
 }
 struct m
 {
 static Meters opMul_r(real value)
 {
 return Meters(value);
 }
 }
 auto distance = 20*m;
 
 In your system, there's no way to have that since you can't have type
 arguments.  And *yes*, there are people who use this kind of thing.
 
 
struct SIUnit(int d, int t, int m, int c=0, int k=0, int l=0) { static Meters opMul_r(real value) { } } const m = SIUnit!(1,0,0)(1.0);
Oct 14 2007
parent BCS <ao pathlink.com> writes:
Reply to Benjamin,

 Reply to Daniel,
 
 struct Meters
 {
 real value;
 }
 struct m
 {
 static Meters opMul_r(real value)
 {
 return Meters(value);
 }
 }
 auto distance = 20*m;
 In your system, there's no way to have that since you can't have type
 arguments.  And *yes*, there are people who use this kind of thing.
 
struct SIUnit(int d, int t, int m, int c=0, int k=0, int l=0) { static Meters opMul_r(real value) { } } const m = SIUnit!(1,0,0)(1.0);
I think I misread that (and I know I mistyped it): struct SIUnit(int d, int t, int m, int c=0, int k=0, int l=0) { } SIUnit!(d, t, m, c, k, l) opMul(int d, int t, int m, int c, int k, int l)(real value, SIUnit!(d, t, m, c, k, l) v2) { }
Oct 14 2007
prev sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 10/13/07, oldrev <oldrev gmail.com> wrote:
 It's a simple way to avoid using the ugly "opAdd_r", eg:

 struct Currency
 {
   private int m_value;

   public static Currency opAdd(Currency lhs, Currency rhs) {
     return Currency(lhs.m_value + rhs.m_value);
   }
 }
Returning to the original thread topic, how should the compiler react if I "cheat" and do struct Currency { private int m_value; public static Currency opAdd(int lhs, int rhs) { return Currency(lhs + rhs); } } I'm sure you can see the problem here. I've just redefined int + int. Surely, that can't be allowed?
Oct 14 2007
parent reply oldrev <oldrev gmail.com> writes:
Janice Caron Wrote:

 On 10/13/07, oldrev <oldrev gmail.com> wrote:
 It's a simple way to avoid using the ugly "opAdd_r", eg:

 struct Currency
 {
   private int m_value;

   public static Currency opAdd(Currency lhs, Currency rhs) {
     return Currency(lhs.m_value + rhs.m_value);
   }
 }
Returning to the original thread topic, how should the compiler react if I "cheat" and do struct Currency { private int m_value; public static Currency opAdd(int lhs, int rhs) { return Currency(lhs + rhs); } } I'm sure you can see the problem here. I've just redefined int + int. Surely, that can't be allowed?
Noway, when you overloading a binary operator, it must has a Currency parameter at least. Regards, - oldrev
Oct 14 2007
parent "Janice Caron" <caron800 googlemail.com> writes:
On 10/14/07, oldrev <oldrev gmail.com> wrote:
 Noway, when you overloading a binary operator, it must has a Currency
parameter at least.
Aha. I thought you might say that, so I've already planned out my response. If one of the parameters /has/ to be a Currency, then the best way to ensure that is to ditch the word "static", and bingo! - one Currency parameter /automatically/ at your disposal (it's called "this"). Job done. Of course, you still need to distinguish LHS from RHS, but that can be done easily and simply just by suffixing "_r" to the function name in the latter case. I call this new, revised proposal, the "status quo". :-)
Oct 14 2007