www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Reasons for current function overload spec

reply Sean Reque <seanthenewt yahoo.com> writes:
I did a search on this forum for function overloading and for HiddenFunc and I
didn't find anything, so I thought I would pose the question: is everyone
generally agreed that the way function overloading works in 2.0 is a good idea? 

I think anything that can cause runtime errors is generally something to be
avoided, and reading about how HiddenFuncErrors can be raised threw up red
flags for me as a bad thing. I can understand wanting to simpify things over
C++, but not being able to access publicly declared super class member
functions, not for technical reasons, but because of language design, and even
worse, not revealing the errors until runtime, seems to me like something that
will cause more problems in the long run than anything else. Today I finally
got gtkD to compile and run successfully on the dmd 2.008 compiler, and much
time was spent figuring out how to get a debugger working so I could get a
stack trace to track down a HiddenFuncError in a very long class hierarchy so I
could put in the correct alias declaration in the right class. This kind of
problem certainly doesn't exist in Java and C# as far as I'm aware.

So basically I just wanted to learn more about the justifications for this
design and how likely this feature will become permanent. 
Jan 04 2008
parent reply Sean Kelly <sean f4.ca> writes:
Sean Reque wrote:
 I did a search on this forum for function overloading and for HiddenFunc and I
didn't find anything, so I thought I would pose the question: is everyone
generally agreed that the way function overloading works in 2.0 is a good idea? 
 
 I think anything that can cause runtime errors is generally something to be
avoided, and reading about how HiddenFuncErrors can be raised threw up red
flags for me as a bad thing. I can understand wanting to simpify things over
C++, but not being able to access publicly declared super class member
functions, not for technical reasons, but because of language design, and even
worse, not revealing the errors until runtime, seems to me like something that
will cause more problems in the long run than anything else. Today I finally
got gtkD to compile and run successfully on the dmd 2.008 compiler, and much
time was spent figuring out how to get a debugger working so I could get a
stack trace to track down a HiddenFuncError in a very long class hierarchy so I
could put in the correct alias declaration in the right class. This kind of
problem certainly doesn't exist in Java and C# as far as I'm aware.

Do you mean function overloading or overriding? Sean
Jan 04 2008
next sibling parent Robert DaSilva <sp.unit.262+digitalmars gmail.com> writes:
Sean Kelly wrote:
 Sean Reque wrote:
 I did a search on this forum for function overloading and for
 HiddenFunc and I didn't find anything, so I thought I would pose the
 question: is everyone generally agreed that the way function
 overloading works in 2.0 is a good idea?
 I think anything that can cause runtime errors is generally something
 to be avoided, and reading about how HiddenFuncErrors can be raised
 threw up red flags for me as a bad thing. I can understand wanting to
 simpify things over C++, but not being able to access publicly
 declared super class member functions, not for technical reasons, but
 because of language design, and even worse, not revealing the errors
 until runtime, seems to me like something that will cause more
 problems in the long run than anything else. Today I finally got gtkD
 to compile and run successfully on the dmd 2.008 compiler, and much
 time was spent figuring out how to get a debugger working so I could
 get a stack trace to track down a HiddenFuncError in a very long class
 hierarchy so I could put in the correct alias declaration in the right
 class. This kind of problem certainly doesn't exist in Java and C# as
 far as I'm aware.

Do you mean function overloading or overriding? Sean

HiddenFuncError is cause by overriding overloaded functions so I would say both.
Jan 04 2008
prev sibling next sibling parent reply Sean Reque <seanthenewt yahoo.com> writes:
Sean Kelly Wrote:

 
 Do you mean function overloading or overriding?
 
 
 Sean

Jan 04 2008
parent reply Sean Kelly <sean f4.ca> writes:
Sean Reque wrote:
 Sean Kelly Wrote:
 
 Do you mean function overloading or overriding?


 Sean


Oh right, I'd completely forgotten this feature :-) The discussion took place in this forum a few months ago under the subject "Overloading/Inheritance issue." Here is a link to the first post: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=56295 Sean
Jan 04 2008
parent reply Sean Reque <seanthenewt yahoo.com> writes:
Thanks for the links! I was able to find through it two very long discussions
on this issue. One point that was brought up is that the reason D implements
overload resolution the way it currently does is because c++ did it the same
way for 20 years and no one complained. Well, a lot of post were made about
different aspects of the issue, so I want to just focus on the area I have the
biggest problem with. I didn't read EVERY post, but I hope this is a newer way
of looking at it. The following C++ program compiles fine:

#include <stdio.h>
class A {
	public:
	void print(int i) {
		printf("you gave me integer %d\n", i);
	}
};

class B : public A {
	public:
	void print(char c) {
		printf("you gave me character %c\n", c);
	}
};

void overload_res_test(A& a) {
	a.print(1);
}

int main() {
	B b;
	overload_res_test(b);
	return 0;
}

The following --equivalent-- D program crashes with a runtime exception that
can  be debugged as far as I know with a debugger:

class A {
	public:
	void print(int i) {
		printf("you gave me integer %d\n", i);
	}
}

class B : A {
	public:
	void print(char c) {
		printf("you gave me character %c\n", c);
	}
}

void overload_res_test(A a) {
	a.print(1);
}

void main() {
	scope B b = new B();
	overload_res_test(b);

}

Like I said in my first post, I had to spend a long time getting a debugger to
work when I tried compiling a hello world app with gtkD and I got a hidden
function error. The shadowed method declaration was about 7 classes up the
hierarchy, while the actual function that did the shadowing was about 3 or 4 up
the hierarchy. The worst part about this is that the error is only revealed at
runtime and only if the function is called under certain conditions. For a
strongly-typed compiled language, in my opinion this is disastrous, and it's
not what either C++ or Java does.
Jan 05 2008
next sibling parent Sean Reque <seanthenewt yahoo.com> writes:
Sean Reque Wrote:

 The following C++ program compiles fine:

 The following --equivalent-- D program crashes with a runtime exception that
can  be debugged as far as I know with a debugger:

I meant to say here that as far as I know this error can ONLY be debugged reasonably with a debugger. The final thing I had to note was that I recompiled the D program, declaring the functions as final, and it actually ran successfully. I recompiled the c++ program with the functions declared as virtual and it still ran fine. So the c++ function works for both virtual and static functions, while the D program works with static functions and crashes at runtime with virtual functions.
Jan 05 2008
prev sibling next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Sean Reque wrote

 The following --equivalent-- D program crashes with a runtime
 exception 

No crash on my machine XP32, dmd 1.029. -manfred
Jan 05 2008
parent reply sean reque <seanthenewt yahoo.com> writes:
Manfred Nowak Wrote:

 Sean Reque wrote
 
 The following --equivalent-- D program crashes with a runtime
 exception 

No crash on my machine XP32, dmd 1.029. -manfred

I'm using D 2.009, and the crashing behavior is part of the 2.0 spec. That's one reason why I was posting, to find out if this behavior is already permanently in the language or still in alpha.
Jan 05 2008
parent Manfred Nowak <svv1999 hotmail.com> writes:
sean reque wrote:

 crashing behavior is part of the 2.0 spec.

oops. Should have read your original post. -manfred
Jan 06 2008
prev sibling parent reply Sean Kelly <sean f4.ca> writes:
Sean Reque wrote:
 Thanks for the links! I was able to find through it two very long discussions
on this issue. One point that was brought up is that the reason D implements
overload resolution the way it currently does is because c++ did it the same
way for 20 years and no one complained. Well, a lot of post were made about
different aspects of the issue, so I want to just focus on the area I have the
biggest problem with. I didn't read EVERY post, but I hope this is a newer way
of looking at it.

Here are some of the posts that I was thinking of in particular: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=56391 http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=56414 http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=56418 The different overload resolution schemes between C++ and D may be a factor as well. Sean
Jan 05 2008
parent reply Jason House <jason.james.house gmail.com> writes:
Sean Kelly wrote:

 Sean Reque wrote:
 Thanks for the links! I was able to find through it two very long
 discussions on this issue. One point that was brought up is that the
 reason D implements overload resolution the way it currently does is
 because c++ did it the same way for 20 years and no one complained. Well,
 a lot of post were made about different aspects of the issue, so I want
 to just focus on the area I have the biggest problem with. I didn't read
 EVERY post, but I hope this is a newer way of looking at it.

Here are some of the posts that I was thinking of in particular:



 
 The different overload resolution schemes between C++ and D may be a
 factor as well.
 
 
 Sean

Wow... That's a pretty evil bug. I think I have to agree with Sean Reque in that this type of thing really can't sit around as a bomb at runtime. I was under the impression that shadowing superclass functions was an ERROR and that if a function was to be defined with the same name that it had to use the override keyword to make the programmer's intent clear. I'm almost certain that shadowing variables in functions is an ERROR. This seems even more evil. I'd really, really hope that a language that includes design by contract, unit testing, and enhanced const correctness would do a better job handling this class of problem. I'd expect some kind of specialized syntax to mark this type of questionable code as the programmer's intent. It seems to me that in the squareIt example, accessing a D instance via a B reference should be illegal... Maybe I should go back and read that whole thread on this topic before I post more...
Jan 06 2008
parent reply Robert DaSilva <sp.unit.262+digitalmars gmail.com> writes:
Jason House wrote:
 Sean Kelly wrote:
 
 Sean Reque wrote:
 Thanks for the links! I was able to find through it two very long
 discussions on this issue. One point that was brought up is that the
 reason D implements overload resolution the way it currently does is
 because c++ did it the same way for 20 years and no one complained. Well,
 a lot of post were made about different aspects of the issue, so I want
 to just focus on the area I have the biggest problem with. I didn't read
 EVERY post, but I hope this is a newer way of looking at it.


http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=56414 http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=56418
 The different overload resolution schemes between C++ and D may be a
 factor as well.


 Sean

Wow... That's a pretty evil bug. I think I have to agree with Sean Reque in that this type of thing really can't sit around as a bomb at runtime. I was under the impression that shadowing superclass functions was an ERROR and that if a function was to be defined with the same name that it had to use the override keyword to make the programmer's intent clear. I'm almost certain that shadowing variables in functions is an ERROR. This seems even more evil. I'd really, really hope that a language that includes design by contract, unit testing, and enhanced const correctness would do a better job handling this class of problem. I'd expect some kind of specialized syntax to mark this type of questionable code as the programmer's intent. It seems to me that in the squareIt example, accessing a D instance via a B reference should be illegal... Maybe I should go back and read that whole thread on this topic before I post more...

This happen when you overRIDE an overLOADed function, but you don't overRIDE all of the overLOADs.
Jan 06 2008
parent reply Jason House <jason.james.house gmail.com> writes:
Robert DaSilva wrote:
 This happen when you overRIDE an overLOADed function, but you don't
 overRIDE all of the overLOADs.

That sounds like something very easy to detect at compile-time. Are there practical situations with large ovrload sets where this would be a real pain for the programmer?
Jan 06 2008
parent reply James Dennett <jdennett acm.org> writes:
Jason House wrote:
 Robert DaSilva wrote:
 This happen when you overRIDE an overLOADed function, but you don't
 overRIDE all of the overLOADs.

That sounds like something very easy to detect at compile-time. Are there practical situations with large ovrload sets where this would be a real pain for the programmer?

In general, it's a bad idea to have overloaded virtual functions. A virtual function is a customization point; having overloads means that each customization has to be sure to overload them all in a consistent manner. Much better to have non-virtual overloads which forward to a single, general, virtual function. Then the problem disappears. I think that diagnosing overloaded virtuals would be entirely reasonable. -- James
Jan 06 2008
parent reply James Dennett <jdennett acm.org> writes:
Janice Caron wrote:
 On 1/7/08, James Dennett <jdennett acm.org> wrote:
 In general, it's a bad idea to have overloaded virtual functions.

Perhaps, but this is D, where member functions are virtual by default.

That's OK, it just makes writing safe code take a little more effort. Writing safe code has always taken effort. Sure, it's nice when the language helped rather than hindered, but no one language will get all trade-offs right. There are other reasons why a _programmer's_ default should be to make a function non-virtual, most significantly that writing (and designing) a solid specification for virtual functions is harder than for non-virtual functions as they have three components: what the default implementation does, what an override is required to do, and what the override is not allowed to do (e.g., if it's called when the object is not in a state which permits calling certain other methods on it). Most functions don't need that much complexity, and a type which has mostly virtual functions almost never has adequate documentation unless it's a pure interface. -- James
Jan 07 2008
parent reply Sean Reque <seanthenewt yahoo.com> writes:
James Dennett Wrote:
ps, but this is D, where member functions are virtual by default.
 
 That's OK, it just makes writing safe code take a little more
 effort. 

Well if everyone is agreed that virtual function overriding is a bad idea, could we at least get some kind of a warning message at compile time when it happens? If the compiler is smart enough to stuff the v-table with garbage functions, it could also inform us that it is doing so. Of course, I still don't agree that the compiler shouldn't be placing the --correct-- functions in the v-table. The way it is now, whenever a programmer decides to create a class that inherits from another, he has to understand the entire class hierarchy of that inherited class to be sure he doesn't accidentally override a function that disables the class from taking advantage of inclusion polymorphism. This HiddenFuncError feature breaks inclusion polymorphism, because having a class B inherit from class A no longer implies that an object of type B is fully capable of acting as an object of type A, regardless of whether or not the programmer intended to make it that way. That's a huge deal, because most of the advantage of OOP comes from this type of polymorphism, more so than encapsulation and data-aggregation. The fact that this important piece of information is only revealed under specific conditions at runtime is what makes it so dangerous. In my opinion, this alone makes D OOP inferior to that of most other modern languages. If this is going to be a permanent feature, then there should at least be a way to get a warning at compile time that a class is hiding functions from a superclass, which could cause your entire program to crash.
Jan 08 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
Sean Reque wrote:
 Well if everyone is agreed that virtual function overriding is a bad idea,
could we at least get some kind of a warning message at compile time when it
happens?

Warnings aren't part of the D spec, so compilers are free to implement them however thy like.
Jan 08 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 1/7/08, James Dennett <jdennett acm.org> wrote:
 In general, it's a bad idea to have overloaded virtual functions.

Perhaps, but this is D, where member functions are virtual by default.
Jan 07 2008