Should this work?

S

Steve Green

This gives the expected result "AB" if the class is declared as B b or cast
to B, but when it is declared "A b" it returns "AA". Should it?

public class A {}
public class B extends A {}
public class C {
public static void main(String[] args) {
A a = new A();
A b = new B();
C c = new C();
c.print(a);
c.print(b);
}

public void print(A a) { System.out.print("A"); }
public void print(B b) { System.out.print("B"); }
}
 
A

Andrew McDonagh

Steve said:
This gives the expected result "AB" if the class is declared as B b or cast
to B, but when it is declared "A b" it returns "AA". Should it?

public class A {}
public class B extends A {}
public class C {
public static void main(String[] args) {
A a = new A();
A b = new B();
C c = new C();
c.print(a);
c.print(b);
}

public void print(A a) { System.out.print("A"); }
public void print(B b) { System.out.print("B"); }
}

yes its working correctly.

When 'b' is declared as 'A b = ...' the 'b' reference is of the type
'A' regardless of the fact that the object it points to is of type B.

Therefore, when you do 'c.print(b)', you will be calling the print(A a)
method.

Its the reference Type that is used to determine which of the two
overloaded methods to call.

Therefore, if you did 'B b = ...' b's reference type would be 'B' and
so print(B b) would be called.

Andrew
 
S

Steve Green

Andrew McDonagh said:
Steve said:
This gives the expected result "AB" if the class is declared as B b or
cast to B, but when it is declared "A b" it returns "AA". Should it?

public class A {}
public class B extends A {}
public class C {
public static void main(String[] args) {
A a = new A();
A b = new B();
C c = new C();
c.print(a);
c.print(b);
}

public void print(A a) { System.out.print("A"); }
public void print(B b) { System.out.print("B"); }
}

yes its working correctly.

When 'b' is declared as 'A b = ...' the 'b' reference is of the type 'A'
regardless of the fact that the object it points to is of type B.

Therefore, when you do 'c.print(b)', you will be calling the print(A a)
method.

Its the reference Type that is used to determine which of the two
overloaded methods to call.

Therefore, if you did 'B b = ...' b's reference type would be 'B' and so
print(B b) would be called.

Andrew

Too bad, I had what I thought was a fairly eligant solution to a problem,
but now I need to clutter it up with casts and class comparisons.
 
A

Andrew McDonagh

Steve said:
Steve said:
This gives the expected result "AB" if the class is declared as B b or
cast to B, but when it is declared "A b" it returns "AA". Should it?

public class A {}
public class B extends A {}
public class C {
public static void main(String[] args) {
A a = new A();
A b = new B();
C c = new C();
c.print(a);
c.print(b);
}

public void print(A a) { System.out.print("A"); }
public void print(B b) { System.out.print("B"); }
}

yes its working correctly.

When 'b' is declared as 'A b = ...' the 'b' reference is of the type 'A'
regardless of the fact that the object it points to is of type B.

Therefore, when you do 'c.print(b)', you will be calling the print(A a)
method.

Its the reference Type that is used to determine which of the two
overloaded methods to call.

Therefore, if you did 'B b = ...' b's reference type would be 'B' and so
print(B b) would be called.

Andrew


Too bad, I had what I thought was a fairly eligant solution to a problem,
but now I need to clutter it up with casts and class comparisons.

why would you?
 
B

Bjorn Abelli

Steve said:
This gives the expected result "AB" if the class is declared as B b or
cast to B, but when it is declared "A b" it returns "AA". Should it?

public class A {}
public class B extends A {}
public class C {
public static void main(String[] args) {
A a = new A();
A b = new B();
C c = new C();
c.print(a);
c.print(b);
}

public void print(A a) { System.out.print("A"); }
public void print(B b) { System.out.print("B"); }
}

yes its working correctly.

When 'b' is declared as 'A b = ...' the 'b' reference is of the type 'A'
regardless of the fact that the object it points to is of type B.

Therefore, when you do 'c.print(b)', you will be calling the print(A a)
method.

Its the reference Type that is used to determine which of the two
overloaded methods to call.

Therefore, if you did 'B b = ...' b's reference type would be 'B' and so
print(B b) would be called.

Andrew

Too bad, I had what I thought was a fairly eligant solution to a problem,
but now I need to clutter it up with casts and class comparisons.

I wonder why you let "c" print out things based on what type "b" is in the
first place.

Why not turn the tables to IMHO a more "object-oriented" approach, to
delegate that to the actual object?


public class A {
public void print() { System.out.print("A"); }
}

public class B extends A {
public void print() { System.out.print("B"); }
}

public class C {
public void print() { System.out.print("C"); }

public static void main(String[] args) {
A a = new A();
A b = new B();
A c = new C();
a.print();
b.print();
c.print();
}
}


// Bjorn A
 
T

Thomas G. Marshall

Bjorn Abelli coughed up:
Steve Green wrote:
This gives the expected result "AB" if the class is declared as B
b or cast to B, but when it is declared "A b" it returns "AA".
Should it? public class A {}
public class B extends A {}
public class C {
public static void main(String[] args) {
A a = new A();
A b = new B();
C c = new C();
c.print(a);
c.print(b);
}

public void print(A a) { System.out.print("A"); }
public void print(B b) { System.out.print("B"); }
}

yes its working correctly.

When 'b' is declared as 'A b = ...' the 'b' reference is of the
type 'A' regardless of the fact that the object it points to is of
type B. Therefore, when you do 'c.print(b)', you will be calling the
print(A a) method.

Its the reference Type that is used to determine which of the two
overloaded methods to call.

Therefore, if you did 'B b = ...' b's reference type would be 'B'
and so print(B b) would be called.

Andrew

Too bad, I had what I thought was a fairly eligant solution to a
problem, but now I need to clutter it up with casts and class
comparisons.

I wonder why you let "c" print out things based on what type "b" is
in the first place.

Why not turn the tables to IMHO a more "object-oriented" approach, to
delegate that to the actual object?


public class A {
public void print() { System.out.print("A"); }
}

public class B extends A {
public void print() { System.out.print("B"); }
}

public class C {
public void print() { System.out.print("C"); }

public static void main(String[] args) {
A a = new A();
A b = new B();
A c = new C();

{brake screech here!}

C does not extend B. Poly-m cannot be achieved here in a statically typed
language.
 
A

Andrew McDonagh

Bjorn said:
...
...
Steve Green wrote:

This gives the expected result "AB" if the class is declared as B b or
cast to B, but when it is declared "A b" it returns "AA". Should it?

public class A {}
public class B extends A {}
public class C {
public static void main(String[] args) {
A a = new A();
A b = new B();
C c = new C();
c.print(a);
c.print(b);
}

public void print(A a) { System.out.print("A"); }
public void print(B b) { System.out.print("B"); }
}
snipped

I wonder why you let "c" print out things based on what type "b" is in the
first place.

Why not turn the tables to IMHO a more "object-oriented" approach, to
delegate that to the actual object?

Sometimes its not appropriate to give objects certain behaviors and so
in this example, it may not be appropriate to give the print behavior to
instances of A.

A real world example would be if A and B classes were Model classes
within an MVC triad. It would not be appropriate to give A or B the
ability to print().

However, having said that, there is another (well many other) way of
achieving what Steve wants in a more 'elegant' (i.e. without casting) way.

By using double dispatch, we can ask instance of A or B to call C back.
Then the correct overloaded method would be called because the 'this'
part of the updateMe(C c) method will either be an A or an B object
depending upon the type at runtime.

public class A {
public void updateMe(C c) {
c.print(this);
}

}

public class B extends A {}

public class C {
public static void main(String[] args) {
A a = new A();
A b = new B();

C c = new C();
a.updateMe(c);
b.updateMe(c);
}


public void print(A a) { System.out.print("A"); }
public void print(B b) { System.out.print("B"); }
}
 
B

Bjorn Abelli

...
C does not extend B. Poly-m cannot be achieved here in a statically typed
language.

Sorry, Typo. It was meant to extend B.

But you understood that anyway...

;-)


// Bjorn A
 
B

Bjorn Abelli

Bjorn Abelli wrote:

Sometimes its not appropriate to give objects certain behaviors and so in
this example, it may not be appropriate to give the print behavior to
instances of A.

A real world example would be if A and B classes were Model classes within
an MVC triad. It would not be appropriate to give A or B the ability to
print().

I imagined that "print" in the OP's case was only an example to illustrate
how to achieve different behaviours depending on type without the need of
casting.
However, having said that, there is another (well many other) way of
achieving what Steve wants in a more 'elegant' (i.e. without casting) way.

By using double dispatch, we can ask instance of A or B to call C back.
Then the correct overloaded method would be called because the 'this' part
of the updateMe(C c) method will either be an A or an B object depending
upon the type at runtime.

In both your and my example we delegate the "responsibility" of "guiding"
the behaviour onto the actual class, but as you say, there are many
different way to achieve this.

In the end it all boils down to what the actual application is supposed to
do, and what means would be appropriate in the specific case.

// Bjorn A
 
S

Steve Green

why would you?

Maybe I should explain my situation a little more clearly and what I am
actually trying to achive.
I have a hierarchy of classes that define the data of my application for
example:

class A {}
class B extends A {}
class MyData
{
Vector<A> data;
}
public class MyDataWriter {
public void writeXML(MyData md) { write(md); }
private void write(MyData md)
{
System.out.println("<mydata>");
for(A i : md.data) write(i);
System.out.println("</mydata>");
}
private void write(A a) { System.out.println("<A/>"); }
private void write(B b) { System.out.println("<B/>"); }
}

I didn't want MyData to know how to write itself, I wanted to keep the
classes simple.
I was hoping to deligate the printing to another class.
This way I could keep XML generation separate from the classes being
exported.
If I wanted to write it out differently in the future I just create another
writer and not clutter up the classes.

In the past I have implemented this as:

class A implements XMLWritable {}
class MyData implements XMLWritable {}

But I was hoping to put the logic all in one place.
Is there a better approach?

Thanks,
Steve
 
T

Thomas G. Marshall

Bjorn Abelli coughed up:
...


Sorry, Typo. It was meant to extend B.

But you understood that anyway...

;-)


// Bjorn A

Yep, sure. I only pointed it out though because the OP went out of his way
to /not/ have C related. His declarations were:

A a
A b
C c

But whatever---I of course prefer a clean old polymorphism like you
intended, any day of the week.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top