javaoption-typesupplier

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?


Solution

  • 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.