• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Paul Clapham
  • Ron McLeod
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Roland Mueller
  • Piet Souris
Bartenders:

Does overidden method with var-args parameters break polymorphism?

 
Ranch Hand
Posts: 218
13
VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A Dog is an Animal, so I'm expecting that anything an Animal can do, a Dog should be able to do.


But here, that seems to not be the case. Although I can call animal.makeNoise("C", "D"), that same method call on dog won't compile.

Does that not break polymorphism?
 
Saloon Keeper
Posts: 11127
88
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No, that is not an override. The compiler under Eclipse even issues a warning about it.
 
Bartender
Posts: 15743
368
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It does not break polymorphism.

Polymorphism allows you to swap the actual type of an object that a variable refers to without changing the validity of the program.

You didn't just change the type of the object that the variable refers to, you also changed the type of the variable itself. That is not covered by polymorphism.
 
Richard Hayward
Ranch Hand
Posts: 218
13
VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Carey Brown wrote:No, that is not an override


ok, I thought @Override at least gave a compile time message if the annotated method wasn't overriding something.

For example


Line 12 is ok because Dog.eat() does indeed override Animal.eat()

but javac gives an error at line 16 because Dog.bark() isn't overriding anything.

 
Rancher
Posts: 5184
84
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Richard - you are correct, that (your original code, before you edited the post and added more) is a legal override.  @Override would actually prevent compilation if it were not a valid override.  

I don't know what warning Carey sees in Eclipse... maybe some warning that there's no good reason to do this, since it limits your options when using a Dog reference.  But it is legal.  It doesn't break polymorphism though, in the sense that you can still use the method exactly the same as before, if you use a reference declared as Animal.  So it satisfies the substitution principle just fine.
 
Carey Brown
Saloon Keeper
Posts: 11127
88
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows ChatGPT
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Warning: "Varargs methods should only override other varargs methods"
 
Richard Hayward
Ranch Hand
Posts: 218
13
VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:
Polymorphism allows you to swap the actual type of an object that a variable refers to without changing the validity of the program.


So maybe I have a mistaken idea of what polymorphism means. Here, I 'swap the actual type of an object that a variable refers to'.


At line 18, instead of using a new Animal(), I use a new Dog() and the code still works.

It still seems weird though. By referencing the Dog via an Animal variable, I can invoke the Dog's makeNoise method with arguments that it shouldn't accept.
The compiler wouldn't allow:


I've noticed a similar thing with interfaces. An interface method with an int... parameter can be implemented by a method with an int[] parameter.

For example


 
Marshal
Posts: 28425
102
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, this is what Cary's compiler warning message is trying to say. The fact is that void makeNoise(String... noises) and void makeNoise(String[] noises) mean exactly the same thing and can be used interchangeably. So using both of them doesn't break polymorphism, it's just confusing.
 
Mike Simmons
Rancher
Posts: 5184
84
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:The fact is that void makeNoise(String... noises) and void makeNoise(String[] noises) mean exactly the same thing and can be used interchangeably.


Except when they can't, as shown in the first post in this thread.  When using a Dog reference, you can't call dog.makeNoise("M", "N"); you have to call dog.makeNoise(new String[] {"M","N"}) or ((Animal) dog).makeNoise("M","N").  When using an Animal reference, this problem goes away. I  don't think that breaks polymorphism, but it's not exactly interchangeable either.
 
Saloon Keeper
Posts: 5657
214
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What I do not get is that

does not compile, but

runs fine.
is still an instance of Dog, and I thought that at runtime the method of the dog-version would have been called, so it should at least not run. But it does. Perhaps it has been explained above and I missed it, but what am I missing?
 
Stephan van Hulst
Bartender
Posts: 15743
368
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You need to completely ignore the runtime type. The compiler only considers the type of expression that you're calling the method on. The compiler doesn't know what the runtime type of the expression is.

In dog.makeNoise("M", "N"), the compiler checks only the Dog class. Dog does not have a method that accepts two strings. It doesn't inherit makeNoise(string...) because it overrides it, and the overridden version doesn't have a varargs parameter.

In ((Animal) dog).makeNoise("O", "P"), the compiler checks only the Animal class. It doesn't know that the expression actually refers to a Dog. Animal has a method that accepts two string arguments by virtue of the varargs parameter.

Polymorphism doesn't come into play at all in deciding what method signature belongs to a specific method invocation, and it doesn't come into play at all in deciding what the correct syntax is to call a method with that signature. Overload resolution is done statically, at compile time.
 
Mike Simmons
Rancher
Posts: 5184
84
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There is something a little backward going on there, because when we override, we're not allowed to make a method more private, or change to an incompatible return type, or throw new checked exceptions.  But we are allowed to take away the vararg calling syntax, at least when using a reference of the new type.  I suspect that if varargs had been part of the language from the beginning, they might not have allowed that, for consistency.  But I think they might have chosen to allow it here, in order to make it easier for users to migrate to the  then-new feature of varargs.  This way, you can change the declaration of a method in a base class, moving from an array type argument to a vararg, without automatically breaking any subclasses that have not also been modified the same way.  The array and the vararg are equivalent, as far as overrides are concerned.  But the compiler still respects the behavior according to the declared type of a reference.  It's a weird compromise, but i think it made it easier to adopt the new feature.
 
reply
    Bookmark Topic Watch Topic
  • New Topic