4

I have had a bit of a problem a few times where I want to do something like this:

interface MyInterface
{
    public Validator<this.class> getValidator();
}

class MyInstance implements MyInterface
{
     public Validator<this.class> getValidator()
     {
          //do stuff
     }
}

So to be able to pass a reference to the concrete class as a generic parameter, it is often needed when you have classes that act on the current class. A simple solution is to use the ? type, but it's not ideal when you then need to access values in the class itself (eg. if you needed to do something like getValidator().validateForm().getField()) or even if you want to subclass a class with chained methods (like the StringBuilder.append())

The way I have usually had to do it like this:

interface MyInterface<T>
{
    public Validator<T> getValidator();
}

class MyInstance implements MyInterface<MyInstance>
{
     public Validator<MyInstance> getValidator()
     {
          //do stuff
     }
}

but that is quite ugly, and it is easy to accidentally put the wrong class as the parameter.

Are there any other solutions to this one?


Edit: The answers provided by 'Is there a way to refer to the current type with a type variable?' currently do not solve this problem (apart from the Scala answer)

FuzzyJulz
  • 2,714
  • 1
  • 16
  • 18
  • I'm not sure what `this.class` is supposed to represent. Is it supposed to represent `Class`? I'm not understanding your problem – Vince Dec 03 '15 at 03:02
  • I mean that it should reference the concrete class that extends the MyInterface, so in this case it should end up being MyInstance, but if another class(say AnotherInstance), extended MyInterface, the `getValidator()` would return a Validator – FuzzyJulz Dec 03 '15 at 03:06
  • as mentioned before this also is a problem for chained methods, so imagine you wanted to extend StringBuilder as a new class `ErrorBuilder`, and add another chained method, let's say `appendError()`, if you do `new ErrorBuilder().appendError("Error").append("Here")` that would work fine, as `appendError()` would return a class of `ErrorBuilder` however if you did `new ErrorBuilder().append("Here").appendError("Error")` it would fail, as append returns a StringBuilder! It would be ideal if you could have a signature like `public this.class append(String x)` – FuzzyJulz Dec 03 '15 at 03:11
  • 1
    The answers do not solve the problem, as it is not possible to solve your problem. What you want is not type-safe in the Java type system. See my answer. – Erwin Bolwidt Dec 03 '15 at 07:22

2 Answers2

2

I don't believe there's any other way than your "usual" to get exactly what you're after.

However, as an alternative, you might consider consider:

interface MyInterface {
    Validator<? extends MyInterface> getValidator();
}

where MyInterface also defines the accessor methods needed by validators. (Note that MyInstance's implementation could still return a Validator<MyInstance>.)

The visitor pattern might be another way to alter the design to work around this.

Brad Mace
  • 27,194
  • 17
  • 102
  • 148
0

What you want is not possible.

The reason is the same reason that you cannot assign a List<Dog> to a List<Animal>.

If what you want is possible, you could have an implementation:

class MyInstance implements MyInterface
{
     public Validator<MyInstance> getValidator()

However, in your interface, the return type of getValidator() was 'defined' as Validator<MyInterface> (since this.class referred to MyInterface in the context of the interface)

And you cannot assign Validator<MyInstance> to Validator<MyInterface>.

The reason for that is that, if you could do that, you could have another class that returns a Validator<MyOtherInstance> which you could also assign to Validator<MyInterface>. And when you then try to call methods on Validator<MyInstance>, you don't now whether it was one that was taking MyInstance or MyOtherInstance objects.

Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79