Disdainty
Disdainty

Reputation: 95

Implementation a variation of `Optional.or()` method

I am currently learning about the functionalities of the Optional class, and I am trying to build a simplified version of the Optional class. I was able to code ifPresent(), filter(), of(), map() and so on. However, I am currently stuck with the implementing or().

I know that or() have the signature Optional<T> or(Supplier<? extends Optional<? extends T>> supplier). However, my implementation assumed that I can access the contents of the Optional. As show below:

class Optional<T> {
    private final T item;
    ...

    Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
        if (this.item == null) {
            T item = supplier.get().item;
            return Maybe.<T>of(item);
        } else {
            return this;
        }
    }
}

As you can see, T item = supplier.get().item would throw an error saying that .item is inaccessible due to it being private. How am I able to access the item without causing this error?

Upvotes: 1

Views: 151

Answers (2)

Holger
Holger

Reputation: 298469

First, you need to recall that you can not access a private field through an instance of a subtype, even though assigning the subtype reference to a variable of the current type, which allows the access, is possible without cast.

So if you have

public class ClassWithPrivateField {
    private String field;
  
    static class Subclass extends ClassWithPrivateField {}
  
    void someMethod(Subclass obj) {
        String s = obj.field; // does not work, you can't access field through Subclass
    }
}

you may write

public class ClassWithPrivateField {
    private String field;
  
    static class Subclass extends ClassWithPrivateField {}
  
    void someMethod(Subclass obj) {
        ClassWithPrivateField withBroaderType = obj; // always works
        String s = withBroaderType.field; // now, no problem to access field
    }
}

Now to your more complicated generic variant. If you have

public class Optional<T> {
    private final T item;
  
    private Optional(T t) {
      item = t;
    }
  
    Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
        if(this.item == null) {
            T item = supplier.get().item;
            return Optional.of(item);
        }
        else return this;
    }
  
    private static <T> Optional<T> of(T item2) {
      return new Optional<>(item2);
    }
}

the access to item is rejected by the compiler because the type returned by the supplier is ? extends Optional<? extends T> which is a subtype of Optional<? extends T>, just the same way as Subclass is a subtype of ClassWithPrivateField.

You can fix the issue the same way, by introducing a variable:

public class Optional<T> {
    private final T item;
  
    private Optional(T t) {
      item = t;
    }
  
    Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
        if(this.item == null) {
            Optional<? extends T> optional = supplier.get(); // valid assignment
            T item = optional.item; // valid access
            return Optional.of(item);
        }
        else return this;
    }
  
    private static <T> Optional<T> of(T item2) {
      return new Optional<>(item2);
    }
}

Alternatively, you could insert a type cast to Optional<? extends T> like

T item = ((Optional<? extends T>)supplier.get()).item;

but I would prefer the variant with a variable as it immediately shows to the reader that the assignment (without a cast) is a valid type transition which can never fail. The type cast can not fail either and is a no-op at runtime, but its syntax is indistinguishable from type casts performing a runtime check that could fail.

Upvotes: 3

talex
talex

Reputation: 20544

You just need to replace

    T item = supplier.get().item;
    return Maybe.<T>of(item);

with

    return (Optional<T>)supplier.get();

Upvotes: 0

Related Questions