8

I am considering whether it is better to have two pointers, one for each object sub class and super, or whether I should just use casting.

How much system resources does this use:

objectName.functionOne();
((SubClass) objectName).functionOther();

Is it better than:

SuperClass objectA = (SuperClass) getSameInstance();
SubClass objectB = getSameInstance();
objectA.functionOne();
objectB.functionOther();

Basically, my main question is about the resources used with casting, versus making an extra pointer. It seems like I could save several in line casts, such as:

((SubClass) objectName).functionOther();

However, is it worth it?

Thanks,
Grae

UPDATE:

There were some unclear parts to my question. Basically, I have a super class that I am using through out a large function. It works with three subclasses. Some the super class is working as I would like. However, I hit a road block in a few places where I have to use a function from one of the three different subclass; a function that is only in one of the subclasses.

I could just have:

SuperClass instanceRef;
SubClass instanceRef2;

instanceRef.etc()
instanceRef.etc2()
instanceRef.etc3()
instanceRef2.specialSubClassOnlyCall();
instanceRef2.specialSubClassOnlyCall2();

or I could have:

SuperClass instanceRef;

instanceRef.etc()
instanceRef.etc2()
instanceRef.etc3()
((SpecialSubClass)instanceRef).specialSubClassOnlyCall();
((SpecialSubClass)instanceRef).specialSubClassOnlyCall2();

However, I don't know which is more efficient.

UPDATE 2:

Here is an example to show you what I am talking about:

class Shape
Triangle extends Shape
Square extends Shape
Circle extends Shape
Cube extends Shape

The Two Pointer Example: (Downside an extra pointer.)

Shape pointer1 = (Shape) getSomeRandomShape();
Cube pointer2 = null;

pointer1.getWidth();
pointer1.getHeight();
pointer1.generalShapeProp();
pointer1.generalShapeProp2();
pointer1.generalShapeProp3();

if(sure_its_cube)
{
   pointer2 = (Cube) pointer1;
   pointer2.getZAxis();
   pointer2.getOtherCubeOnlyThing();
   pointer2.getOtherCubeOnlyThing2();
   pointer2.getOtherCubeOnlyThing3();
   pointer2.getOtherCubeOnlyThing4();
}

Or I could do it this way. (Downside a bunch of casts.)

Shape pointer1 = (Shape) getSomeRandomShape();

pointer1.getWidth();
pointer1.getHeight();
pointer1.generalShapeProp();
pointer1.generalShapeProp2();
pointer1.generalShapeProp3();

if(sure_its_cube)
{
   ((Cube)pointer1).getZAxis();
   ((Cube)pointer1).getOtherCubeOnlyThing();
   ((Cube)pointer1).getOtherCubeOnlyThing2();
   ((Cube)pointer1).getOtherCubeOnlyThing3();
   ((Cube)pointer1).getOtherCubeOnlyThing4();
}

So is five casts worse than one extra pointer? What is it was six casts, or 20? Is one cast worse than the pointer.

Grae

Community
  • 1
  • 1
GC_
  • 1,673
  • 6
  • 23
  • 39
  • It is not good practice to maintain two, can you post your actual problem so that we can suggest better design. I didn't down vote – jmj Oct 19 '10 at 13:36
  • Casting to the superclass should be free. And about how many pointers are we talking here? Is it just a few local variables or thousands? – CodesInChaos Oct 19 '10 at 13:41
  • 2
    Worth reading the answers to this question on the overhead of casting - http://stackoverflow.com/questions/2170872/does-java-casting-introduce-overhead-why – Tom Castle Oct 19 '10 at 13:46
  • http://stackoverflow.com/questions/2170872/does-java-casting-introduce-overhead-why/2171477#2171477 is what you are looking for. – Robert Munteanu Oct 19 '10 at 15:09
  • I choose Péter Török, because he wrote, "Optimize only when you know that you need to, and have proven (using a profiler) where the bottleneck is within your code," which I think is good advice. – GC_ Oct 24 '10 at 22:43

6 Answers6

20

Do whatever makes the code clearer, forget about micro-optimizations.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • It just seems like I should know how much resources a downcast uses, before I replace it with the allocation of another pointer. I get your point about it being small, but it just seems like I should know what I am doing. It is just like O-big for me. Suppose I have 10 downcasts, is that worth than one extra pointer? – GC_ Oct 19 '10 at 17:40
  • 1
    @Grae - This advice isn't about "I should know what I am doing" its about "someone else should understand what you did" – Ivan Oct 19 '10 at 17:44
  • @Grae: What you should do is *stop even thinking about it!* Seriously, this kind of thing is a complete waste of brain time that would be much better used to make the code correct and easy to understand. – Michael Borgwardt Oct 19 '10 at 18:00
  • I fully agree, but I have strong opinions on what is more readable! I really dislike identical code that is repeated several times. Every time you look at it, you have to make sure *again* that it is indeed identical. So I nearly always use the first variant with the extra pointer variable. This also takes away any doubts that repeated expressions that start like `o.getThis().getThat().getOther()....` really work on the same object, don't repeat expensive calculations, and don't have side effects multiple times. – Olaf Seibert Nov 25 '15 at 14:13
12

It seems from your code snippet that getSameInstance() returns a SubClass. In this case the simplest solution is

SubClass objectB = getSameInstance();
objectB.functionOne();
objectB.functionOther();

No casts, no worries :-)

As others have rightly noted, the primary concern should be code readability and simplicity, not performance. Optimize only when you know that you need to, and have proven (using a profiler) where the bottleneck is within your code. Even in this case, micro-optimization is rarely useful in Java.

An additional note: calling the same method twice can be problematic if the method is heavy (in which case you are effectively making your code slower, not faster), or has side effects (in which case the behaviour of your program may noticeably change).

And btw in this line of your code snippet

SuperClass objectA = (SuperClass) getSameInstance();

there is absolutely no need to upcast the returned value to SuperClass - a superclass reference can always point to a subclass object. (I guess that such an upcast would be omitted by the compiler anyway, so it makes no difference in the bytecode.)

Update

You still haven't published the declaration of the method I asked for. But from your explanation I presume it should look something like

public Shape getSomeRandomShape();

is this correct?

This would btw mean that your 2nd original code snippet (with the getSameInstance() call) is incorrect - the casts should be the opposite way. You managed to confuse me with it, so you got a confusing answer :-)

Also in the latest examples, you don't need to cast the returned value to a (Shape), since it is already a Shape. The cast is just cluttering your code. Similarly, the many casts in the 2nd example of your UPDATE 2 are making the code hard to read. I would prefer the first version, with two references (not pointers btw - Java has no pointers).

And I care only about code readability here - as others have already noted, you should really, really not waste your time thinking about the cost of casts. Just focus on making your code as simple and readable as possible. You would most likely never ever going to notice the tiniest bit of difference between the performance of the two code snippets you show above (unless maybe if they are executed in a tight loop millions of times - but then, I guess, the JIT would optimize the casts away anyway). However, you will notice the difference it takes in time to understand one code snippet versus the other, for someone who is new to this code - or someone who has forgotten the details already, which could be you in about 6 months.

Community
  • 1
  • 1
Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • 1
    +1 - in my view this is the best answer, you should only need the SubClass pointer, inheritance takes care of the rest – mikera Oct 19 '10 at 13:43
  • getSameInstance would be getting the subclass, not the super class. – GC_ Oct 19 '10 at 16:28
  • @Grae, nice, then my suggestion above works and you need no casts indeed. – Péter Török Oct 19 '10 at 20:11
  • There is however more than one type of subclass. – GC_ Oct 20 '10 at 13:00
  • @Grae, now this is getting confusing. Note that the static type of the object returned may be different from its dynamic type. E.g. a method may be declared as `Object getSomeObject()` and may return a `String`, whereas the static type of the returned object is `Object`, the dynamic is `String`. I was referring to the static type the whole time - are you talking about the dynamic type? Or do you mean that `SubClass` has further subclasses? Please post the exact signature of `getSameInstance()` to clarify. – Péter Török Oct 20 '10 at 13:16
  • The part I think you are missing, is that there is more than one subclass. I am going to add something more to the question. – GC_ Oct 21 '10 at 01:31
3

Casting is not an "operation" that is done at runtime. It's just needed by the compiler to assure you static type safety.

Just looked at JVM code, the two approaches are basically equivalent, they are implemented as

CHECKCAST Main$B
INVOKEVIRTUAL Main$B.mySubMethod()V

so a small overhead is present, but it's the same in both cases (since you gotta do a downcast anyway).

Jack
  • 131,802
  • 30
  • 241
  • 343
2

Readability and code maintenance should be your priority in something like this, not performance, unless you actually hit a bottleneck (extremely unlikely).

However, there is no reason to have two references (pointers). Just reference the subclass. Anything you could do with the superclass reference you can do with the subclass reference, in almost all cases (a parameter to an overloaded method is the only exception I know of).

Yishai
  • 90,445
  • 31
  • 189
  • 263
  • in cases of method overloading you can cast the parameter to the parent type for free anyway. The static link is changed but the cast is thrown away, as is any up-cast that is statically known to succeed. – Mark Peters Oct 19 '10 at 13:42
1

Just go with whichever solution is easier to read and cleanest to maintain (likely the first solution). At that low a level of optimization, it's really not worth it except in edge cases where you really need the extra 0.01% performance improvement.

For what it's worth, you don't actually need to cast a subclass to a superclass reference (second solution listed), only the other way around. When casting a superclass to a subclass, it's generally preferred verify its type with instanceof prior to the cast rather than making assumptions.

Ophidian
  • 9,775
  • 2
  • 29
  • 27
0

Lets say you have a 64-bit machine and it saves 8-bytes of resources. Lets say you have spent 10 minutes think about it. Was it a good use of your time?

1 GB adds about $100 to the cost of a server so 8 bytes cost about $0.0000008

10 minutes of you time is worth about $1 on minimum wage.

The resource is reusable, your time is not. More importantly the time of anyone reading/ supporting your code is likely to be even more expensive and that is why simplicity/clarity is far more important.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Now let's say that this code is repeated a few thousand times in my codebase. And now lets say that it's running on a billion devices around the world. Now is it worth it? – Andrew Rose Jan 02 '14 at 12:03
  • @AndrewRose If you are saving 8 * 3000 * one billion that is a ~24 TB, so yes that would matter. It is perhaps worth spending about $240,000 except you should consider that you will be paying for the redevelopment whereas you won't be paying for the memory unless it is a problem for your end users. i.e. the redevelopment costs you, the memory maybe not. – Peter Lawrey Jan 02 '14 at 12:16