views:

336

answers:

4

Is it possible (or even advisable) to cast the element retrieved from a for each statement in the statement itself? I do know that each element in list will be of type <SubType>.

I.E.:

List<BaseType> list = DAO.getList();  
for(<SubType> element : list){ 
    // Cannot convert from element type <BaseType> to <SubType>
    ...
}

rather than:

List <BaseType> list = DAO.getList();
for(<BaseType> el : list){
    <SubType> element = (<SubType>)el;
    ...
}
+6  A: 

Do you really know that each entry is going to be a subtype ? The DAO simply has to fulfill the List<BaseType> contract, and if you're assuming a subclass, then I think something is wrong somewhere. I'd perhaps concentrate more on getting the interface to the DAO correct, and have it contractually return what you want.

Brian Agnew
+1 for so eloquently stating the contract mechanism that interfaces should adhere to.
aperkins
Unfortunately the DAO code isn't ours. However, the feeds into the datasource are. We subclassed <BaseType> (the only such subclass) since we wanted additional functionality in the class. Since we control the input and we're only putting <SubType> objects in there I feel I can be fairly certain that the retrieved object will actually be one of <SubType>. If we controlled all the code, you would be 100% correct.
Carl Summers
@Carl - is it worth wrapping the DAO then, and providing a *different* interface that does what you want. Otherwise you'll have to convert all across your code base (potentially - I realise I'm making assumptions about how widely distributed this is)
Brian Agnew
Ahh, but to be able to always see the forest for the trees. That makes perfect sense. Thanks for the suggestion, I'll pass it along to those who make such decisions.
Carl Summers
+1  A: 

Possible, yes! but god forbid, Why? My early attempts in my career did that and I have learnt. Programming to interfaces always has an advantage. I always get questions from junior developers about handling cases where only subtypes have the methods/functionality required.

Say Animal class with Dog subtype having method bark(). They want bark() functionality. The actual challenge is that they want a behaviour of animal communication not bark() but animal speak(). So a new Cat sub class would not require meow(). What about this then:- My dog's form a pack, but cats don't. The answer pack() behaviour is not owned by a single dog. Pack is a different aspect, pass a pack to all objects and ask the objects to join the pack. (Visitor pattern/Adapter pattern). My Wolf class can use the same behaviour.

Am I rigid about this, no if it is only 1 off instance I am fine. If the answer is I am not sure, then you better play safe by working at interface contracts.

questzen
+2  A: 

For all the reasons stated by others, you shouldn't do this. However, if you cannot change the interface, the following is possible:

for (BaseType element : list) {
    SubType subType = (SubType)element;
    ...
}

As far as I know, this is the only way to do this and remain truly type safe - i.e. not rely on type erasure to catch any problems, which it will not necessarily do until much later.

I realize this is not EXACTLY what you were looking for, but it does handle the casting.

aperkins
I should note, that if you CAN change the interface, and it will ALWAYS be the SubType, you SHOULD change the interface, whether that is through a subclass extension or just changing it.
aperkins
To be really safe, you could do: if(element instanceof SubType)
jex
Very true - I should have put that.
aperkins
Very good, this is what I have been doing. I was hoping there was a shorter way, but I do see the wisdom in not having one.
Carl Summers
A: 

If you are not partial to Google collections, you can wrap the list with transform method. In your case it will be very efficient and totally compliant. I would put it as a wrapper method though as Brian has suggested.

public List< SubType > fromDao ( )
{
    // Put a comment for maintainer

    // Lists from DAO always contain SubTypes
    return
        Lists.transform(
            DAO.getList( ),
            new Function< BaseType, SubType >( )
            {
                public SubType apply ( final BaseType from )
                {
                    return (SybType) from;
                }
            };
}
Alexander Pogrebnyak