September 20, 2003
Don't know how parse text/html message
September 20, 2003
Sean L. Palmer wrote:
> "Matthew Wilson" <matthew@stlsoft.org> wrote in message news:bkgn1s$30ng$1@digitaldaemon.com...
> 
>>>>Having said that, I can probably live with them as such, if only they
>>
>>were
>>
>>>>static.
>>>
>>>I don't understand.
>>
>>Even though your assertion that they should be in the global namespace is correct I, as a pragmatic fellow, will be content (at least to the point
> 
> of
> 
>>ceasing my whingeing) if they are implement as *static* member functions.
> 
> I
> 
>>can't live with the status quo, of them as non-static member functions,
> 
> and
> 
>>I don't plan to stop campaigning against them (see this month's CUJ!)
> 
> 
> Ok, I still don't understand how you would want them declared.  If static, they don't automatically take any arguments, and what you get is essentially the same thing as a global function, only it's somehow hidden in the class namespace?  How would you use it then?
> 
> It wouldn't resolve the issue of which class should it be a static member function of!  And you'd still need "friend" capability, though not for both classes, just for one of them.
> 
> Sean
> 
> 

operators should be in the form

binary/op= : RT operator ( LHS, RHS ) { .... }
where ever declared should be a "friend" or the types RT, LHS, RHS

unary/++   : RT operator ( T ) { .... }
where ever declared should be a "friend" or the types RT, T

e.g.
int operator_add( A a, B b ) { ... }
A   operator_add( A a, B b ) { ... }
B   operator_add( A a, B b ) { ... }

class A {}; class B : A {}
A b, a;
int i;
b = new B();
a = new A();
i = a+b;   // should call int operator_add( A, B );
b = a+b;   // should call B   operator_add( A, B );

a more complex example say `i = a+b+b`; is
i = ((a + b) + b);
the first (a + b) would be expected to be evaluated in the same context
as the RHS unless cast so
would be
B t1 = a+b; B op_add( A, B)
i = t1 + b; int op_add( B, B );

to force the first a+b to be evaluated in A context it would have to be
rewritten as
i = (cast(A)(a + b) + b);
would now become
A t1 = a+b; A op_add( A, B )
i = t1 + b; int op_add( A, B );

I've attached some example code I've been playing with to try to get
this behaviour from D classes, but currently am stummped on how to get
the operators to "evaluate" into context
(so far my chose is lazy eval )
i = a+b would be written
i = (a+b).eval(int.classinfo);
(all operators return "LazyEvaluators")
so a+b+b
=> (a+b)
=>LazyEval["+" : A, B => Unknown] + B
=> LazyEval( "+" : LazyEval, B => Unknown )
eval( int.classinfo) would then process A,B=>B; B+B=>int
throwing runtime exceptions along the way if operators where missing.

I also do not believe in r_sub;
instead
B operator_sub( B, A );
and
B operator_sub( A, B );
should be written (if required)












September 20, 2003
Sean L. Palmer wrote:
> "Matthew Wilson" <matthew@stlsoft.org> wrote in message
> news:bkgocr$3j7$1@digitaldaemon.com...
> 
>>>is fundamentally different from +=. I think operator overloading should
> 
> be
> 
>>>used much more conservatively than how it is popularly used in C++.
> 
> People
> 
>>>shouldn't have to look for an operator overload of += to find out that
> 
> what
> 
>>>it is doing has nothing at all to do with adding.
>>
>>Quite right. Transgressors should be weeded out and forced to 3yrs hard
>>VB.NET before they're allowed back on parole
> 
> 
> In my own module, I should be able to do whatever I please, whatever makes
> solving the task at hand easier.  Who are you to dictate to me how I should
> program?  Who the hell do you think you are?
> 

you have already allowed Walter to dictated to you how you program, by chosing his language to use.

what you write in your own module is upto you, but if you are making it public, then you might want to listen to what those who might be using it are saying.

are you that well intune with D to understand the effects and implications of operator overloading
for instance, although virtual, which "virtual" method to call is statically determined

and have you made your users aware of the side effects of your use of overloading.


> If I expose this stuff to you, and you don't like it, feel free to not use
> my library.
> 

September 20, 2003
"Mike Wynn" <mike@l8night.co.uk> wrote in message news:bkib7u$2ilb$1@digitaldaemon.com...
> Sean L. Palmer wrote:
>><snip>
> > In my own module, I should be able to do whatever I please, whatever
makes
> > solving the task at hand easier.  Who are you to dictate to me how I
should
> > program?  Who the hell do you think you are?


/me steps inbetween Mike and Sean and says:   "SO HOW ABOUT THEM SEATTLE
SEAHAWKS?"
:)

> you have already allowed Walter to dictated to you how you program, by chosing his language to use.
>
> what you write in your own module is upto you, but if you are making it public, then you might want to listen to what those who might be using it are saying.
<snip>


September 20, 2003
"Sean L. Palmer" <palmer.sean@verizon.net> wrote in message news:bki5gj$2apn$1@digitaldaemon.com...
> If ++x is converted to x += 1 automatically, then what if you overload operator + to take something besides int type?
>
> And if you do mapp ++x to x += 1, then you should also automatically map
x++
> to temp = x, x += 1, temp, and similarly for x--
>
> 99% of the time what I do want to use overloading for IS a mathematical type.  But I've seen some really neat stuff done with operator
overloading,
> things that the inventors would never have considered.

There is always that risk that perhaps this shuts the door on something. But although I don't agree with using arithmetic operator overloading for non-arithmetic purposes, that's a purely stylistic issue. Sorry if my opinions come on a little strong about it sometimes. What the arithmetic operator overloading rules do, however, is make it much easier to make a user-defined arithmetic type and integrate it into the language. For example, only one comparison operator needs to be written, rather than the 8 in C++.


September 20, 2003
"Jeroen van Bemmel" <someone@somewhere.com> wrote in message news:bkh5rd$1269$1@digitaldaemon.com...
> > In a mathematical sense you're right, but I just turn < into > to swap
the
> > operands, and >= into <=.
> OK, so they are like 'commutable'. Isn't this confusing in the context of overloading? When do you do this implicit transformation, in the
optimizer?

No, in the semantic phase.

> I noticed all these operators map to 'cmp', so 'cmp' should return -1,0,+1 or something?

All it needs to return is an int less than 0, 0, or greater than 0. Think of it like the strcmp() function in C.

> I must say this new operator overloading feature doesn't really appeal to me. It seems like there is more complexity and caveats being added than benefits (syntactic sugar)

One benefit is only one cmp function needs to be written instead of the 8 in C++ <g>. Remember, though, that == and != are handled by eq(), not cmp(). This is because it is common for a type to have an equality characteristic, but a relational characteristic would make no sense.


September 21, 2003
>
> There is always that risk that perhaps this shuts the door on something.
But
> although I don't agree with using arithmetic operator overloading for non-arithmetic purposes, that's a purely stylistic issue. Sorry if my opinions come on a little strong about it sometimes. What the arithmetic operator overloading rules do, however, is make it much easier to make a user-defined arithmetic type and integrate it into the language. For example, only one comparison operator needs to be written, rather than the
8
> in C++.
>
>

IMHO, how the operators works is a property of the class (this include
assignment, creation,...) and we either tag the class with an attribute
when we want something different than the default (which should be
conservative and safe) or it should be expressed by the functions
(and their attibutes) that are prent in the class.

We should be able to detect if a class support a concept without requiring an interface (and a virtual table). We do not necessarily need MI but we should be able to associate some characteristics to a class (or the compiler should be able to tell us from the definition).

I want to be able to know if a class is comparable (and if so, which
king of comparison are allowed, equality only, fully ordered or
partly ordered), copyable (if so, if bitwise for struct, deeep, shalow,...),
createable on stack (auto) or dynamically, assignable, if it might be null,
...

For the operator, it is true that in C++, not enough operators are defined in terms of others but I think we should have some control of what we allows and which operators are always or sometimes defined in term of others... I think the best solution would be to do almost nothing by default but provide an easy way to get many things done by the compiler...

This could be done in a few ways. Here are some possibilities:

a) We have some class attributes (or the possibility to inherit from
some special "capability declaration classes" that would tell how
some operators (and other functions) are handled:

class A : fully_ordered, deep_copy, standard_arithmetic { }

where theses bases classes would give constraints or capabilities
or behaviors of the classes. A constraint class cannot have virtual
member nor data member (i.e always a empty-base) but would
only have declarations and template style definitions. We would
provide a few such constraint classes in the standard library. Here
an example (the syntax may have some errors but it should give
the idea) :

constraint class fully_ordered {
    // derived indicate that the type must be a derived class...
    template (T:derived)
    int cmp(T t1, T t2);    // declaration only

    // Here is is a sample on how we could prevent (we might
    // also simply uses private access) but exactly what we
    // give might vary a bit (we could in particular have
    // one safe class and another one that do more thing
    // automatically.
    template (T:derived, U:derived)
    prohibited int cmp(T t, U u); // declaration -- prevent mixed derived
classes

    template (T:derived)
    bool operator < (T t1, T t2) { return cmp(t1, t2) < 0; }

    template (T:derived)
    bool operator <= (T t1, T t2) { return cmp(t1, t2) <= 0; }

    template (T:derived)
    bool operator > (T t1, T t2) { return cmp(t1, t2) > 0; }

    template (T:derived)
    bool operator >= (T t1, T t2) { return cmp(t1, t2) >= 0; }

    // Have a way to check if a type has a member (or free) function
    // and if so, uses that specialisation...
    // The syntax need reworking -- I uses plain english to give the
    // concept. The idae is simply to be able to specialize on something
    // more than T* or MyClass* or something similar
    template (T : derived where T has (eq))
    bool operator==(T t1, T t2) { return eq(t1, t2); }

    // This is the normal definition uses when the specialisation
    // do not apply.
    template (T : derived )
    bool operator==(T t1, T t2) { return cmp(t1, t2); }

    template (T: derived)
    bool operator!=(T t1, T t2) { return !(t1 == t2); }
}

constraint_class fully_ordered_less {
    // Similar to above but uses a member function less
    // to implement all operators.

    // In fact, we could merge that constraint class with the
    // previous and check for the presence of members
    // eq(), cmp() and less() to decide what we do (and
    // we could even prohibit having both operator less and
    // cmp defined if we want by making a specialisation
    // when both are defined and prohibiting it...

    // In fact, it be usefull in that case to prohibit class instanciation
    // even if no comparison are ever done..

    // Maybe we would also like to be able to put contraints
    // that make the class abstract is something is not defined...
}

The advantage of doing is that way is clear... We can provide a class with the most usefull rules so that it would be very easy to uses them but it is possible to define our owns constraint classes (for example one that would works with partial order).

Also, it is possible to group those class:

constraint class fully_ordered_with_deep_copy : fully_ordered, deeep_copy { }

and when we want to uses a class, we simply specify those classes as if we inherit from them.

class A : fully_ordered {
    int cmp(...) { definition here... }
};


With such a concept of constraint classes, we add lot of power to the language as those classes would be used to:

a) automatically implement some operations in term of others
b) verify that a class define something (similar to an abstract method)
c) verify some other constraint on a type...

Also, it would be easy if one want operator ++ to means += 1 to have one such class and one other if we don't want it...

By default, I would say that classes would be relatively restricted
if the do not inherited from such a class (to be the safest by default).
We might even prohibit some kind of operations if we do not inherit
from a class that enable it... (for ex. no operator cmp if we do not
have a constraint class that define its behavior)

We would have a language that would allows to express lot of things directly in the code...


September 21, 2003
> >
> > I'm a bit worried about the interface for defining properties.  The way it is, you could do weird things like document.save="filename"; whether or not it was intended to be used that way.
>
> Yes, you can do that. Whether you want to or not is a style issue.
>

I would prefer that properties attributes would be required in the declaration to allows the uses of a function as a property.

Otherwise, this could lead to code obfuscation...  Function call syntax make the code more clear that an action will occurs.

Also, if properties are explicitly documented as such, this would
be usefull when D will be used for COM or .NET programming
or for visual editing of an UI (the inspector will display public
(or published) methods (as in Delphi) but not arbitrary method
that happen to have the proper number of argument (0 or 1).

Also having a keyword would allows support for array properties.


September 21, 2003
x = x :+: y; //Probably the neatest form

I like the idea of being able to define our own operators. This could be
done by using :something: as youi suggest or we might also uses
another symbol like @, # or $ to start a user symbol and we could
allows most characters that are used in operators and any valid
name (we migth have some restrictions on what symbols are
allowed and not allowing mixing symbol (like +, <) with names.

Using a trailing symbol does have an advantage of limiting possible ambiguities if we want to allows no space after the operator.

For example, I would be able to define an exponent operator

5.1 @pow 2    // 5.1 ^ 2 (i.e. 5.1 * 5.1)

Matrix m;

@det m;    // determinant of the matrix m
    // where @det is defined as a prefix operator of class Matrix


When a user defined operator is found, the compiler would suppose binary operator if there is an expression on both side a prefix operator if there is an expression on the right and a a postfix operator if there is an expression on the left.

a + @my_op b;    @my_op is a prefix op for object of type b
a @my_op b;    @my_op is a binary op
a @my_op + b;    @my_op is a postfix op for object of type a



September 21, 2003
Philippe Mori wrote:
>>>I'm a bit worried about the interface for defining properties.  The way
>>>it is, you could do weird things like document.save="filename"; whether
>>>or not it was intended to be used that way.
>>
>>Yes, you can do that. Whether you want to or not is a style issue.
>>
> 
> 
> I would prefer that properties attributes would be required in the
> declaration to allows the uses of a function as a property.
> 
> Otherwise, this could lead to code obfuscation...  Function call
> syntax make the code more clear that an action will occurs.
> 
> Also, if properties are explicitly documented as such, this would
> be usefull when D will be used for COM or .NET programming
> or for visual editing of an UI (the inspector will display public
> (or published) methods (as in Delphi) but not arbitrary method
> that happen to have the proper number of argument (0 or 1).
> 
> Also having a keyword would allows support for array properties.
> 
> 

without proper property syntax,
what happens with a property or function that returns a class that overloads opCall ?