6

So I want to create a Mono<Void> (or any Mono<SomeIgnorableType>) that actually emits an element. Why? Because I actually want to run an effect, and the result just implies the effect was run, YET, it can be ignored.

In Haskell Void is an uninhabitable type... like the Nothing in Scala. In Java Void is also uninhabitable, yet it is used more like the Unit type in Scala or the () (0 arity tuple) in Haskell. A type with only one inhabitant.

Ok, too much with the theory. My options so far:

  1. Mono.just((Void) null) throws an Exception.

  2. Mono.empty().single() (because I actually want to emit an event), ends up with failure, when one subscribes to it. And...

  3. Mono.just("something").then() runs the effect, but then I cannot chain it with other monos, because it only emits complete and error events.

So how???

caeus
  • 3,084
  • 1
  • 22
  • 36
  • I found this https://stackoverflow.com/questions/48556082/how-to-create-single-justvoid, which actually implies that this is not a reactor problem, more than a Java design problem. :facepalm: Java! – caeus Mar 25 '21 at 21:22
  • I'm actually starting to consider using `Mono` (`Tuple0` from Vavr). – caeus Mar 25 '21 at 21:30
  • 1
    A void Mono is naturally empty. You can construct it with Mono.empty(). Why do you need it to have a value? Sometimes it´s useful to emit a value (e.g. to zip with another mono). In this case I wrap the value in an Optional. I suppose you could use Mono> in your case. – Neil Swingler Mar 27 '21 at 15:18
  • Exactly, I need it to emit a value to use FlatMap or Zip, or map or... Well, every method that needs a value on Mono. I migrated to rxjava Single eventually – caeus Mar 27 '21 at 18:37
  • 1
    For instance if you want to zip a void mono completion a with another mono b then you can rather use a.then(b). If you are using rxjava then you can use Completable – Neil Swingler Mar 28 '21 at 07:42

1 Answers1

3

Java's lack of null-safety means the unit type concept doesn't translate particularly well. I've never been convinced when people have postulated Void as equivalent to a unit type. You can never instantiate it by design; you can assume that any reference containing the Void type is null, which I don't really see as a value - it's more the absence of any value (ie. an uninhabitable type.)

There's nothing that I would consider a "real" unit type built into Java, but you can create one trivially via the use of an enum with a single value:

public enum Unit {UNIT}

If your Mono type is then set to Unit, this does what you need - you can either complete the Mono with no value, you can complete it with a single Unit value (and ignore the value, just reacting to the fact it's there), or complete it with an error. It sounds like that's exactly what you're after.

That said, answering the question directly and ignoring whether you should (you shouldn't IMHO), you can mock Void to actually assign it a non-null value. Mockito can do it no problem, you just need to make sure Mockito is configured so it can mock final classes:

Void v = Mockito.mock(Void.class);
Mono.just(v)
        .doOnNext(actualVoid -> System.out.println(actualVoid))
        .block();

Prints: Mock for Void, hashCode: 1830745997

(It's not something I've ever done, nor felt the need to do, but that doesn't prevent you from technically doing it.)

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
  • I ended up using the Tuple0 from vavr. I posted in the comments of the question my thoughts as I continued looking for solutions. What you suggested was one of my options too – caeus Mar 26 '21 at 00:19