3

I have two kinds of data streams that both implement the same interface:

public interface DataReceiver {
    public Data getData();
}

public class DeviceDataReceiver implements DataReceiver {
    // Receives data from an external device
    public Data getData();
}

public class PlaybackDataReceiver implements DataReceiver {
    // Receives data from textfile
    public Data getData();
}

The DeviceDataReceiver can return null, indicating that there is no new data available, or the device wasn't able to pick up any new data. The PlaybackDataReceiver returns null if all the data from the file has been returned. Both of them are supposed to be polled in a while-loop.

The problem i am having is how to indicate, that there is no new data available, so that working with the interface using dependency injection makes more sense. I was thinking about adding this method to my interface:

public boolean hasNext();

Where the DeviceDataReceiver always returns true (since there can always be new data) and the PlaybackDataReceiver returning true, unless it has reached EOF.

The classes would be polled through the interface like this:

DataReceiver rec = getDataReceiverImplementation();
while(rec.hasNext()) {
    Data data = rec.getData();
    if(data != null) { /* perform some action */ }
}

Like this both classes could be injected and the loop would exit automatically for the PlaybackDataReceiver. To exit the loop for the DeviceDataReceiver the user would have to send some kind of signal, like pushing a button to stop receiving data.

Is this understandable? It's supposed to become part of a library i am writing.

4

In-band error signalling where certain values have a special meaning is always problematic. It is easy to forget to check those special cases.

You have found one solution to this problem: move the special meaning out of the return value. In this case, this is a separate function. This is a valid solution, but it introduces dependencies between your method – the getData() should only be called if hasNext() returned true. That does complicate the API. But in this case, this is very similar to the well-known java.lang.Iterator API and is as such an acceptable idiom. In fact, you could have DataReceiver extend the Iterator interface, then you can use all DataReceivers in a for-loop like:

for (Data data : receiver) {
  if (data != null) { /* perform some action */ }
}

An alternative solution is to wrap the returned value in a different type that indicates the kind of result: did we get a value, or a special marker. For example:

final class DataOrEOF {
  private final boolean isEOF;
  private final Data data;

  private DataOrEOF(boolean isEOF, Data data) {
    this.isEOF = isEOF;
    this.data = data;
  }

  public static DataOrEOF of(Data d) { return new DataOrEOF(false, d); }
  public static DataOrEOF ofEOF() { return new DataOrEOF(true, null); }

  public boolean isEOF() { return isEOF; }

  public Data getDataOrThrow() {
    if (isEOF) throw InvalidStateException(...);
    return data;
  }
}

This forces the consumer of the result to check the special case or risk an exception. This is somewhat similar to Java8's java.util.Optional, except that our DataOrEOF allows null data.

  • I will go with the first one. I actually like the second one better (F# has a similar feature called discriminated unions which i love), but i think that the first one will fit the rest of the library better. Thank you! – Luca Fülbier Nov 13 '16 at 17:08
  • JavaScript ES6 basically does exactly this, except, being JavaScript, asking for the data after an EOF is allowed (and undefined what will happen). – user949300 Nov 14 '16 at 22:01
  • 1
    I would like to add that the first example will not work, since the class would have to implement Iterable and not Iterator to support Javas foreach loop. The answer is still correct, since my Receiver is an Iterator and the underlying data source is Iterable. – Luca Fülbier Nov 15 '16 at 23:03
2

You could define a special unique instance of Data to indicate done, e.g.

public class Data {
   public static final Data.EOF = new Data();`// Singleton to mark EOF

   // rest of Data stuff here...
}

Return it from the methods. The client checks with ==, not equals()!

while (true) {  // for illustration, we're probably in a loop
                // real code probably needs to test isInterrupted()
    Data data = rec.getData();
    if (data == Data.EOF)
        break;

    // it's "real", process it...
}

// clean up interrupt, close stuff, finally clause, etc. here...
  • +1 I often use this technique in dynamic languages to generate unique symbols. It is somewhat error prone since the special value is not in itself distinguishable from ordinary values, but that's sometimes the best possible trade-off. If we were to use a special subclass of Data for the marker object, that would be a kind of Null Object Pattern + Singleton combination. – amon Nov 13 '16 at 18:55
  • @amon in Java at least it can be a Singleton - see clarified answer. – user949300 Nov 13 '16 at 23:00
  • This is very interesting, i have never done anything like that. Does this pattern have a name? – Luca Fülbier Nov 13 '16 at 23:08
3

Our job as programmers is to provide useful, complete, easy to use abstractions.

If an abstraction isn't useful and complete, then the consuming client (programmer) has to add a bunch of stuff together, likely inferring too much information about the underlying implementations of things s/he is bundling together, resulting in tighter coupling than we'd like between a client and an implementation.

The abstractions we publish (even if only to ourselves) should be so easy to use that the programmer falls into the pit of success.

As @amon points out, the hasNext/getData paradigm is well understood. You should not only use it, you should even implement iterator so that your abstraction is an iterator.

By comparison, special values and nulls are impoverished from a self-documenting point of view.

  • +1 for "you should even implement iterator so that your abstraction is an iterator". – user949300 Nov 14 '16 at 22:02
0

The simples way to solve this is to escape an end-of-stream indicator. Choose an arbitrary but not often used char. When this is transmitted, let it follow a second char that tells whether it's the char or the end-of-stream char.

  • This wasn't quite what i was looking for (see amon's answer), but thank you anyways. – Luca Fülbier Nov 13 '16 at 17:09
  • Actually his DataOrEof is exactly what I describe. But of course he's more detailed (my Java is quite poor). – qwerty_so Nov 13 '16 at 17:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.