Thread overview
opAssign?
Dec 18, 2004
Garett Bass
Dec 18, 2004
David Medlock
Dec 18, 2004
Garett Bass
Dec 18, 2004
David Medlock
Dec 18, 2004
Garett Bass
Dec 21, 2004
Stewart Gordon
Dec 18, 2004
Benjamin Herr
December 18, 2004
I'd like to have an opAssign() operator.  This would allow me to create new numeric types with syntax similar to built-in numeric types.  For example:

    struct clampf {
        private float value;
        opAssign(float assign) {
            assign = (assign =< 0) ? 0 : assign;
            value  = (assign >= 1) ? 1 : assign;
        }
        opAssign(clampf assign) {
            opAssign(assign.value);
        }
        // additional operators, eg. opAdd() etc.
    }

    clampf r, g, b;
    r = 0.5; // r.value == 0.5;
    g = r;   // g.value == 0.5;
    b = 2.f; // b.value == 1.0;

Then I could avoid clamping floating point values all the time, because I would always know that clampf's are clamped, and I could use the normal built-in type syntax.  It would also be handy to have implicit return functions, eg.:

    struct clampf {
        // ... see above
        float retFloat() {
            return value;
        }
    }

To allow numeric use such as:

    float f;
    f = r; // f == 0.5 (ie. f = r.retFloat())

Further, if this were all template friendly, then I could easily make a variety of clamp types with different limits. Thoughts, comments?

Regards,
Garett




December 18, 2004
This may be feasible for structs, but not for classes I think.

class A has member function:

A opAssign( A other ) {... ; return other;}


Now I type
A foo = new A();
A bar = new A();

foo = bar;

what happens?  Is foo now un-rebindable?

Garett Bass wrote:
> I'd like to have an opAssign() operator.  This would allow me to create new numeric types with syntax similar to built-in numeric types.  For example:
> 
>     struct clampf {
>         private float value;
>         opAssign(float assign) {
>             assign = (assign =< 0) ? 0 : assign;
>             value  = (assign >= 1) ? 1 : assign;
>         }
>         opAssign(clampf assign) {
>             opAssign(assign.value);
>         }
>         // additional operators, eg. opAdd() etc.
>     }
> 
>     clampf r, g, b;
>     r = 0.5; // r.value == 0.5;
>     g = r;   // g.value == 0.5;
>     b = 2.f; // b.value == 1.0;
> 
> Then I could avoid clamping floating point values all the time, because I would always know that clampf's are clamped, and I could use the normal built-in type syntax.  It would also be handy to have implicit return functions, eg.:
> 
>     struct clampf {
>         // ... see above
>         float retFloat() {
>             return value;
>         }
>     }
> 
> To allow numeric use such as:
> 
>     float f;
>     f = r; // f == 0.5 (ie. f = r.retFloat())
> 
> Further, if this were all template friendly, then I could easily make a variety of clamp types with different limits. Thoughts, comments?
> 
> Regards,
> Garett
> 
>  
> 
> 
December 18, 2004
David,

    I see your point.  However, I still see the value of
opAssign().  Let the usual reference assignment take place
when there is no opAssign() defined, and let opAssign() do
its intended business if it is defined.  Thus, defining
opAssign() means "Objects of this type don't want to be
rebound, they want to copy-on-assignment".

    What makes things really strange is if you allow static
opAssign(), which would effectively allow foo to copy
whatever static values were present in new A().  Does that
make sense at all?  I suspect static opAssign() would be an
error.  Are static operator functions always considered
erroneous?

    I think the numeric syntax advantages make this
appealing.  I always wondered why there is unsigned int, but
no unsigned float.  Certainly a 0..1, or -1..1 number class
can be very handy at times, and it sure would be nice to
keep the bounds checking centralized without sacrificing
normal numeric syntax.

Regards,
Garett


"David Medlock" <amedlock@nospam.org> wrote in message news:cq0aa0$krt$1@digitaldaemon.com...
> This may be feasible for structs, but not for classes I think.
>
> class A has member function:
>
> A opAssign( A other ) {... ; return other;}
>
>
> Now I type
> A foo = new A();
> A bar = new A();
>
> foo = bar;
>
> what happens?  Is foo now un-rebindable?


December 18, 2004
I clearly see the advantage of it, don't get me wrong.  I just like the
simple semantics of D and wouldn't want it to get too messy.

For things such as ranges(as you stated ) as well as Metrix/English measurement classes with auto conversions would be very nice.

As for static OpXXX() functions, I think they are ignored when you use the operators(since you don't have a this variable they wouldnt be very useful anyway).

Cheers,
-Ash

Garett Bass wrote:
> David,
> 
>     I see your point.  However, I still see the value of opAssign().  Let the usual reference assignment take place when there is no opAssign() defined, and let opAssign() do its intended business if it is defined.  Thus, defining opAssign() means "Objects of this type don't want to be rebound, they want to copy-on-assignment".
> 
>     What makes things really strange is if you allow static opAssign(), which would effectively allow foo to copy whatever static values were present in new A().  Does that make sense at all?  I suspect static opAssign() would be an error.  Are static operator functions always considered erroneous?
> 
>     I think the numeric syntax advantages make this appealing.  I always wondered why there is unsigned int, but no unsigned float.  Certainly a 0..1, or -1..1 number class can be very handy at times, and it sure would be nice to keep the bounds checking centralized without sacrificing normal numeric syntax.
> 
> Regards,
> Garett
> 
> 
> "David Medlock" <amedlock@nospam.org> wrote in message news:cq0aa0$krt$1@digitaldaemon.com...
> 
>>This may be feasible for structs, but not for classes I think.
>>
>>class A has member function:
>>
>>A opAssign( A other ) {... ; return other;}
>>
>>
>>Now I type
>>A foo = new A();
>>A bar = new A();
>>
>>foo = bar;
>>
>>what happens?  Is foo now un-rebindable?
> 
> 
> 
December 18, 2004
David,

    Thanks for your points.  I've decided to use opCast()
and opCall() to acheive the desired effect.  I have to
cast(float) to assign a clampf to a float, and a(0.5) to
assign a float to a clampf, but that hardly seems
unreasonable, and it makes certain the user knows that
clampf is not just a float.  I'm happy with the result.

Regards,
Garett


December 18, 2004
David Medlock wrote:
> This may be feasible for structs, but not for classes I think.
> 
> class A has member function:
> 
> A opAssign( A other ) {... ; return other;}
> 
> 
> Now I type
> A foo = new A();
> A bar = new A();
> 
> foo = bar;
> 
> what happens?  Is foo now un-rebindable?

This is rather an issue with the ambiguity of `=', being binding operator for object references and assignment operator for everything else (and equality operator in Pascal, eeks).

Perhaps we need to change the syntax for variable binding in a later iteration of D, to enable opAssign for class instances? foo := bar??

Another syntax for assignment is much more evil as it would need to apply to all other types to be really consistent?

Oh, I know nothing of this is going to happen to D, but let me dream :(
I will just write foo.opAssign(bar) in the meantime!

-ben
December 21, 2004
Garett Bass wrote:
> David,
> 
>     I see your point.  However, I still see the value of opAssign().  Let the usual reference assignment take place when there is no opAssign() defined, and let opAssign() do its intended business if it is defined.  Thus, defining opAssign() means "Objects of this type don't want to be rebound, they want to copy-on-assignment".

If you want C++, you (I guess) know where to find it.

Seriously, I'm not sure that overriding = to copy class objects would be useful or desirable.  A virtue of the current = operator is that it is consistently defined for everything (copy whatever its right operand represents, be it a value or a reference), and this is useful for generic programming.  If its semantics are changed for certain types, someone will try to use templates that expect the default behaviour, possibly leading to bugs that are hard to diagnose.

See also, if you haven't already

http://www.digitalmars.com/d/faq.html#assignmentoverloading

Of course, if you want to be able to make a copy of an object, you can always define a .dup property.

>     What makes things really strange is if you allow static opAssign(), which would effectively allow foo to copy whatever static values were present in new A().  Does that make sense at all?  I suspect static opAssign() would be an error.  Are static operator functions always considered erroneous?

No.  They denote the operator applied to the struct/union/class name. So if we had opAssign, it would lead to

    class Qwert {
        static Qwert opAssign(int i) { ... }
    }

    void main() {
        Qwert = 42;
    }

if that makes sense.

For a more meaningful example (using opCall), see

http://www.digitalmars.com/drn-bin/wwwnews?D/25334

>     I think the numeric syntax advantages make this appealing.  I always wondered why there is unsigned int, but no unsigned float.  Certainly a 0..1, or -1..1 number class can be very handy at times, and it sure would be nice to keep the bounds checking centralized without sacrificing normal numeric syntax.
<snip top of upside-down reply>

Hmm ... maybe.  Maybe someone else can provide a more detailed opinion....

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on on the 'group where everyone may benefit.