www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Uniform Function Call Syntax in D - GameDev.net

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
http://www.reddit.com/r/programming/comments/vvpfy/uniform_function_call_syntax_in_d_gamedevnet/

Andrei
Jul 01 2012
next sibling parent reply Nick Sabalausky <SeeWebsiteToContactMe semitwist.com> writes:
On Sun, 01 Jul 2012 11:13:10 -0400
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

 http://www.reddit.com/r/programming/comments/vvpfy/uniform_function_call_syntax_in_d_gamedevnet/
 
 Andrei

Good article. One of the commenters brought up a point about confusion from possible conflicts between UFCS funcs and member funcs. I was just about to reply saying that's not an issue in D because it would be a conflict error, but I did a little test first: ----------------------- import std.stdio; void bar(Foo f) { writeln("UFCS"); } struct Foo { void bar() { writeln("Member"); } } void main() { Foo f; f.bar(); } ----------------------- That successfully compiles and prints "Member". Same thing happens if you move the UFCS func and Foo definition out into their own separate modules. But I was expecting a conflict error at compile-time. Is this a bug?
Jul 01 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 7/1/2012 11:53 AM, Nick Sabalausky wrote:
 That successfully compiles and prints "Member". Same thing happens if
 you move the UFCS func and Foo definition out into their own separate
 modules. But I was expecting a conflict error at compile-time. Is this
 a bug?

No, it's correct behavior. A real member overrides.
Jul 01 2012
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 01.07.2012 23:02, schrieb Walter Bright:
 On 7/1/2012 11:53 AM, Nick Sabalausky wrote:
 That successfully compiles and prints "Member". Same thing happens if
 you move the UFCS func and Foo definition out into their own separate
 modules. But I was expecting a conflict error at compile-time. Is this
 a bug?

No, it's correct behavior. A real member overrides.

isn't that some sort of highjacking then?
Jul 01 2012
parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 02.07.2012 07:13, schrieb Jonathan M Davis:
 On Monday, July 02, 2012 07:00:23 dennis luehring wrote:
 Am 01.07.2012 23:02, schrieb Walter Bright:
 On 7/1/2012 11:53 AM, Nick Sabalausky wrote:
 That successfully compiles and prints "Member". Same thing happens if
 you move the UFCS func and Foo definition out into their own separate
 modules. But I was expecting a conflict error at compile-time. Is this
 a bug?

No, it's correct behavior. A real member overrides.

isn't that some sort of highjacking then?

More like it avoids hijacking. It stops you from creating a function which is used instead of the one which is on the class or struct. Granted, this does mean that you could be surprised about your external function not being called, and adding a new member function could cause your existing external function to no longer be called (which could be a problem), but realistically there's no other way to handle the situation. It's possible to explicitly give a path to the free function (e.g. path.to.function), but there's no way to do that for a member function, since there's only one way to call it. So, if you were forced to disambiguate, you could never indicate anything else other than the free function - not without introducing a new syntax to indicate the member function. - Jonathan M Davis

but the compiler selects the member-functions silently - thats odd, ok i will see it very fast - but then i need to change my code anyway - so whats the reason for the silent "overwrite"?
Jul 01 2012
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/01/2012 11:11 PM, Jonathan M Davis wrote:

 Yes, but as I said, if it _didn't_ select the member function when 

 conflict, it would be impossible to call the member function whenever 

 a conflict.

I wouldn't be a fan of it but I think it would still be possible: class C { void foo() {} } void main() { auto c = new C(); auto c_foo = &c.foo; c_foo(); } Ali
Jul 02 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 07/03/2012 09:55 PM, bearophile wrote:
 Jonathan M Davis:

 Yes, but as I said, if it _didn't_ select the member function when
 there was a
 conflict, it would be impossible to call the member function whenever
 there was
 a conflict. There is no way to indicate that you mean a member
 function rather
 than a free function. The normal way to do that is to use member
 function call
 syntax, and UFCS allows you to then use that for free functions. With
 conflicts
 between free functions, you can do path.to.func or other.place.func
 instead of
 just func, but with a member function, that's not possible. So,
 without adding
 new syntax to the language,

I understand. This is Nick Sabalausky example:
 import std.stdio;

 void bar(Foo f) {
     writeln("UFCS");
 }

 struct Foo {
     void bar() {
         writeln("Member");
     }
 }

 void main()
 {
     Foo f;
     f.bar();
 }

So let's assume the language gives an compile error here, because there is a conflict.

There is no conflict. The method takes precedence.
 If you want to call the free function you use bar(f). If
 you want to call the bar method of Foo, you can't, because it's
 ambiguous, and as you say there is no alternative (simple) syntax to
 specify you want the method of Foo.

 This is a limitation. But is this a problem?

Certainly.
 If you want to call Foo.bar
 then you don't import the free function bar in the current scope. How
 often do you want to keep both the free function and a method with the
 same name and you wan to call the method?

Every time you want the free function to be a generic implementation that works for everything and the method to be a specialisation for the respective type if present. The question you should be asking is: "How often do you want to keep both the function and a method with the same name and don't want to call the method?" I cannot think of a single case.
 So maybe it's worth accepting this limitation, to reduce confusion for
 the people the read the code.

It does not do that. It does not matter whether or not a function is a member function. Why would it make any difference?
Jul 03 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, July 02, 2012 07:00:23 dennis luehring wrote:
 Am 01.07.2012 23:02, schrieb Walter Bright:
 On 7/1/2012 11:53 AM, Nick Sabalausky wrote:
 That successfully compiles and prints "Member". Same thing happens if
 you move the UFCS func and Foo definition out into their own separate
 modules. But I was expecting a conflict error at compile-time. Is this
 a bug?

No, it's correct behavior. A real member overrides.

isn't that some sort of highjacking then?

More like it avoids hijacking. It stops you from creating a function which is used instead of the one which is on the class or struct. Granted, this does mean that you could be surprised about your external function not being called, and adding a new member function could cause your existing external function to no longer be called (which could be a problem), but realistically there's no other way to handle the situation. It's possible to explicitly give a path to the free function (e.g. path.to.function), but there's no way to do that for a member function, since there's only one way to call it. So, if you were forced to disambiguate, you could never indicate anything else other than the free function - not without introducing a new syntax to indicate the member function. - Jonathan M Davis
Jul 01 2012
prev sibling parent "Kapps" <opantm2+spam gmail.com> writes:
On Monday, 2 July 2012 at 05:55:20 UTC, dennis luehring wrote:
 Am 02.07.2012 07:13, schrieb Jonathan M Davis:
 On Monday, July 02, 2012 07:00:23 dennis luehring wrote:
 Am 01.07.2012 23:02, schrieb Walter Bright:
 On 7/1/2012 11:53 AM, Nick Sabalausky wrote:
 That successfully compiles and prints "Member". Same thing 
 happens if
 you move the UFCS func and Foo definition out into their 
 own separate
 modules. But I was expecting a conflict error at 
 compile-time. Is this
 a bug?

No, it's correct behavior. A real member overrides.

isn't that some sort of highjacking then?

More like it avoids hijacking. It stops you from creating a function which is used instead of the one which is on the class or struct. Granted, this does mean that you could be surprised about your external function not being called, and adding a new member function could cause your existing external function to no longer be called (which could be a problem), but realistically there's no other way to handle the situation. It's possible to explicitly give a path to the free function (e.g. path.to.function), but there's no way to do that for a member function, since there's only one way to call it. So, if you were forced to disambiguate, you could never indicate anything else other than the free function - not without introducing a new syntax to indicate the member function. - Jonathan M Davis

but the compiler selects the member-functions silently - thats odd, ok i will see it very fast - but then i need to change my code anyway - so whats the reason for the silent "overwrite"?

If it didn't overwrite silently, it would mean every single free function is now not a valid member function name. Better hope your users don't import a module that uses said free function. In my opinion, the current way is the one that makes sense. And extension methods in C# do this as well.
Jul 01 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, July 02, 2012 07:54:56 dennis luehring wrote:
 Am 02.07.2012 07:13, schrieb Jonathan M Davis:
 On Monday, July 02, 2012 07:00:23 dennis luehring wrote:
 Am 01.07.2012 23:02, schrieb Walter Bright:
 On 7/1/2012 11:53 AM, Nick Sabalausky wrote:
 That successfully compiles and prints "Member". Same thing happens if
 you move the UFCS func and Foo definition out into their own separate
 modules. But I was expecting a conflict error at compile-time. Is this
 a bug?

No, it's correct behavior. A real member overrides.

isn't that some sort of highjacking then?

More like it avoids hijacking. It stops you from creating a function which is used instead of the one which is on the class or struct. Granted, this does mean that you could be surprised about your external function not being called, and adding a new member function could cause your existing external function to no longer be called (which could be a problem), but realistically there's no other way to handle the situation. It's possible to explicitly give a path to the free function (e.g. path.to.function), but there's no way to do that for a member function, since there's only one way to call it. So, if you were forced to disambiguate, you could never indicate anything else other than the free function - not without introducing a new syntax to indicate the member function. - Jonathan M Davis

but the compiler selects the member-functions silently - thats odd, ok i will see it very fast - but then i need to change my code anyway - so whats the reason for the silent "overwrite"?

Yes, but as I said, if it _didn't_ select the member function when there was a conflict, it would be impossible to call the member function whenever there was a conflict. There is no way to indicate that you mean a member function rather than a free function. The normal way to do that is to use member function call syntax, and UFCS allows you to then use that for free functions. With conflicts between free functions, you can do path.to.func or other.place.func instead of just func, but with a member function, that's not possible. So, without adding new syntax to the language, it was essentially impossible to do anything other than pick the member function whenever there's a conflict. - Jonathan M Davis
Jul 01 2012
prev sibling next sibling parent "xenon325" <1 mail.net> writes:
On Monday, 2 July 2012 at 06:11:22 UTC, Jonathan M Davis wrote:
 So, without adding new syntax to the language, it was 
 essentially impossible to do anything other than pick the 
 member function whenever there's a conflict.

Thanks to C++ for inspiration, I even have proposal for such syntax! obj.free myFunc( args ) obj.member myFunc( args ) :D
Jul 02 2012
prev sibling next sibling parent d coder <dlang.coder gmail.com> writes:
--f46d04016c2935c63804c3ec0888
Content-Type: text/plain; charset=ISO-8859-1

 Thanks to C++ for inspiration, I even have proposal for such
 syntax!

        obj.free myFunc( args )
        obj.member myFunc( args )

obj.myFunc( args ); // calls member function, even if free function exists myFunc( obj, args ); // calls free function, even if member function exists That is the current behavior. :-) Regards - Puneet --f46d04016c2935c63804c3ec0888 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote"><br><blockquote class=3D"gmail_quote" style=3D"m= argin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div id=3D":5= 1q">Thanks to C++ for inspiration, I even have proposal for such<br> syntax!<br> <br> =A0 =A0 =A0 =A0obj.free myFunc( args )<br> =A0 =A0 =A0 =A0obj.member myFunc( args )<br><br></div></blockquote><div><br=
</div><div>How about:</div><div><br></div><div>obj.myFunc( args ); // call=

); // calls free function, even if member function exists</div> <div><br></div><div>That is the current behavior. =A0:-)</div><div><br></di= v><div>Regards</div><div>- Puneet</div><div><br></div></div> --f46d04016c2935c63804c3ec0888--
Jul 03 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 Yes, but as I said, if it _didn't_ select the member function 
 when there was a
 conflict, it would be impossible to call the member function 
 whenever there was
 a conflict. There is no way to indicate that you mean a member 
 function rather
 than a free function. The normal way to do that is to use 
 member function call
 syntax, and UFCS allows you to then use that for free 
 functions. With conflicts
 between free functions, you can do path.to.func or 
 other.place.func instead of
 just func, but with a member function, that's not possible. So, 
 without adding
 new syntax to the language,

I understand. This is Nick Sabalausky example:
 import std.stdio;

 void bar(Foo f) {
     writeln("UFCS");
 }

 struct Foo {
     void bar() {
         writeln("Member");
     }
 }

 void main()
 {
     Foo f;
     f.bar();
 }

So let's assume the language gives an compile error here, because there is a conflict. If you want to call the free function you use bar(f). If you want to call the bar method of Foo, you can't, because it's ambiguous, and as you say there is no alternative (simple) syntax to specify you want the method of Foo. This is a limitation. But is this a problem? If you want to call Foo.bar then you don't import the free function bar in the current scope. How often do you want to keep both the free function and a method with the same name and you wan to call the method? So maybe it's worth accepting this limitation, to reduce confusion for the people the read the code. Bye, bearophile
Jul 03 2012
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, July 03, 2012 21:55:47 bearophile wrote:
 So maybe it's worth accepting this limitation, to reduce
 confusion for the people the read the code.

I would give a resounding no on that one. The confusion on how to actually manage to be able to use your member function would t hen be even greater, and if you need lots of other stuff from the module which provides the offending free function, then _not_ importing it becomes a royal pain. I think that the current approach works just fine. - Jonathan M Davis
Jul 03 2012