www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Making uniform function call syntax more complete a feature

reply "Tommi" <tommitissari hotmail.com> writes:
As I see it, the goal of uniform function call syntax, as 
described here http://www.drdobbs.com/blogs/cpp/232700394, is to 
allow non-intrusively extending the functionality of a type. I 
think the current implementation comes short in accomplishing 
this goal on two accounts:

1) You can't non-intrusively add static member functions
2) You can't non-intrusively add constructors

So, I'm suggesting these two features to be added to the language:

1. Static method lowering rules
     If function calls like the following are encountered...
     A) Type.compute(<ARGUMENTS>);
     B) Type.compute; // it's a static  property function
     ...and the compute functions haven't been implemented by Type,
     they get lowered into free function calls...
     A) compute!(Type)(<ARGUMENTS>);
     B) compute!(Type);

2. Constructors as free functions
     If a constructor call hasn't been implemented by Type...
     auto t = Type(<ARGUMENTS>);
     ...then it get's lowered into a free function call...
     auto t = this!(Type)(<ARGUMENTS>);
     (or something like that)
Jun 16 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-06-17 08:39, Tommi wrote:
 As I see it, the goal of uniform function call syntax, as described here
 http://www.drdobbs.com/blogs/cpp/232700394, is to allow non-intrusively
 extending the functionality of a type. I think the current
 implementation comes short in accomplishing this goal on two accounts:

 1) You can't non-intrusively add static member functions
 2) You can't non-intrusively add constructors

 So, I'm suggesting these two features to be added to the language:

 1. Static method lowering rules
 If function calls like the following are encountered...
 A) Type.compute(<ARGUMENTS>);
 B) Type.compute; // it's a static  property function
 ...and the compute functions haven't been implemented by Type,
 they get lowered into free function calls...
 A) compute!(Type)(<ARGUMENTS>);
 B) compute!(Type);

 2. Constructors as free functions
 If a constructor call hasn't been implemented by Type...
 auto t = Type(<ARGUMENTS>);
 ...then it get's lowered into a free function call...
 auto t = this!(Type)(<ARGUMENTS>);
 (or something like that)

I like that idea. -- /Jacob Carlborg
Jun 17 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 07/12/2012 12:05 PM, Thiez wrote:
 Have you considered adding operator overloading using UFCS while you're
 at it?

There is already an open issue about that iirc.
Jul 12 2012
prev sibling parent reply travert phare.normalesup.org (Christophe Travert) writes:
"Thiez" , dans le message (digitalmars.D:172060), a écrit :
 Have you considered adding operator overloading using UFCS 
 while you're at it?

I assumed it's already possible to add operators non-intrusively, because operators are just syntactic sugar for method calls: ++var; // actual code var.opUnary!"++"(); // lowered once opUnary!"++"(var); // lowered twice (if necessary) If you're talking about overloading existing operators (which have been implemented as member functions) non-intrusively for other types, then I don't know, doesn't it work?

I actually tried those yesterday (with opEquals and opCmp on structs) and couldn't get it to work. Code still used what appeared to be an automatically generated opEquals (that appears to perform a bitwise comparison) instead of my UFCS opEquals.

This behavior for opEquals is debatable, but make sense. If the designer of a struct did not implement opEquals, it may be that he intended opEqual to be the default opEqual. If you overload opEquals for such struct, you may be hijacking it's intended behavior: your not just adding a functionality, your overriding an existing functionality. Did you try operators that are not automatically generated ?
 It's already quite obvious that the compiler does not obey its 
 own rewrite rules (see 
 http://dlang.org/operatoroverloading.html#compare) Consider opCmp:
   a < b
 is rewritten to
   a.opCmp(b) < 0
 or
   b.opCmp(a) > 0
 Let's assume the first rule is always chosen. According to the 
 very rewrite rule we just applied, this must be rewritten to
   a.opCmp(b).opCmp(0) < 0
 
 It seems quite obvious the compiler does not rewrite compares on 
 integers or all hell would break loose... The language reference 
 should be more specific about these things.

The rewrite rule obviously apply only if the comparison operator is not already defined for those types by the langage. That could be precised in the web site, but it's consistent. By the way, would it be possible to implement an opCmp that returns a double, to allow it to return a NaN ? That may allow to create values that are neither superior, nor inferior to other value, like NaNs. It's not possible to implement opCmp for a floating point comparison if opCmp is bound to return an int. Another reason to ban Object imposing a specific signature for opCmp in all classes...
Jul 12 2012
parent travert phare.normalesup.org (Christophe Travert) writes:
"Simen Kjaeraas" , dans le message (digitalmars.D:172349), a écrit :
 On Thu, 12 Jul 2012 16:31:34 +0200, Christophe Travert  
 <travert phare.normalesup.org> wrote:
 
 By the way, would it be possible to implement an opCmp that returns a
 double, to allow it to return a NaN ? That may allow to create values
 that are neither superior, nor inferior to other value, like NaNs. It's
 not possible to implement opCmp for a floating point comparison if opCmp
 is bound to return an int.

Why don't you just test it? Not like it'd be many lines of code. Anyways, yes this works.

Thanks. I don't always have a d compiler at hand when I read this newsgroup. Maybe I should just write myself a todo to make this kind of test back home rather than directly posting the idea.
Jul 16 2012
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
I posted this as an enhancement request over there:
http://d.puremagic.com/issues/show_bug.cgi?id=8381
Jul 12 2012
prev sibling next sibling parent "Thiez" <thiezz gmail.com> writes:
Have you considered adding operator overloading using UFCS while 
you're at it?
Jul 12 2012
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 12 July 2012 at 10:05:16 UTC, Thiez wrote:
 Have you considered adding operator overloading using UFCS 
 while you're at it?

I assumed it's already possible to add operators non-intrusively, because operators are just syntactic sugar for method calls: ++var; // actual code var.opUnary!"++"(); // lowered once opUnary!"++"(var); // lowered twice (if necessary) If you're talking about overloading existing operators (which have been implemented as member functions) non-intrusively for other types, then I don't know, doesn't it work?
Jul 12 2012
prev sibling next sibling parent "Thiez" <thiezz gmail.com> writes:
On Thursday, 12 July 2012 at 12:43:24 UTC, Tommi wrote:
 On Thursday, 12 July 2012 at 10:05:16 UTC, Thiez wrote:
 Have you considered adding operator overloading using UFCS 
 while you're at it?

I assumed it's already possible to add operators non-intrusively, because operators are just syntactic sugar for method calls: ++var; // actual code var.opUnary!"++"(); // lowered once opUnary!"++"(var); // lowered twice (if necessary) If you're talking about overloading existing operators (which have been implemented as member functions) non-intrusively for other types, then I don't know, doesn't it work?

I actually tried those yesterday (with opEquals and opCmp on structs) and couldn't get it to work. Code still used what appeared to be an automatically generated opEquals (that appears to perform a bitwise comparison) instead of my UFCS opEquals. It's already quite obvious that the compiler does not obey its own rewrite rules (see http://dlang.org/operatoroverloading.html#compare) Consider opCmp: a < b is rewritten to a.opCmp(b) < 0 or b.opCmp(a) > 0 Let's assume the first rule is always chosen. According to the very rewrite rule we just applied, this must be rewritten to a.opCmp(b).opCmp(0) < 0 which must be rewritten to a.opCmp(b).opCmp(0).opCmp(0) < 0 and then a.opCmp(b).opCmp(0).opCmp(0).opCmp(0) < 0 and so on, to infinity. It seems quite obvious the compiler does not rewrite compares on integers or all hell would break loose... The language reference should be more specific about these things.
Jul 12 2012
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 12 July 2012 at 13:19:00 UTC, Thiez wrote:
 It's already quite obvious that the compiler does not obey its 
 own rewrite rules (see 
 http://dlang.org/operatoroverloading.html#compare) Consider 
 opCmp:
  a < b
 is rewritten to
  a.opCmp(b) < 0
 or
  b.opCmp(a) > 0
 Let's assume the first rule is always chosen. According to the 
 very rewrite rule we just applied, this must be rewritten to
  a.opCmp(b).opCmp(0) < 0
 which must be rewritten to
  a.opCmp(b).opCmp(0).opCmp(0) < 0
 and then
  a.opCmp(b).opCmp(0).opCmp(0).opCmp(0) < 0
 and so on, to infinity.

 It seems quite obvious the compiler does not rewrite compares 
 on integers or all hell would break loose... The language 
 reference should be more specific about these things.

Quote from 'The D Programming Language' chapter 12.1: "D’s approach to operator overloading is simple: whenever at least one participant in an operator expression is of user-defined type, the compiler rewrites the expression into a regular method call with a specific name. Then the regular language rules apply." So, assuming opCmp returns integer, then a.opCmp(b) < 0 doesn't get rewritten (lowered) any further, because user-defined types are not involved.
Jul 12 2012
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 12 July 2012 at 14:31:34 UTC, 
travert phare.normalesup.org (Christophe Travert) wrote:
 This behavior for opEquals is debatable, but make sense.

I don't think it's debatable at all. You must be able to figure out how a class is going to behave just by looking at its definition.
Jul 12 2012
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Thu, 12 Jul 2012 16:31:34 +0200, Christophe Travert  
<travert phare.normalesup.org> wrote:

 By the way, would it be possible to implement an opCmp that returns a
 double, to allow it to return a NaN ? That may allow to create values
 that are neither superior, nor inferior to other value, like NaNs. It's
 not possible to implement opCmp for a floating point comparison if opCmp
 is bound to return an int.

Why don't you just test it? Not like it'd be many lines of code. Anyways, yes this works. -- Simen
Jul 14 2012