Can't make simple Streams over indirect projects work

Ben Evans benjamin.john.evans at gmail.com
Wed Aug 14 14:13:24 UTC 2019


Thanks Srikanth.

I can confirm that this does indeed fix my examples.

However, when I try to generalise this to deal with optional values of
reference type, then while this compiles:

public inline class Optional<T> {
private T value;

@SuppressWarnings("unchecked")
public static<T> Optional<T> empty() {
return (Optional<T>) Optional.default;
}

private Optional(T value) {
this.value = value;
}

public static <T> Optional<T> of(T value) {
if (value == null)
return empty();
return new Optional<T>(value);
}

public T get() {
if (value == null)
throw new NoSuchElementException("No value present");
return value;
}

public boolean isPresent() {
return value != null;
}

public T orElse(T other) {
return value != null ? value : other;
}

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else
return Optional.of(mapper.apply(value));
}

@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}

all my attempts to use it, eg. via code like this:

List<Optional?<Integer>> opts = new ArrayList<>();
for (int i=0; i < 5; i++) {
Optional<Integer> oi = Optional.of(i);
opts.add((Optional?<Integer>)oi);
Optional<Integer> oe = Optional.empty();
opts.add((Optional?<Integer>)oe);
}
Integer total = opts.stream()
.map((Optional?<Integer> o) -> {
Optional<Integer> op = (Optional<Integer>)o;
return op.orElse(0);
})
.reduce(0, (x, y) -> x + y);

System.out.println("Total: "+ total);

fail to compile.

Have I misunderstood something here? Is Optional?<Integer> a valid
type, and should it be possible to project the inline type
Optional<Integer> to it?

Thanks,

Ben


On Wed, 14 Aug 2019 at 10:46, Srikanth <srikanth.adayapalam at oracle.com> wrote:
>
> Hello Ben,
>
> With this push:
> http://hg.openjdk.java.net/valhalla/valhalla/rev/7ec951ef532d for
> https://bugs.openjdk.java.net/browse/JDK-8229537, I believe the code
> snippet below
> compiles fine (once suitable imports are typed in)
>
> However, this program fails at runtime with "Exception in thread "main"
> java.lang.ClassCircularityError: OptionalInt" - this circularity error
> is a bogus error that is being addressed as we speak by the good folks
> at the VM team.
>
> See
> https://mail.openjdk.java.net/pipermail/valhalla-dev/2019-August/006229.html
> which initiates a review of a fix for
> https://bugs.openjdk.java.net/browse/JDK-8229372.
>
> In the meantime, you can easily workaround the circularity problem by
> manually constant propagating OptionalInt.default into the only place
> OptionalInt.EMPTY is used.
>
> You may want to peruse the tests I have added here,
> http://hg.openjdk.java.net/valhalla/valhalla/rev/7ec951ef532d
>
> Thanks!
> Srikanth
>
> On 28/07/19 6:44 PM, Ben Evans wrote:
> > Hi,
> >
> > I'm probably missing something really obvious, but I've been playing
> > with this code for several days and can't find my bug.
> >
> > Given an inline class defined like this:
> >
> > public inline class OptionalInt {
> >      private static final OptionalInt EMPTY = OptionalInt.default;
> >
> >      private boolean isPresent = false;
> >      private int v = 0;
> >
> >      public static OptionalInt empty() {
> >          return EMPTY;
> >      }
> >
> >      public static OptionalInt of(int val) {
> >          OptionalInt self = OptionalInt.default;
> >          self = __WithField(self.v, val);
> >          self = __WithField(self.isPresent, true);
> >          return self;
> >      }
> >
> >      public int getAsInt() {
> >          if (!isPresent)
> >              throw new NoSuchElementException("No value present");
> >
> >          return v;
> >      }
> >
> >      public boolean isPresent() {
> >          return isPresent;
> >      }
> >
> >      public void ifPresent(IntConsumer consumer) {
> >          if (isPresent)
> >              consumer.accept(v);
> >      }
> >
> >      public int orElse(int other) {
> >          return isPresent ? v : other;
> >      }
> > }
> >
> > and some code that attempts to use it like this:
> >
> > public final class Main4 {
> >      public static void main(String[] args) {
> >          List<OptionalInt?> opts = new ArrayList<>();
> >          for (int i=0; i < 5; i++) {
> >              opts.add(OptionalInt.of(i));
> >              opts.add(OptionalInt.empty());
> >              opts.add(null);
> >          }
> >
> >          Integer total = opts.stream()
> >              .map((OptionalInt? o) -> {
> >                  if (o == null)
> >                      return 0;
> >
> >                  OptionalInt op = (OptionalInt)o;
> >                  return op.orElse(0);
> >              })
> >              .reduce(0, (x, y) -> x + y);
> >
> >          System.out.println("Total: "+ total);
> >      }
> > }
> >
> > Then javac barfs like this:
> >
> > bevans$ javac -XDallowWithFieldOperator -XDallowGenericsOverValues
> > javamag/Main4.java
> >
> > javamag/Main4.java:15: error: ')' expected
> >              .map((OptionalInt? o) -> {
> >                               ^
> > javamag/Main4.java:15: error: : expected
> >              .map((OptionalInt? o) -> {
> >                                  ^
> > javamag/Main4.java:15: error: ';' expected
> >              .map((OptionalInt? o) -> {
> >                                   ^
> > javamag/Main4.java:20: error: illegal start of expression\
> >              })
> >               ^
> > 4 errors
> >
> > Could some kind person put me out of my misery and tell me what I'm
> > doing wrong here, and what the proper way to express this should be?
> >
> > Thanks,
> >
> > Ben
>


More information about the valhalla-dev mailing list