1

I have three abstract classes:

public abstract class Shader

public abstract class ShaderInput

public abstract class ShaderOutput

The body of the Shader class is very simple:

    protected Function<ShaderInput, ShaderOutput> shader;

    public Shader(Function<ShaderInput, ShaderOutput> shader){
        this.shader = shader;
    }

    public ShaderOuput render(ShaderInput input){
        return shader.apply(input);
    }

I then have a VertexShader which extends Shader,

a VertexInput which extends ShaderInput,

and a VertexOutput which extends ShaderOutput

What I don't understand is why my constructor in my VertexShader class cannot be written as follows:

public VertexShader(Function<VertexInput, VertexOutput> vertexShader){
     super(vertexShader);
}

When I type the incoming Function as above, the IDE complains that

The constructor Shader(Function<VertexInput,VertexOutput>) is undefined

I would assume that because VertexInput extends ShaderInput and VertexOutput extends ShaderOutput that this would work and be able to provide more readability to the code.

CraigR8806
  • 1,584
  • 13
  • 21

1 Answers1

2

In your code, it would be possible to call render with any ShaderInput, e.g. of class SpecialInput extends ShaderInput, which is not compatible with VertexInput.

What you can do is change your classes like this:

public abstract class Shader<T extends ShaderInput, U extends ShaderOutput> {

  protected Function<T, U> shader;

  public Shader(Function<T, U> shader) {
    this.shader = shader;
  }

  public U render(T input) {
    return shader.apply(input);
  }
}

and

public class VertexShader extends Shader<VertexInput, VertexOutput> {

  public VertexShader(Function<VertexInput, VertexOutput> vertexShader) {
    super(vertexShader);
  }

}

Also see:

Sentry
  • 4,102
  • 2
  • 30
  • 38
  • why not directly say `public U render(T input) {` – Lino Dec 15 '17 at 12:44
  • @Lino Thanks, I missed that – Sentry Dec 15 '17 at 12:46
  • you might also want to change the `Function` to `Function super T, ? extends U>` which is more reliable. because a `Function super VertexInput, ? extends VertexOutput>` would not be allowed to be passed to `Shader` constructor – Lino Dec 15 '17 at 12:53
  • @Lino I'm sure you're right, but I can't quite follow your train of thought. Feel free to edit my answer, though, if it preserves correctness ;) – Sentry Dec 15 '17 at 13:42
  • A `Function super VertexInput, ? extends VertexOutput>` can accept a type that extends a `VertexInput` but which is not known and produces a Type that extends `VertexOutput` but which is also not known. This is a problem in the fact that you can't assign that `function` to `Function`. Maybe have a look yourself at [this link](https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super). Which should help you understand my point – Lino Dec 15 '17 at 13:46