Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions vavr/src/main/java/io/vavr/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,14 @@ default T getOrNull() {
return isEmpty() ? null : get();
}

default <U> Value<U> as(U val) {
return map((ignored) -> val);
}

default Value<Void> voided() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably a bit too specific - with the other method, people can just write as(null) or with(null) and that's probably clearer than guessing what "voided" actually means

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two advantages to using an explicit method: it clarifies the intent (which is good for code-reviews), and it avoids depending on type inference of the whole expression for the Void type.

For example, in our company we use a dedicated, Function<Object, Void> replaceWithVoid(), for this case as opposed to the <T> Function<Object, T> replaceWith(Supplier<? extends T> value) that we also have.

So, maybe with better naming there is a place for such a method?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point actually - you'd need to cast to Void to get the same semantics

Do you have an idea for a better name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a comment about the name, guys - I tried to follow the naming I'm the most familiar with, which is the one from cats' FunctorOps helper. there is an as(X) and void() there. in Java we can't do void, cause it's a keyword, but I'm happy to change it to whatever you suggest :)

Copy link
Contributor

@achinaou achinaou Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m also most familiar with the Typelevel/ZIO terminology of as and void/unit!

However, since Vavr’s main inspiration is Scala’s standard library with the terminology adapted to Java, I think the same strategy could apply here as well.

For developers coming from the Typelevel/ZIO ecosystems, .as and .voided would feel most familiar. But from the Scala stdlib perspective, and Vavr’s existing API, the .as* prefix conventionally signals a wrapper type conversion (e.g., List#asJava()), so reusing it for content replacement could break established intuition.

So, I think the methods .with(T) and .withVoid() are good choices as they build on the idea of "wither" methods (that may also come natively to Java), but without referring to a specific field, suggesting replacement of the Value’s content.

Copy link
Contributor

@achinaou achinaou Nov 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another not bad choice I think is the mapTo(T) / mapToVoid() option which is easily discoverable and cognitively closer to how someone would think about what would happen given an established intuition for map.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I like this option the most - as sounds like it's close to asJava() method family. Also, I think that alignment to Scala should have much lower priority than years ago.

@adamkopec what do you think about mapTo/mapToVoid ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's actually a very good idea, I updated the PR. @achinaou - you proposed something that is both easy to understand and not controversial. thx!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really glad I could help!

return map((ignored) -> null);
}

/**
* Checks if this {@code Value} is asynchronously (short: async) computed.
* <p>
Expand Down
5 changes: 5 additions & 0 deletions vavr/src/main/java/io/vavr/collection/TreeSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,11 @@ public <U> SortedSet<U> zipWithIndex(BiFunction<? super T, ? super Integer, ? ex
return TreeSet.ofAll(Comparators.naturalComparator(), iterator().zipWithIndex(mapper));
}

@Override
public TreeSet<Void> voided() {
return map((o1, o2) -> 0, ignored -> null);
}

// -- Object

@Override
Expand Down
19 changes: 19 additions & 0 deletions vavr/src/test/java/io/vavr/AbstractValueTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,25 @@ public void shouldReturnValueWhenGetOrNullOfNonEmpty() {
assertThat(of(1).getOrNull()).isEqualTo(1);
}

// -- as
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those are outdated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed 😅


@TestTemplate
public void shouldExecuteAsCorrectly() {
assertThat(empty().as(1)).isEqualTo(empty().as(2));
assertThat(of(2).as(1)).isEqualTo(of(3).as(1));
assertThat(of(2).as(1)).isEqualTo(of(3).map(ignored -> 1));
assertThat(of(3).as(2)).isEqualTo(of(1).map(ignored -> 2));
}

// -- voided
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and this

let's update it for now, but I will eventually get rid of these comments and replace with nested junit test classes wherever it makes sense

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated both :)


@TestTemplate
public void shouldExecuteVoidedCorrectly() {
assertThat(empty().voided()).isEqualTo(empty());
assertThat(of(1).voided()).isEqualTo(of(1).as(null));
assertThat(of(1).voided()).isEqualTo(of(1).map(ignored -> null));
}

// -- forEach

@TestTemplate
Expand Down
7 changes: 7 additions & 0 deletions vavr/src/test/java/io/vavr/collection/BitSetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,13 @@ public void shouldReturnTailOfNonEmptyHavingReversedOrder() {
// BitSet can't have reverse order
}

@Test
@Override
public void shouldExecuteVoidedCorrectly() {
assertThat(empty().voided()).isEqualTo(empty());
assertThat(of(1).voided()).isEqualTo(of((Integer)null));
}

// -- classes

private static final class Mapper<T> implements Serializable {
Expand Down
7 changes: 7 additions & 0 deletions vavr/src/test/java/io/vavr/collection/TreeSetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -411,4 +411,11 @@ public void shouldZipAllEmptyAndNonNil() {
@Disabled
public void shouldZipAllNonEmptyAndNil() {
}

@Test
@Override
public void shouldExecuteVoidedCorrectly() {
assertThat(empty().voided()).isEqualTo(empty());
assertThat(of(1).map(ignored -> null)).isEqualTo(of(1).voided());
}
}