www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Static method conflicts with non-static method?

reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
Is this a bug? Code:

	import std.stdio;

	struct S {
		static int func(int x) { return x+1; }
		int func(int x) { return x+2; }
	}

	void main() {
		S s;
		writeln(s.func(1));
	}

DMD (latest git) output:

	test.d(10): Error: function test.S.func called with argument types:
		((int))
	matches both:
		test.S.func(int x)
	and:
		test.S.func(int x)

The error message is unhelpful, but basically the complaint is that the
static method is conflicting with the non-static method.

But I would've thought it is unambiguous; I'd expect that s.func should
resolve to the non-static method, and S.func to the static method. After
all, no object is needed to invoke the static method, and the static
method cannot be invoked without an object.


T

-- 
The early bird gets the worm. Moral: ewww...
Apr 26 2012
next sibling parent "Paulo Pinto" <pjmlp progtools.org> writes:
On Friday, 27 April 2012 at 06:14:13 UTC, H. S. Teoh wrote:
 Is this a bug? Code:

 	import std.stdio;

 	struct S {
 		static int func(int x) { return x+1; }
 		int func(int x) { return x+2; }
 	}

 	void main() {
 		S s;
 		writeln(s.func(1));
 	}

 DMD (latest git) output:

 	test.d(10): Error: function test.S.func called with argument 
 types:
 		((int))
 	matches both:
 		test.S.func(int x)
 	and:
 		test.S.func(int x)

 The error message is unhelpful, but basically the complaint is 
 that the
 static method is conflicting with the non-static method.

 But I would've thought it is unambiguous; I'd expect that 
 s.func should
 resolve to the non-static method, and S.func to the static 
 method. After
 all, no object is needed to invoke the static method, and the 
 static
 method cannot be invoked without an object.


 T

I always thought that D follows the same rules as Java, C++ and C# have. Meaning you can use an instance object to call a static method, even though it is not needed. As such the call becomes ambiguous, because the compiler won't know what it supposed to call. I tried to look in the language reference, but did not find a clear explanation for this, but I would expect such scenarios to be forbidden. This type of code is a pain to maintain if it is allowed. -- Paulo
Apr 26 2012
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 27 Apr 2012 01:07:03 -0400, H. S. Teoh <hsteoh quickfur.ath.cx>  
wrote:

 Is this a bug? Code:

 	import std.stdio;

 	struct S {
 		static int func(int x) { return x+1; }
 		int func(int x) { return x+2; }
 	}

 	void main() {
 		S s;
 		writeln(s.func(1));
 	}

 DMD (latest git) output:

 	test.d(10): Error: function test.S.func called with argument types:
 		((int))
 	matches both:
 		test.S.func(int x)
 	and:
 		test.S.func(int x)

 The error message is unhelpful, but basically the complaint is that the
 static method is conflicting with the non-static method.

 But I would've thought it is unambiguous; I'd expect that s.func should
 resolve to the non-static method, and S.func to the static method. After
 all, no object is needed to invoke the static method, and the static
 method cannot be invoked without an object.

It's not a bug, it's intended behavior. Static members are accessible via an instance pointer. My personal belief is that it shouldn't be this way, especially since you can make factory static methods that look like they are doing something on an instance. I brought this up a while ago, but since when did anyone listen to me? :) Here is a relevant discussion: http://forum.dlang.org/post/j3fi1u$1uge$1 digitalmars.com One of the counter-arguments from Andrei was that static methods can be used as "methods" on types for generic programming. With the advent of UFCS, this argument has much less teeth. Maybe it should be revisited... -Steve
Apr 27 2012
parent travert phare.normalesup.org (Christophe) writes:
"Steven Schveighoffer" , dans le message (digitalmars.D:165141), a
 The idea I came up with in my proposal  
 (http://d.puremagic.com/issues/show_bug.cgi?id=6579) was to allow aliasing  
 the static method into the instance namespace:

+1
Apr 28 2012
prev sibling next sibling parent "so" <so so.so> writes:
On Friday, 27 April 2012 at 10:48:29 UTC, Steven Schveighoffer 
wrote:

 With the advent of UFCS, this argument has much less teeth.  
 Maybe it should be revisited...

 -Steve

Elaborate please how UFCS would help in that context.
Apr 27 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 27 Apr 2012 07:03:02 -0400, so <so so.so> wrote:

 On Friday, 27 April 2012 at 10:48:29 UTC, Steven Schveighoffer wrote:

 With the advent of UFCS, this argument has much less teeth.  Maybe it  
 should be revisited...

 -Steve

Elaborate please how UFCS would help in that context.

Hm... thinking about it, UFCS requires passing the instance, while static methods do not. So it doesn't make as much sense as I thought... I still think static methods should not be callable on instances without opt-in from the aggregate author. The confusion it can cause is not worth the benefits IMO. -Steve
Apr 27 2012
prev sibling next sibling parent "so" <so so.so> writes:
On Friday, 27 April 2012 at 11:23:39 UTC, Steven Schveighoffer 
wrote:
 On Fri, 27 Apr 2012 07:03:02 -0400, so <so so.so> wrote:

 On Friday, 27 April 2012 at 10:48:29 UTC, Steven Schveighoffer 
 wrote:

 With the advent of UFCS, this argument has much less teeth.  
 Maybe it should be revisited...

 -Steve

Elaborate please how UFCS would help in that context.

Hm... thinking about it, UFCS requires passing the instance, while static methods do not. So it doesn't make as much sense as I thought... I still think static methods should not be callable on instances without opt-in from the aggregate author. The confusion it can cause is not worth the benefits IMO.

I agree it is ugly. If there is a way out (reason why i asked), we should just dump it.
Apr 27 2012
prev sibling next sibling parent Kevin Cox <kevincox.ca gmail.com> writes:
--0015175d07ac38e11d04bea7b068
Content-Type: text/plain; charset=UTF-8

On Apr 27, 2012 7:34 AM, "so" <so so.so> wrote:
 I agree it is ugly. If there is a way out (reason why i asked), we should

I don't like the idea either because it is confusing. The only reason I can imagine is if there was polymorphism on statics which I see as a fairly useless feature. I would be interested to hear of possible use cases though. --0015175d07ac38e11d04bea7b068 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <p><br> On Apr 27, 2012 7:34 AM, &quot;so&quot; &lt;so so.so&gt; wrote:<br> &gt;<br> &gt; I agree it is ugly. If there is a way out (reason why i asked), we sho= uld just dump it.</p> <p>I don&#39;t like the idea either because it is confusing.=C2=A0 The only= reason I can imagine is if there was polymorphism on statics which I see a= s a fairly useless feature.=C2=A0=C2=A0 I would be interested to hear of po= ssible use cases though. <br> </p> --0015175d07ac38e11d04bea7b068--
Apr 27 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 27 Apr 2012 07:31:50 -0400, so <so so.so> wrote:

 On Friday, 27 April 2012 at 11:23:39 UTC, Steven Schveighoffer wrote:
 On Fri, 27 Apr 2012 07:03:02 -0400, so <so so.so> wrote:

 On Friday, 27 April 2012 at 10:48:29 UTC, Steven Schveighoffer wrote:

 With the advent of UFCS, this argument has much less teeth.  Maybe it  
 should be revisited...

 -Steve

Elaborate please how UFCS would help in that context.

Hm... thinking about it, UFCS requires passing the instance, while static methods do not. So it doesn't make as much sense as I thought... I still think static methods should not be callable on instances without opt-in from the aggregate author. The confusion it can cause is not worth the benefits IMO.

I agree it is ugly. If there is a way out (reason why i asked), we should just dump it.

The idea I came up with in my proposal (http://d.puremagic.com/issues/show_bug.cgi?id=6579) was to allow aliasing the static method into the instance namespace: struct S1 { static void foo() {} alias S1.foo this.foo; } struct S2 { static void foo() {} } void main() { S1 i1; S2 i2; S1.foo(); // ok i1.foo(); // ok S2.foo(); // ok i2.foo(); // error } -Steve
Apr 27 2012
prev sibling next sibling parent "so" <so so.so> writes:
On Friday, 27 April 2012 at 11:49:08 UTC, Kevin Cox wrote:
 On Apr 27, 2012 7:34 AM, "so" <so so.so> wrote:
 I agree it is ugly. If there is a way out (reason why i 
 asked), we should

I don't like the idea either because it is confusing. The only reason I can imagine is if there was polymorphism on statics which I see as a fairly useless feature. I would be interested to hear of possible use cases though.

This one is quite important for templates. struct A(T) { static T mini() { return T.min; } static T maxi() { return T.max; } } struct B(T) { T[] v; T mini() { return min(v); } T maxi() { return max(v); } } void test(T)(T a) { writeln("min: ", a.mini()); writeln("max: ", a.maxi()); }
Apr 27 2012
prev sibling next sibling parent "so" <so so.so> writes:
On Friday, 27 April 2012 at 11:51:40 UTC, Steven Schveighoffer 
wrote:

 The idea I came up with in my proposal 
 (http://d.puremagic.com/issues/show_bug.cgi?id=6579) was to 
 allow aliasing the static method into the instance namespace:

 struct S1
 {
    static void foo() {}
    alias S1.foo this.foo;
 }

 struct S2
 {
    static void foo() {}
 }

 void main()
 {
    S1 i1;
    S2 i2;
    S1.foo(); // ok
    i1.foo(); // ok
    S2.foo(); // ok
    i2.foo(); // error
 }

 -Steve

But call site remains unchanged, which was the main reason of confusion. If we expect user to read the function declaration anyway, an extra alias won't do much good or probably complicate it even further.
Apr 27 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 27 Apr 2012 08:11:48 -0400, so <so so.so> wrote:

 On Friday, 27 April 2012 at 11:51:40 UTC, Steven Schveighoffer wrote:

 The idea I came up with in my proposal  
 (http://d.puremagic.com/issues/show_bug.cgi?id=6579) was to allow  
 aliasing the static method into the instance namespace:

 struct S1
 {
    static void foo() {}
    alias S1.foo this.foo;
 }

 struct S2
 {
    static void foo() {}
 }

 void main()
 {
    S1 i1;
    S2 i2;
    S1.foo(); // ok
    i1.foo(); // ok
    S2.foo(); // ok
    i2.foo(); // error
 }

 -Steve

But call site remains unchanged, which was the main reason of confusion. If we expect user to read the function declaration anyway, an extra alias won't do much good or probably complicate it even further.

Huh? The main reason of confusion is that the static method is named in such a way that it looks like an instance method. So we prevent that, unless the author of the class (who is deciding the name of the function) deems it should be called on instances example: struct File { static File open(string name) {...} // factory method this(string name); } File f = File("hello"); f.open("world"); // oops! Just opened file world and threw it away f = File.open("world");// better! I challenge you to name File.open some way where it *wouldn't* be confusing when called on an instance :) -Steve
Apr 27 2012
prev sibling next sibling parent "so" <so so.so> writes:
On Friday, 27 April 2012 at 12:35:53 UTC, Steven Schveighoffer 
wrote:

 Huh?  The main reason of confusion is that the static method is 
 named in such a way that it looks like an instance method.  So 
 we prevent that, unless the author of the class (who is 
 deciding the name of the function) deems it should be called on 
 instances

 example:

 struct File
 {
    static File open(string name) {...} // factory method
    this(string name);
 }

 File f = File("hello");

 f.open("world"); // oops!  Just opened file world and threw it 
 away
 f = File.open("world");// better!

With your proposal you can still do "f.open("world");" and get the same result if the author provided alias. You are trying to solve another problem, that the author should better state if this is intended. The problem i see is user assumming author is a smart guy. But at the end he finds out the author is as dumb as himself {he should have RTFM :)}
 I challenge you to name File.open some way where it *wouldn't* 
 be confusing when called on an instance :)

 -Steve

Easy! Don't call on an instance! openFile() out of the struct. I always add "make_" before any static function, otherwise static methods should be precise as http://forum.dlang.org/post/araqkvvgyspzmdecxqxi forum.dlang.org
Apr 27 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 27 Apr 2012 09:15:31 -0400, so <so so.so> wrote:

 On Friday, 27 April 2012 at 12:35:53 UTC, Steven Schveighoffer wrote:

 Huh?  The main reason of confusion is that the static method is named  
 in such a way that it looks like an instance method.  So we prevent  
 that, unless the author of the class (who is deciding the name of the  
 function) deems it should be called on instances

 example:

 struct File
 {
    static File open(string name) {...} // factory method
    this(string name);
 }

 File f = File("hello");

 f.open("world"); // oops!  Just opened file world and threw it away
 f = File.open("world");// better!

With your proposal you can still do "f.open("world");" and get the same result if the author provided alias.

The point is, don't provide the alias. Why would anyone do that in this case?
 You are trying to solve another problem, that the author should better  
 state if this is intended. The problem i see is user assumming author is  
 a smart guy. But at the end he finds out the author is as dumb as  
 himself {he should have RTFM :)}

There is no protection D could ever provide against dumb authors ;) He could have named it "close", or "r72" and the compiler is powerless to prevent this! It's useless to try and prevent such things, D compiler is not a psychologist. The problem I see here is that *smart* authors are inhibited from writing smart code.
 I challenge you to name File.open some way where it *wouldn't* be  
 confusing when called on an instance :)

 -Steve

Easy! Don't call on an instance! openFile() out of the struct. I always add "make_" before any static function, otherwise static methods should be precise as http://forum.dlang.org/post/araqkvvgyspzmdecxqxi forum.dlang.org

I like having open inside the struct, just a matter of preference. I think File.open implies better than it returns a File more than openFile. -Steve
Apr 27 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-27 07:07, H. S. Teoh wrote:
 Is this a bug? Code:

 	import std.stdio;

 	struct S {
 		static int func(int x) { return x+1; }
 		int func(int x) { return x+2; }
 	}

 	void main() {
 		S s;
 		writeln(s.func(1));
 	}

 DMD (latest git) output:

 	test.d(10): Error: function test.S.func called with argument types:
 		((int))
 	matches both:
 		test.S.func(int x)
 	and:
 		test.S.func(int x)

 The error message is unhelpful, but basically the complaint is that the
 static method is conflicting with the non-static method.

 But I would've thought it is unambiguous; I'd expect that s.func should
 resolve to the non-static method, and S.func to the static method. After
 all, no object is needed to invoke the static method, and the static
 method cannot be invoked without an object.

It's intended behavior but there's a suggestion to change that: http://d.puremagic.com/issues/show_bug.cgi?id=3345 -- /Jacob Carlborg
Apr 27 2012