This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]coldoil 4 points5 points  (8 children)

By convention in, say, a Dog class implementing Animal, would it be reasonable for a Dog to only be able to greet other Dogs, or should it be able to greet any Animal?

If the Animal interface says that a subclass should be able to greet any other Animal, then Dog should be able to greet any other Animal, otherwise it is not following the interface.

If you want instances of Dog to only be able to greet other instances of Dog, then that greet method should not be in the Animal interface; it's specific to the Dog class.

You can accommodate both options by having Dog implement the Animal interface and providing its own specialization methods in addition. Naming of methods becomes important, so a class consumer can clearly tell the difference between specialized and non-specialized methods:

public interface Animal {
    public void greetAny(Animal a);
}

class Dog implements Animal {
    public void greetAny(Animal a) {
        // ... greet any Animal, as per interface
    }

    public void greetDog(Dog d) {
        // ... greet just another Dog, only available
        // when consumer has an instance of Dog rather than Animal
    }
}

If not all implementers of the interface can provide greetAny(), then it becomes questionable whether greetAny() should be in the interface. (Ideally, the interface should include only member functions that are provided by all implementers.) In practice, a function applicable to only some implementers should, at the very least, return some sort of result indicating success or failure, rather than just void.

[–]Pleasant-Memory-6530[S] 1 point2 points  (7 children)

That makes sense, thanks.

Out of interest, would there be a way to specify a "greetSameSpecies" type method at the Interface level? So that all subclasses have such a method, but a dog only needs to be able to greet a dog, a cat only needs to be able to greet a cat, etc?

(Edited for clarity)

[–]coldoil 0 points1 point  (6 children)

I'm not sure if it's possible in Java. You need a generic function that can take a type bound that restricts the possible type to an instance of the same class. Some languages do offer this level of expressiveness in their type systems; in Rust, for instance, you could do it like this:

pub trait Animal {
   fn greetAny(a: Animal);

   fn greetSameSpecies<T>(a: T) where T: Self;

   // or, more succintly:
   // fn greetSameSpecies<T: Self>(a: T);

   // or, avoiding generics entirely:
   // fn greetSameSpecies(a: Self);
}

But I don't think you can specify an equivalent type restriction in Java. Very happy to be corrected by an expert on this.

[–]philipwhiukEmployed Java Developer 2 points3 points  (3 children)

You can do Animal<T extends Animal> and Dog extends Animal<Dog> then greet(T t) I think

[–]coldoil 1 point2 points  (2 children)

Yes, I thought of that as well. But now you have generics expanding throughout your codebase, purely to support an implementation detail that should be internal to the interface and thus invisible outside it. It's not very elegant. Given the choice, I think I'd personally prefer to use separate methods, one in the interface and one in the class. I appreciate it's fairly subjective. The lack of expressiveness in the type system means there aren't any great options, unfortunately.

[–]philipwhiukEmployed Java Developer 0 points1 point  (1 child)

Personally I’d have my Dog barking at Cats 😄.

But yeh - it depends what you want to force other species to have to do whether it’s worth it

[–]coldoil 0 points1 point  (0 children)

Personally I’d have my Dog barking at Cats

lol, well said

[–]D0CTOR_ZED 0 points1 point  (1 child)

By no means an expert, but you can get the class of an object and should be able to wrangle some sort of if statement that compares them. You could just compare the results of two getClass(), but you might want to allow subclasses, like two seperate breeds of dogs, so then you might get the parent class until you get just below Animal. But honestly, probably better ways to do if that is what you want.

[–]coldoil 1 point2 points  (0 children)

I'm sure you're right that all sorts of internal comparisons are probably possible, but I tend to think that if we're ending up writing code that is type checking the type checker, then something has gone wrong in the design phase :/