August 09, 2004
your style has no advantage. it is just another special name for something that has a special meaning. a context-dependent keyword.

searching for 'opAnything' or 'operator Anything' doesn't do any difference. i just prefer the second by much. that way, the method really shines out to have special behaviour, and is not planned to get called manually, too..

but as i said. it's just me, and it's just about style. you don't have any keywords with capital letters in else. and it would remove all those op* keywords, and instead create only one keyword, namely operator.

later, in D 2.0, or so, you could even allow others.. like float operator
dot(vec second)
to get called as v0 dot v1

for example..


but i guess this was discussed before. it's a minor issue. it's just about style. keywords shall be small case, and low in count. all those opAnything are ugly imho.

i prefer the c++/cli style, with the concatenated keywords, for new features..

value class X {}, ref class Y {} etc.. in the same way i like the operator XX()
style.

In article <cf79j8$dqp$4@digitaldaemon.com>, Walter says...
>
>
>"davepermen" <davepermen_member@pathlink.com> wrote in message news:cf60oo$1pt$1@digitaldaemon.com...
>> In article <cf31k5$223l$2@digitaldaemon.com>, Walter says...
>> >
>> >
>> >"Jarrett Billingsley" <kb3ctd2@yahoo.com> wrote in message news:cf2qfj$1toe$1@digitaldaemon.com...
>> >> personally i don't see what's wrong with
>> >> operator+() , but oh well.
>> >
>> >operator+ doesn't work when you need both the forward and the 'r'
>versions
>> >of an operator overload. Also, opCmp handles <, <=, >, >=. And lastly,
>opCmp
>> >is eminently greppable.
>> >
>> >
>>
>> i'd still prefer operator cmp() and similar. opAnything looks ugly.
>operator
>> Anything() not (imho). but thats me.. and doesn't really mather
>
>I think it's advantageous to have a predictable and recognizable 'look' for operator overload function names, since they don't have a keyword setting them off.
>
>


August 09, 2004
On Mon, 9 Aug 2004 00:32:37 -0700, Walter <newshound@digitalmars.com> wrote:
> "Ivan Senji" <ivan.senji@public.srce.hr> wrote in message
> news:cf3i3d$2a7r$3@digitaldaemon.com...
>> What is so special about opCmp, (ok it is used in AAs but
>> couldn't compiler report: "this type cann't be used in AA because
>> of the missing opCmp!")
>
> Putting it in Object reserves a predictable vtbl[] slot for it.

That that achieves... allowing you to aggressively optimise performance?

Could you achieve the same thing with some sort of hard-coded globally defined interface? eg.

interface IComparable {
  int opCmp(IComparable rhs);
}

class Foo : IComparable {
}

Does an interface reserve a vtbl slot? and can it be predictable?

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 09, 2004
Stewart Gordon wrote:
> Ant wrote:
> <snip>
> 
>> How else can an array of objects be sorted?
>> what problems do they cause?
> 
> 
> Can you think of a scenario in which an array of objects, of no common base class besides Object, would be mutually comparable?

Object[] list;
void Add(Object o) {
  list ~= o;
}

char[] Work() {
  char[] ret;
  foreach(Object o; list)
    ret ~= "{"~o.toString()~"}";
  return ret;
}

void Remove(Object o) {
  list.sort;
  <find object>
  <remove object>
}

August 09, 2004
"davepermen" <davepermen_member@pathlink.com> wrote in message news:cf8oq1$10lq$1@digitaldaemon.com...
> i prefer the c++/cli style, with the concatenated keywords, for new
features..

The context-sensitive keyword technique breaks the separation between lexical analysis and syntactic analysis, something that C++ does all the time but I wish to avoid with D. One consequence of breaking this rule is it makes syntax highlighters a lot more work to build.


August 09, 2004
"Regan Heath" <regan@netwin.co.nz> wrote in message news:opschjvoak5a2sq9@digitalmars.com...
> On Mon, 9 Aug 2004 00:32:37 -0700, Walter <newshound@digitalmars.com> wrote:
> > "Ivan Senji" <ivan.senji@public.srce.hr> wrote in message news:cf3i3d$2a7r$3@digitaldaemon.com...
> >> What is so special about opCmp, (ok it is used in AAs but couldn't compiler report: "this type cann't be used in AA because of the missing opCmp!")
> >
> > Putting it in Object reserves a predictable vtbl[] slot for it.
>
> That that achieves... allowing you to aggressively optimise performance?
>
> Could you achieve the same thing with some sort of hard-coded globally defined interface? eg.
>
> interface IComparable {
>    int opCmp(IComparable rhs);
> }
>
> class Foo : IComparable {
> }
>
> Does an interface reserve a vtbl slot? and can it be predictable?

Each interface implemented by a class creates another vptr and corresponding vtbl[] for it. Testing whether an object supports a particular interface is a runtime check, not a compile time one. So, yes, it will impact sorting performance.


August 09, 2004
Russ Lewis wrote:
> Stewart Gordon wrote:
> 
>> Ant wrote:
>> <snip>
>>
>>> How else can an array of objects be sorted?
>>> what problems do they cause?
>>
>>
>>
>> Can you think of a scenario in which an array of objects, of no common base class besides Object, would be mutually comparable?
> 
> 
> Object[] list;
> void Add(Object o) {
>   list ~= o;
> }
> 
> char[] Work() {
>   char[] ret;
>   foreach(Object o; list)
>     ret ~= "{"~o.toString()~"}";
>   return ret;
> }
> 
> void Remove(Object o) {
>   list.sort;
>   <find object>
>   <remove object>
> }

This is arguably the "D way" of thinking, but it strikes me as being a
hack brought around by the lack of a standard Set or MultiSet container.
  Also, the cost is very high:

     class Apple { }
     class Orange { }
     Apple a = new Apple();
     Orange o = new Orange();
     if (a > o) { /* why can we do this? */ }

Object.opCmp causes unintuitive behaviour in other places too:

     class IntWrapper {
       int value;
       this(int i) { value = i; }

       char[] toString() {
         return std.string.toString(value);
       }

       int opCmp(TestInteger rhs) {
         return value - rhs.value;
       }

       int opEquals(TestInteger rhs) {
         return rhs !== null && value == rhs.value;
       }
     }

Due to overload resolution rules, the sort property will use Object.opCmp, not IntWrapper.opCmp!

When overloading opCmp for class types, you must /always/ recieve an Object and do a dynamic cast if only wish to allow comparison against specific types.  This means, in the vast majority of cases, an unneccesary runtime test for every object comparison.

As an unrelated sidenote, omitting the 'override' annotation effectively achieves C++-style non-polymorphic inheritance: the opCmp chosen depends purely on how the reference is cast. (and, in this case, both overloads can match the argument, so we don't get the benefit of a compile error!)

Going back to the root of the problem, Object defines opCmp and opEquals for exactly two reasons:  array.sort and associative arrays.

Associative arrays can just as easily use the object's hash value instead of calling opCmp.  The actual ordering of the keys in an AA isn't any of our business anyway.

Fixing array.sort is easy too: dump it and replace it with a Phobos function.

For the sake of testing, I refactored the built-in sort function into a template that recieves a comparer function.  It took about 20 minutes, and it still passes the unit test. (attached.  Use -debug=main to build a standalone executable that runs the unit test then quits.  Use -debug=qsort for verbosity)

This isn't a hard change, or even a big one.  But it is causing a lot of inconvenient and unintuitive behaviour, which suggests that it is an important change.

  -- andy


August 10, 2004
Russ Lewis wrote:
> Stewart Gordon wrote:
<snip>
>> Can you think of a scenario in which an array of objects, of no common base class besides Object, would be mutually comparable?
<snip>

Your code has nothing to do with my question at all.  You've merely given me a set of wrapper functions for the process of sorting an Object[].  They give not a proton, neutron or electron of evidence of objects of different classes being added to the list, nor of their being mutually comparable.

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on the 'group where everyone may benefit.
August 10, 2004
Andy Friesen wrote:
<snip>
> This is arguably the "D way" of thinking, but it strikes me as being a hack brought around by the lack of a standard Set or MultiSet container. Also, the cost is very high:

Actually, I think the "D way" is that you'd almost never need a container of arbitrary Objects, since D has templates.

<snip>
> Object.opCmp causes unintuitive behaviour in other places too:
> 
>     class IntWrapper {
>       int value;
>       this(int i) { value = i; }
> 
>       char[] toString() {
>         return std.string.toString(value);
>       }
> 
>       int opCmp(TestInteger rhs) {
>         return value - rhs.value;
>       }
> 
>       int opEquals(TestInteger rhs) {
>         return rhs !== null && value == rhs.value;
>       }
>     }
> 
> Due to overload resolution rules, the sort property will use Object.opCmp, not IntWrapper.opCmp!

And because TestInteger is not a superclass of IntWrapper.

> When overloading opCmp for class types, you must /always/ recieve an Object and do a dynamic cast if only wish to allow comparison against specific types.  This means, in the vast majority of cases, an unneccesary runtime test for every object comparison.

Yes, as has been said already, this should be a compile-time check.

> As an unrelated sidenote, omitting the 'override' annotation effectively achieves C++-style non-polymorphic inheritance: the opCmp chosen depends purely on how the reference is cast. (and, in this case, both overloads can match the argument, so we don't get the benefit of a compile error!)

AIUI the override keyword is just a typo catcher.  I.e. if a program compiles, it will compile to exactly the same with the keyword removed.

> Going back to the root of the problem, Object defines opCmp and opEquals for exactly two reasons:  array.sort and associative arrays.
> 
> Associative arrays can just as easily use the object's hash value instead of calling opCmp.  The actual ordering of the keys in an AA isn't any of our business anyway.

AIUI, AAs already use both toHash and opCmp.

> Fixing array.sort is easy too: dump it and replace it with a Phobos function.
<snip>

I'm not sure how simply moving something into Phobos would fix it.

Indeed, a lot of D's builtins are actually part of Phobos.  Look at dmd\src\phobos\internal.  But by being builtins, they have the advantage that a compiler can optimise them if it likes.

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on the 'group where everyone may benefit.
August 10, 2004
has to be hell of a lot more work to scan for... 'operator add' compared to opAdd..

but it's okay. it's your language, and you can do what ever you want.


In article <cf8upo$12fc$1@digitaldaemon.com>, Walter says...
>
>
>"davepermen" <davepermen_member@pathlink.com> wrote in message news:cf8oq1$10lq$1@digitaldaemon.com...
>> i prefer the c++/cli style, with the concatenated keywords, for new
>features..
>
>The context-sensitive keyword technique breaks the separation between lexical analysis and syntactic analysis, something that C++ does all the time but I wish to avoid with D. One consequence of breaking this rule is it makes syntax highlighters a lot more work to build.
>
>


August 10, 2004
Stewart Gordon wrote:
> Andy Friesen wrote:
> <snip>
> 
>> This is arguably the "D way" of thinking, but it strikes me as being a hack brought around by the lack of a standard Set or MultiSet container. Also, the cost is very high:
> 
> 
> Actually, I think the "D way" is that you'd almost never need a container of arbitrary Objects, since D has templates.
> 
> <snip>
> 
>> Object.opCmp causes unintuitive behaviour in other places too:
>>
>>     class IntWrapper {
>>       int value;
>>       this(int i) { value = i; }
>>
>>       char[] toString() {
>>         return std.string.toString(value);
>>       }
>>
>>       int opCmp(IntWrapper rhs) {
>>         return value - rhs.value;
>>       }
>>
>>       int opEquals(IntWrapper rhs) {
>>         return rhs !== null && value == rhs.value;
>>       }
>>     }
>>
>> Due to overload resolution rules, the sort property will use Object.opCmp, not IntWrapper.opCmp!
> 
> And because TestInteger is not a superclass of IntWrapper.

eugh.  That's a typo.  Assume that TestInteger and IntWrapper are the same class.  Sorry.

>> When overloading opCmp for class types, you must /always/ recieve an Object and do a dynamic cast if only wish to allow comparison against specific types.  This means, in the vast majority of cases, an unneccesary runtime test for every object comparison.
> 
> Yes, as has been said already, this should be a compile-time check.
> 
>> As an unrelated sidenote, omitting the 'override' annotation effectively achieves C++-style non-polymorphic inheritance: the opCmp chosen depends purely on how the reference is cast. (and, in this case, both overloads can match the argument, so we don't get the benefit of a compile error!)
> 
> AIUI the override keyword is just a typo catcher.  I.e. if a program compiles, it will compile to exactly the same with the keyword removed.

Right.

>> Going back to the root of the problem, Object defines opCmp and opEquals for exactly two reasons:  array.sort and associative arrays.
>>
>> Associative arrays can just as easily use the object's hash value instead of calling opCmp.  The actual ordering of the keys in an AA isn't any of our business anyway.
> 
> AIUI, AAs already use both toHash and opCmp.

Currently, yes.  But the algorithm doesn't fundamentally need to in order to work correctly.

>> Fixing array.sort is easy too: dump it and replace it with a Phobos function.
> 
> <snip>
> 
> I'm not sure how simply moving something into Phobos would fix it.
> 
> Indeed, a lot of D's builtins are actually part of Phobos.  Look at dmd\src\phobos\internal.  But by being builtins, they have the advantage that a compiler can optimise them if it likes.

What I meant was to remove the built-in sort property altogether and replace it with a plain old, ordinary function in Phobos.

The current implementation effectively translates "x.sort" to "_adSort(x, typeid(typeof(x[0])));".  _adSort() is implemented in phobos/internal/qsort.d, so the gain in optimizibility isn't all that much.

In contrast, a template function is actually *more* optimizable because the comparison function can be inlined instead of requiring a virtual call to a TypeInfo instance. (this virtual call, incidently, itself performs another virtual call: opCmp of the class type)

 -- andy