• Forum
  • Lounge
  • Why would the designers of Java think th

 
Why would the designers of Java think this was OK?

Pages: 12
Java: http://ideone.com/YT5GYX
C++: http://ideone.com/7jgXOO

So what's going on here? The C++ version correctly calls A::getResource() because those who designed C++ were smart enough to know that polymorphic function calls in constructors is bad news.

The Java version, however, incorrectly performs a polymorphic function call and invokes B::getResource() - however, since A has not finished being constructed, B hasn't even started being constructed yet, resulting in a huge problem.

But surely there's a way in Java to force it to perform a static function call instead of a polymorphic one, right?

http://stackoverflow.com/questions/17958493/java-bypassing-polymorphism

Wrong. There isn't. The designers of Java decided that constructors could only perform polymorphic function calls. What's that? You think you're safe if you only call private methods? You're wrong - inner classes can extend their outer classes and can override private methods.

The chance of this actually happening is pretty low, especially amongst good programmers (even ones who don't know of this quirk), but it's still incredibly dangerous.

My question is: Why on earth would the designers of Java think this was OK? I know it must have been a really old decision that can't be changed unless we jump from Java 1.x to Java 2.x, but that doesn't excuse the fact that the decision was made.

What's worse is that they could easily add a simple syntax to allow constructors to statically call methods rather than polymorphically, and yet they haven't and have no plans to (at least not in Java 8, which by the way won't be having lambdas after all).

This is beyond frustrating to me. The simple fact that it's not possible to port the C++ version to Java without changing the interface is unacceptable to me.

Yes, I'm angry. At least this issue doesn't affect me currently or I'd be even angrier. And yes I'm most definitely overreacting ;)
closed account (Dy7SLyTq)
huh thats good to know. there are so many issues with java class inheritance... so just out of curiosity, how did you discover that?
In my college level class today my professor was confused (as was I and several other students) at this behavior when we were taking a quiz 'as a class'.
closed account (Dy7SLyTq)
ah...

So what's going on here? The C++ version correctly calls A::getResource() because those who designed C++ were smart enough to know that polymorphic function calls in constructors is bad news.


<troll mode>
Unlike C++ Java was designed for programmers who know what they are doing and doesn't hold your hand. :P
</troll mode>

But seriously, all other languages have it solved the Java way - it is C++ which is different here. And IMHO Java's behaviour is much more consistent. If a method is not marked final nor private, this means I can override it. Why do you think overriding should not work for constructors if it works for all other methods?



This is beyond frustrating to me. The simple fact that it's not possible to port the C++ version to Java without changing the interface is unacceptable to me.


Oh, someone forgot to tell you Java is *not* C++, and C++ is not the only true way of implementing OOP.


What's worse is that they could easily add a simple syntax to allow constructors to statically call methods rather than polymorphically, and yet they haven't and have no plans to (at least not in Java 8, which by the way won't be having lambdas after all).


This would add complexity for no real value. People who work with Java for a longer than an assignment project demand totally different kinds of improvements (Oracle, value types or packed objects, please... IBM already did them).
Last edited on
<troll mode>
Unlike C++ Java was designed for programmers who know what they are doing and doesn't hold your hand. :P
</troll mode>

Yep, that's pretty much nothing more than content-free troll bait.


But seriously, all other languages have it solved the Java way - it is C++ which is different here.

That's a pretty broad statement. Untrue, too.


And IMHO Java's behaviour is much more consistent. If a method is not marked final nor private, this means I can override it. Why do you think overriding should not work for constructors if it works for all other methods?

If you define consistency only at the most trivial level. It is nevertheless the correct thing to do.

Why do you believe that I should be calling a derived class's methods from a constructor? Constructors should work on their own data and finish, then the derived class's constructor should do the same, all before considerations of polymorphic redirection.

Your argument would be valid if you were to point out that his original design appears flawed.

Oh, someone forgot to tell you Java is *not* C++, and C++ is not the only true way of implementing OOP.
Oh, someone forgot to tell you that LB never said anything like that. All he said is that he had to change his interface.

Your argument would be valid if you were to point out that it would be possible to do it without changing the interface.


So, troll off bud. C++ is far from a perfect language, and no one who actually knows anything about it will ever claim as much.

Unlike all the Java fruits out there who often claim that it is closer to perfection than their nemesis C++. Java has some horrific design flaws. That doesn't stop it from being useful and well-used.

So rather than go on the attack to defend poor, defenseless Java, why not offer some real advice?

Oh, "IMHO".
I did say (I thought I said) that a situation where this comes up is rare, but rare or not it doesn't seem the right way for Java to behave.

Constructors should work on their own data and finish, then the derived class's constructor should do the same, all before considerations of polymorphic redirection.


Who said so? I don't recall Alan Kay or any other OOP gurus stating that.

There are valid design patterns where you *want* to have constructor call the derived class, because you want to affect the initialisation of the class because you want to make initialization or part of the initialisation abstract. Or you need early initialization of the subclass (also very commonly requested in the community). Java's solution lets you abstract object initialisation, C++ does not. If you don't want this, just make the methods called from constructor private and/or final. Both cases covered.


Java has some horrific design flaws.


Sure it has. But this is not one of them.
If it was, it wouldn't be the same in C#, Scala, Object Pascal, Python, Ruby, PHP, ActionScript, JavaScript and probably a dozen of other languages I don't know.

I guess C++ is making up a nice theory for an accidental (mis)feature (it's not a bug, it's a feature!). It wasn't designed, it just happened so that many implementations did it this way and it became accepted as standard, even though it doesn't make much sense.


All he said is that he had to change his interface.


This doesn't say anything about language being well designed or not. He would have to change his interface if he translated that to Python, Ruby or JavaScript as well. Different languages, different things are considered correct.



Last edited on
rapidcoder wrote:
There are valid design patterns where you *want* to have constructor call the derived class, because you want to affect the initialisation of the class because you want to make initialization or part of the initialisation abstract. Or you need early initialization of the subclass (also very commonly requested in the community). Java's solution lets you abstract object initialisation, C++ does not.
Java's solution forces a specific behavior with no simple alternative. C++ defaults to one behavior and allows the other behavior via a simple change in syntax. Ok, nevermind - I was wrong. Apparently the compiler is really good at stopping me from shooting myself in the foot. In fact, it seems that you get undefined behavior when you try to get around the safety guards (a crash in my case).

Still, I think lazy initialization was invented for a reason.
Last edited on

Java's solution forces a specific behavior with no simple alternative


It allows *both*. Just don't call non-final, non-private methods from constructors. Simple as it is. Also, many tools actually catch those kind of bugs.
Also in C++, as well as in Java there are still plenty of ways to leak a partially constructed object to the outer world. If C++ wanted to be consistent, then it would have to prohibit any calls from constructors, especially to other objects. Every such call is a potential for leaking *this.
Last edited on
rapidcoder wrote:
It allows *both*. Just don't call non-final, non-private methods from constructors.
That requires changing the public interface of my example and is quite an annoying workaround.
Who said so? I don't recall Alan Kay or any other OOP gurus stating that.

Funny. Alan Kay can't stand Java.

There are valid design patterns where you *want* to have constructor call the derived class...

No there aren't. Such patterns exist, but they are well known in the Java community (as well as other OOP languages) as fail.

Polymorphism and constructors don't mix.

You really don't have to dig too hard to find people in the know saying the same thing. Don't call virtual methods from a constructor. Just don't do it.

Smalltalk does not work that way. And factory patterns that do are mistaken about the meaning of the factory pattern.

Sure it has. But this is not one of them.

Tell that to all the people on message boards constantly getting bit by this feature -- sometimes even when the JRT was updated and the program was not.

If it was, it wouldn't be the same in C#, Scala, Object Pascal, Python, Ruby, PHP, ActionScript and probably a dozen of other languages I don't know.

I'm not sure what you are saying here. I do know three of those languages, and a dozen or so more. I don't see how most of them apply to the argument as more than a bandwagon fallacy.

I guess C++ is making up a nice theory for an accidental (mis)feature (it's not a bug, it's a feature!). It wasn't designed, it just happened so that many implementations did it this way and it became accepted as standard, even though it doesn't make much sense.

I love it when people argue by rewriting history. It makes a lot of sense, and wasn't a mistake.

I don't have any interest in digging around to further this conversation, so, bye.

Funny. Alan Kay can't stand Java.


... and C++, too. But this is off-topic.


Don't call virtual methods from a constructor. Just don't do it.


Yep, this advice is spread mostly on C++ boards, because calling virtual methods doesn't work in C++ as everyone is expecting, especially in the most desired case - if you want to call pure-virtual method to abstract out initialization behaviour.

Again, I don't see any problem - if you feel this is an antipattern, simply don't use it. Make the method final and noone can override.


Tell that to all the people on message boards constantly getting bit by this feature


They are getting bit by C++ behaviour, not Java's.

Personally I've never run into problem because of this feature in Java, but I've run into a problem of inability to call pure virtual method when I was coding in C++ many times (and Java didn't exist at that time so no, it wasn't Java's influence). It is inconsistent, adds needless complexity and doesn't allow to use factory methods from the constructor, which is a very common and good pattern.


I don't see how most of them apply to the argument as more than a bandwagon fallacy.


This shows we're discussing a feature that is a matter of opinion. If it was considered a true design bug (or at least misfeature), most of people in the programming community would agree Java did that wrong and modern languages would take a different approach, e.g. from C++ (just like Scala fixed Java's exception model or generics or ripped out static). But most of them didn't, because Java's approach is cleaner and causes less confusion, even if it is still an antipattern. Simply not enough people are complaining about it and noone will change the world and make the language much more complex just to conform a very tiny minority like C++ coders switching to Java. Therefore you're wrong saying "this is the only correct way of implementing constructors".

So to summarize your complaint reduces to: "Java doesn't work like C++". I'm fine with that.

BTW: Just checked that D language also took the Java approach, which is funny because one of the goals of D was to be a better C++. So I guess most modern language designers consider C++ way of doing constructors "incorrect" not the Java's.
Last edited on
closed account (3qX21hU5)
Who would have thought this thread would turn into a Java vs C++ holy war... Weird...

Anyways I think you are being a bit to critical here LB. Programming languages are going to be different plain and simple. You can't really expect every programming language will do things the exact same way can you?
Last edited on
Just checked that D language also took the Java approach

indeed, D enforces two-step initialization, what a waste.

Looks like C++ is the only language where constructors actually construct things.
rapidcoder wrote:
They are getting bit by C++ behaviour, not Java's.
I beg to differ.

http://stackoverflow.com/questions/10404879/polymorphism-and-constructors

Even the answer states it is bad practice in Java.
Last edited on
Oh yeah, because someone said so on Stack Overflow. LOL.
Actually by following the reasoning of that answer, *any* overridable method is bad practice [1], because the base class may expect it to run differently.

General rule is: if the method is *not marked final nor private*, the base class is expecting it to be overriden. If it is not marked as final, yet unprepared for being overriden, then this is bad practice regardless it is called from the constructor or some other method.

As for SO posts:
http://stackoverflow.com/questions/496440/c-virtual-function-from-constructor
http://stackoverflow.com/questions/962132/calling-virtual-functions-inside-constructors?lq=1

So people are stumped with C++ behaviour too and there are probably much more, compare the number of votes for those C++ questions and for the Java one.


[1] Actually, prohibiting implementation overriding at all is not as crazy as it seems. I find it an antipattern. The only overriding accepted in my code is overriding an abstract method (pure virtual in C++) or empty implementation (adapter pattern). This eliminates the whole bunch of problems, including the one here discussed.
Last edited on
I see java and android as languages that you dont need to know you just look bits up and use them, I cant learn to use these languages freely like c++, it just doesnt make any sense to me why they do what they do, I just know that they do it.

Oh yeah, since Duoas didn't feel like finding a reference,

rapidcoder wrote:
It wasn't designed, it just happened so that many implementations did it this way
Stroustrup wrote:
It has been suggested that this rule is an implementation artifact. It is not so. In fact, it would be noticeably easier to implement the unsafe rule of calling virtual functions from constructors exactly as from other functions. However, that would imply that no virtual function could be written to rely on invariants established by base classes. That would be a terrible mess.

--http://www.stroustrup.com/bs_faq2.html#vcall
Pages: 12