ELI5: Why cast to an interface?
Max Cerrina

Max Cerrina @alephnaught2tog

Joined:
Aug 23, 2017

ELI5: Why cast to an interface?

Publish Date: Dec 10 '17
12 11

So, I am super new to OOP and Java--specifically, just finishing up my first semester of it.

I understand interfaces are akin to contracts, and understand the uses of them; similarly, I understand casting, etc. I understand you can cast to an interface, but I don't get why you would want to. I've checked a number of books, a number of sites, read some arguments on the topic on SO, and have yet to actually get the point of doing so.

Specifically: if you had an interface called Forecastable and two classes, Weather and StockMarket, both of which implemented Forecastable--and thus must have the methods of the interface, and thus any object instantiated in them has access to those methods by definition--then what would the actual use be of casting either some Weather or StockMarket object be to Forecastable, if they can both already access those methods inherently?

Comments 11 total

  • Hamza
    HamzaDec 10, 2017

    If you cast to Forecastable, then that object can only access the methods of the interface, you can't access other methods in the Weather or StockMarket class.

    • Max Cerrina
      Max CerrinaDec 10, 2017

      Okay, that makes sense. But why would you want to do that?

      • Hamza
        HamzaDec 10, 2017

        You can do that for example to check whether some class implements an interface at runtime with a try catch block, if the cast fails then you can throw an error saying that the class should implement the interface, one example is to make a callback between Activity and Fragment in Android.

        • Lluís Josep Martínez
          Lluís Josep MartínezDec 11, 2017

          This would be a programming error and you shouldn't use the Exception mechanism to catch errors.

      • W. Brian Gourlie
        W. Brian GourlieDec 10, 2017

        One reason is that you want to ensure that no methods that aren't part of the contract are called on the object. If the interface represents a contract, yet you can call a method that isn't on the interface, in a sense, the contract has been broken!

        I will say that it's somewhat odd to cast a type to accomplish this. Typically you would either instantiate an object of the interface type, for example:

        MyContract contract = new MyContractImpl();
        

        Or, you make sure your methods accept only the contract, and not the implementation:

        void doSomething(MyContract contract) {
            ...
        }
        

        This way, even though the underlying type is a MyContractImpl, you won't be able to call methods on it that aren't a part of MyContract!

  • Evan Oman
    Evan OmanDec 11, 2017

    Casting to an interface allows you to pass/refer to objects with the same behavior.

    For example, if you wanted to make a report from a bunch of forecasts you could write code like this:

    /* Collect some forecastable things */
    List<Forecastable> forecastables = Arrays.asList(nycWeather,frankfurtWeather, nyse, dax);
    
    /* Get the forecasts themselves */
    List<Forecast> forecasts = forecastables.stream()
        .map(Forecastable::getForecast)
        .collect(Collectors.toList());
    
    /* Add the forecasts to our report */
    report.addForecasts(forecasts);
    

    Here you can see that we only need the Forecastable subset of these objects' functionality so we cast them to the interface.

  • edA‑qa mort‑ora‑y
    edA‑qa mort‑ora‑yDec 11, 2017

    There are only a few situations where I've explicit cast to an interface:

    • I am downcasting from a less-specified type, such as object or a base class. That is, an implicit cast doesn't work in these situations.
    • I'm trying to call an interface function in C# which is exposed only on the interface (it's a C# oddity)
    • I'm forcing selection of a function overload where multiple might work (such as when a class implements multiple interfaces and both have functions). This is a hack and usually indicates an API defect.

    The idea of casting to an explicit interface just to limit the interface, used locally in a function, seems like an anti-pattern to me: the function is mixing multiple divergent purposes. If you have the full object then you can use it. If you're making generic code then put it in a function that takes only the interface.

  • Miff
    MiffDec 11, 2017

    I don't really see a reason to explicitly downcast to an interface, but there are two situations I see about casting to an interface: when upcasting (when you don't know in advance if the object you're working with implements the interface) and the second is implicit casting (when you're calling code that operates on the interface only).

  • Lluís Josep Martínez
    Lluís Josep MartínezDec 11, 2017

    When you invoke a legacy method that returns Object or a very bad designed API. In these cases if you can't refactor the method (if it's an old version of Hibernate for instance) you have no other option than casting. I use to create wrappers over this kind of methods to generify them. Once they're generified you can remove all the casts.

  • (((Florian Schätz)))
    (((Florian Schätz)))Dec 12, 2017

    Every point of code should only see the minimum amount of stuff it needs to see. The less it sees, the less complexity it has to deal with and thus it itself will probably less complex.

    This is not only trivially true for methods, where using the interface as a parameters also makes it a lot more generic, but even when designing interfaces: Implementing multiple smaller interfaces are preferable over big composite ones, because if your interfaces are big, the code sees a lot of stuff that it doesn't actually need. With multiple smaller interfaces, the code can work with the one that it actually needs and doesn't even see the other stuff. This is, I believe, called the interface segregation principle (see en.wikipedia.org/wiki/Interface_se...).

    Where does this lead? It leads us to almost automatically casting to the interface. When we write something like this...

    Weather weather = new Weather();

    ...we immediately ask ourselves: "Does the code that follows actually need the complete Weather? Or will all following code work fine with a Forecastable?" In the later case, we can immediately replace it with...

    Forecastable forecastable = New Weather();

    ...since we know that we don't actually care that it's Weather. Of course, if we do care, we need to work with Weather - but perhaps we can return it as a humble Forcastable, because nobody outside the method creating it actually cares?

Add comment