6

Requirements

I am trying to write an Observer / Observable pair of classes. I want to parametrize the Observer so that a type safe update call is possible. Imagine this version:

class View implements Observer<Model> {
    @Override
    public void update(Model model) { render(model); }  // no casting:)
}

Instead of this version that needs casting:

class View implements Observer {
    @Override
    public void update(Object model) { render((Model) model); }  // casting:(
}

Attempt

Here's what I have so far. My Observer interface:

public interface Observer<T extends Observable> {
    public void update(T observable);
}

and my Observable abstract class:

import java.util.List;

public abstract class Observable {
    private List<Observer<? extends Observable>> observers;

    public Observable() {
        System.out.println(this.getClass());
    }

    public void addObserver(Observer<? extends Observable> obs) {
        observers.add(obs);
    }

    public void removeObserver(Observer<? extends Observable> obs) {
        observers.remove(obs);
    }

    protected <E extends Observable> void updateObservers(E self) {
        for (Observer<? extends Observable> obs : observers) {
            obs.update(self);  // <-------------------- COMPILER ERROR!!!
        }
    }
}

Problem

The line labeled "COMPILER ERROR" has a problem with the .update():

The method update(capture#4-of ? extends Observable) in the type Observer is not applicable for the arguments (E)

So even though the self argument passed to update() is of type E extends Observable, it does not satisfy the interface method signature update(T observable); where T extends Observable. Why is that? I really expected those to be compatible.

Is there I can fix this to meet my requirements?

Thanks.

kdbanman
  • 10,161
  • 10
  • 46
  • 78
  • Just because `E` extends `Observable` doesn't mean that it'll extend any class that extends Observable (as in the wildcard ` extends Observable>`. – nanofarad Feb 22 '15 at 01:40
  • @hexafraction, It seems the compiler agrees with you! You must be right, but I just can't imagine it. Can you provide an example? A case where `E extends Observable` is true, but it does not "extend any class that extends Observable"? – kdbanman Feb 22 '15 at 01:53
  • Here's a counterexample: `class A extends Observable`, `class B extends Observable`, `class A1 extends A`. The wildcard for `obs` would allow an `Observer` to be assigned to `obs`, and in that case calling `obs.update()` with an instance of A1 would be invalid. My wording the first time was a bit off. – nanofarad Feb 22 '15 at 01:55
  • @hexafraction, interesting. Thank you. Maybe I could find a way to tighten up the type bounds on obs (the List contents). Evidently the wildcard `? extends Observable` is too loose. Maybe if I parametrize the Observable class by subclasses of itself... – kdbanman Feb 22 '15 at 02:28
  • @hexafraction, it worked!! Thanks so much for your help. I'll self answer below and reference your commentary. – kdbanman Feb 22 '15 at 02:53

4 Answers4

12

Use import io.reactivex.Observable;

instead of import java.util.Observable;

user1555123
  • 377
  • 3
  • 4
4

Why is that? I really expected those to be compatible.

Because the function public void update(T observable); has the same generic argument T as the Observer<T extends Observable> class, which means that it's argument type should be the same as the type of the reference variable which will invoke the update() function.

While, when you try to use the wildcard ? then the type of the variable obs is Observer<? extends Observable> which could be any different class that extends Observable than the type of the method arguments which is E.

Is there I can fix this to meet my requirements?

Yes, using the Self Bound / Recursive Generics, a concrete example is the Class Enum<E extends Enum<E>>, to understand this concept you can take a look at the See also section below.

So, your Observable will be something like:

import java.util.List;

public abstract class Observable<T extends Observable<T>> {
    private List<Observer<T>> observers;

    public Observable() {
        System.out.println(this.getClass());
    }

    public void addObserver(Observer<T> obs) {
        observers.add(obs);
    }

    public void removeObserver(Observer<T> obs) {
        observers.remove(obs);
    }

    protected  void updateObservers(T self) {
        for (Observer<T> obs : observers) {
            obs.update(self);  
        }
    }
}

The Observer interface:

public interface Observer<T extends Observable<T>> {
    public void update(T observable);
}

The View class:

class View implements Observer<Model> {
    @Override
    public void update(Model model) { render(model); } 
}

Assuming that your Model class should be something like this:

public class Model extends Observable<Model>{

}

See also:

Community
  • 1
  • 1
Tarik
  • 4,961
  • 3
  • 36
  • 67
  • Wow. We answered with the *exact* same solution within minutes of each other. (I self answered after research and helpful prodding.) – kdbanman Feb 22 '15 at 03:11
  • ok, no problem then, the important is that you solved your issue :) – Tarik Feb 22 '15 at 03:12
  • "self-bounded generics" is almost *never* useful in Java. `Observable` should just be declared as `public abstract class Observable` and `Observer` declared as public interface `Observer`. It compiles just as well. – newacct Feb 22 '15 at 10:34
  • 1
    @newacct it's not only about compiling, there is many other solutions to compile well, following what you said there will be also no need to use even the `` ! But, the OP don't want that the `T` in `Observer` to be any class, he want it to be a class that extends the `Observable` class, do you have any other solution without using self-bounded generics? Meanwhile, I don't agree with you when you said that it's "is almost never useful in Java." if that is the case could you explain why they are used in Enum definition? – Tarik Feb 22 '15 at 12:56
  • @Tarik: "following what you said there will be also no need to use even the " It is about compiling *with type safety*, without casts. Without generics, this would require a cast. However, the bounds do not serve any purpose in eliminating casts. "But, the OP don't want that the T in Observer to be any class, he want it to be a class that extends the Observable class" But such a restriction doesn't serve a type-safety purpose. An `Observer` whose type argument doesn't extend `Observable` is not in itself unsafe, even if it may not be as useful. – newacct Feb 22 '15 at 20:35
  • @Tarik: "if that is the case could you explain why they are used in Enum definition?" There is absolutely no reason it is used in `Enum`. This I can say for sure. Any code that compiles now will still compile if `Enum` were declared as `class Enum`. While "self-bounded generics" is sometimes useful in builder patterns where an instance needs to return its own type from an instance method, `Enum` does not have a method that returns its own type. – newacct Feb 22 '15 at 20:36
  • @newacct This is interesting and I'am thinking to ask that in a question to understand more the reasons, may I quote your comment in case I asked a question ? – Tarik Feb 22 '15 at 20:43
  • 1
    @newacct there is already a very clear and detailled answer here: http://stackoverflow.com/questions/3061759/why-in-java-enum-is-declared-as-enume-extends-enume – Tarik Feb 22 '15 at 21:30
  • @Tarik: Nope, there is not a single answer anywhere that points out any advantage of `class Enum>` over `class Enum`. – newacct Feb 23 '15 at 08:14
  • I think Jon skeet's answer explaining the advantage when using Comparable is the one we are looking for: http://stackoverflow.com/a/211161/4170582 – Tarik Feb 23 '15 at 15:03
  • @Tarik: Please use `@` when responding to comments. I think you read the statement backwards -- it's explaining why it is NOT an advantage. – newacct Feb 25 '15 at 05:07
  • @newacct sorry I was responding from my phone so sometimes the "@" doesn't work correctly with me :) I will reread that answer tomorrow and reply – Tarik Feb 25 '15 at 05:07
2

Problem

As per @hexafraction's commentary,

The Observable's List of the Observers is parametrized by any subclass of Observer (wildcard <? extends Observer>). This does not play nice with Observer<T extends Observable>'s update(T observable) method, which is expecting exactly the type of Observable which the Observer was parametrized by.

Here's a counterexample: class A extends Observable, class B extends Observable, class A1 extends A. The wildcard for obs would allow an Observer to be assigned to obs, and in that case calling obs.update() with an instance of A1 would be invalid.

Solution

The solution is to parametrize the Observable class as well, so that the List contents are constrained correctly for the Observer update() method:

public abstract class Observable<E> {
    private List<Observer<E>> observers;

    public Observable() {
        observers = new ArrayList<>();
    }

    public void addObserver(Observer<E> obs) {
        observers.add(obs);
    }

    public void removeObserver(Observer<E> obs) {
        observers.remove(obs);
    }

    protected void updateObservers(E self) {
        for (Observer<E> obs : observers) {
            obs.update(self);
        }
    }
}

And the Observer parametrized by its own T:

public interface Observer<T> {
    public void update(T observable);
}

If you need type constraints such that Observers may only observe Observables, and/or Observables may only send Observables to Observer updates, then use these class signatures:

public interface Observer<T extends Observable<T>> { ... }
public abstract class Observable<E extends Observable<E>> { ... }

The class bodies and behaviors are unaffected, but the compiler will complain if Observers and Observables are bound to anything but each other.

Usage

Parametrize an Observer (View) by the Observable (Model):

class View implements Observer<Model> {
    @Override
    public void update(Model model) { render(model); }  // no casting:)
}

Parametrize an Observable (Model) by itself and call updateObservers():

class Model extends Observable<Model> {
    public void doStuff() {
        //...
        updateObservers(this);
    }
}
kdbanman
  • 10,161
  • 10
  • 46
  • 78
  • The bounds are unnecessary. `Observable` should just be declared as `public abstract class Observable` and `Observer` declared as public interface `Observer`. It compiles just as well. – newacct Feb 22 '15 at 10:34
  • Just tested that - you're right! I'm not a fan of unnecessary constraints, so I'll cite you and fix my answer. – kdbanman Feb 22 '15 at 19:02
0

Change the Observer interface like below :

public interface Observer<T extends Observable> {
    public <E extends Observable> void update(E observable);
}
Suat Keskin
  • 116
  • 5
  • 1
    Actually the problem was that the Observable's list of Observers was too loosely constrained for use within the `update()` method. Thanks anyways. – kdbanman Feb 22 '15 at 19:15