U
U
user_of_toster2022-01-22 11:49:22
Java
user_of_toster, 2022-01-22 11:49:22

Why is contravariance associated with the Consumer?

The covariance of the producer is completely understandable Array<? extends Shape>- if the array returns figures, then it can also return a more specialized square. (Because square = figure)

But Consumer'a's contravariance is not intuitive Array<? super Square>. The fact that a square can be added to an array does not mean that a more abstract figure can be added there, and even more so Object.

What do I not fully understand?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
Mercury13, 2022-01-22
@user_of_toster

A little wrong.
1. Let Producer output an array of shapes. Then the child can set up a rule: it returns an array of more specialized shapes, such as circles. And the user who sees the Producer's contract, but does not know the specific implementation, will be within the scope of the contract.
2.Consumer canto establish a rule: it accepts an array of not only squares, but also figures, and in general game objects, and in general any objects. For example, the Consumer circular will cut out rectangles from plywood, the Consumer plotter will cut any shapes from thin lines, the Consumer game archive manager will cut shapes, textures, sounds, and in general everything that is in the game. Likewise, a user who sees a Consumer's contract but does not know a specific implementation will be within the scope of any implementation's contract.
In general, read " the Liskov substitution principle ". The offspring can tighten the requirements for themselves and relax the requirements for others. But not vice versa - otherwise we will substitute the ancestor type and exit the contract. Hence the name.
But: in Java with Producers, covariance works automatically.

public interface Producer {
    ArrayList<? extends Object> produce();    
}

public class MyProducer implements Producer {
    @Override
    public ArrayList<Square> produce() {
        return new ArrayList<>();
    }   
}

And with consumers, such automatic contravariance does not work, you have to manually check what the user submitted. There is no performance penalty here, Java's type erasure-based template functions constantly check objects to see if they belong to a class. Just an inconvenience.
public interface Consumer {
    void consume(ArrayList<? super Square> x);
}

public class MyConsumer implements Consumer {
    @Override
    public void consume(ArrayList<? super Square> x) {
        var a = (Square)x.get(0);
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question