Why are Optional's or and flatMap methods' supplier type parameters wildcards?
up vote
29
down vote
favorite
The Optional.or
method was added in Java 9. This is the method signature
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
Why is the type parameter of the Supplier
taking ? extends Optional
rather than just Optional
, since Optional
is a final class?
The same is true for the Optional.flatMap
method. This is a change from Java 8.
In Java 8, it was Function<? super T, Optional<U>> mapper
whereas it was changed to Function<? super T,? extends Optional<? extends U>>
in Java 9.
java optional java-9 supplier
add a comment |
up vote
29
down vote
favorite
The Optional.or
method was added in Java 9. This is the method signature
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
Why is the type parameter of the Supplier
taking ? extends Optional
rather than just Optional
, since Optional
is a final class?
The same is true for the Optional.flatMap
method. This is a change from Java 8.
In Java 8, it was Function<? super T, Optional<U>> mapper
whereas it was changed to Function<? super T,? extends Optional<? extends U>>
in Java 9.
java optional java-9 supplier
Kinda seems like they're positioning it to not be afinal
class in future version?
– nbrooks
Dec 10 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 at 1:45
3
My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
– Daniel Pryden
Dec 10 at 17:52
add a comment |
up vote
29
down vote
favorite
up vote
29
down vote
favorite
The Optional.or
method was added in Java 9. This is the method signature
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
Why is the type parameter of the Supplier
taking ? extends Optional
rather than just Optional
, since Optional
is a final class?
The same is true for the Optional.flatMap
method. This is a change from Java 8.
In Java 8, it was Function<? super T, Optional<U>> mapper
whereas it was changed to Function<? super T,? extends Optional<? extends U>>
in Java 9.
java optional java-9 supplier
The Optional.or
method was added in Java 9. This is the method signature
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
Why is the type parameter of the Supplier
taking ? extends Optional
rather than just Optional
, since Optional
is a final class?
The same is true for the Optional.flatMap
method. This is a change from Java 8.
In Java 8, it was Function<? super T, Optional<U>> mapper
whereas it was changed to Function<? super T,? extends Optional<? extends U>>
in Java 9.
java optional java-9 supplier
java optional java-9 supplier
edited Dec 10 at 13:47
Boann
36.6k1287121
36.6k1287121
asked Dec 10 at 1:25
user7
9,15932242
9,15932242
Kinda seems like they're positioning it to not be afinal
class in future version?
– nbrooks
Dec 10 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 at 1:45
3
My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
– Daniel Pryden
Dec 10 at 17:52
add a comment |
Kinda seems like they're positioning it to not be afinal
class in future version?
– nbrooks
Dec 10 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 at 1:45
3
My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
– Daniel Pryden
Dec 10 at 17:52
Kinda seems like they're positioning it to not be a
final
class in future version?– nbrooks
Dec 10 at 1:42
Kinda seems like they're positioning it to not be a
final
class in future version?– nbrooks
Dec 10 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 at 1:45
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 at 1:45
3
3
My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
– Daniel Pryden
Dec 10 at 17:52
My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
– Daniel Pryden
Dec 10 at 17:52
add a comment |
3 Answers
3
active
oldest
votes
up vote
35
down vote
I found the reasoning behind this from Stuart Marks himself
http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html
This has to do with nested generics (Optional
is nested within Function
).
From the mail thread
Function<..., Optional<StringBuilder>>
is not a subtype of
Function<..., Optional<? extends CharSequence>>
To get around this, we have to add the outer wildcard as well, so that
Function<..., Optional<StringBuilder>>
is a subtype of
Function<..., ? extends Optional<? extends CharSequence>>
8
+1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach"<V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper)
would not work in all circumstances.
– Stefan Zobel
Dec 10 at 8:48
add a comment |
up vote
10
down vote
FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
These signatures do not allow for some combinations of seeds and UnaryOperator
s that are sound from a type perspective, e.g. the following doesn't compile:
UnaryOperator<String> op = s -> s;
Stream<CharSequence> scs = iterate("", op); // error
The proposed solution is to change the method signatures to
static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)
So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.
add a comment |
up vote
9
down vote
Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple>
is an actual subtype of List<? extends Fruit>
(considering that Apple
extends Fruit
); this is also called covariance.
Or in the examples that you have shown, it means that Optional<StringBuilder>
is a subtype of Optional<? extends Optional<? extends CharSequence>>
, so you could for example do:
List<Optional<String>> left = new ArrayList<>();
List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();
right = left; // will compile
or assign a Function
to the other
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53698401%2fwhy-are-optionals-or-and-flatmap-methods-supplier-type-parameters-wildcards%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
35
down vote
I found the reasoning behind this from Stuart Marks himself
http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html
This has to do with nested generics (Optional
is nested within Function
).
From the mail thread
Function<..., Optional<StringBuilder>>
is not a subtype of
Function<..., Optional<? extends CharSequence>>
To get around this, we have to add the outer wildcard as well, so that
Function<..., Optional<StringBuilder>>
is a subtype of
Function<..., ? extends Optional<? extends CharSequence>>
8
+1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach"<V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper)
would not work in all circumstances.
– Stefan Zobel
Dec 10 at 8:48
add a comment |
up vote
35
down vote
I found the reasoning behind this from Stuart Marks himself
http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html
This has to do with nested generics (Optional
is nested within Function
).
From the mail thread
Function<..., Optional<StringBuilder>>
is not a subtype of
Function<..., Optional<? extends CharSequence>>
To get around this, we have to add the outer wildcard as well, so that
Function<..., Optional<StringBuilder>>
is a subtype of
Function<..., ? extends Optional<? extends CharSequence>>
8
+1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach"<V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper)
would not work in all circumstances.
– Stefan Zobel
Dec 10 at 8:48
add a comment |
up vote
35
down vote
up vote
35
down vote
I found the reasoning behind this from Stuart Marks himself
http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html
This has to do with nested generics (Optional
is nested within Function
).
From the mail thread
Function<..., Optional<StringBuilder>>
is not a subtype of
Function<..., Optional<? extends CharSequence>>
To get around this, we have to add the outer wildcard as well, so that
Function<..., Optional<StringBuilder>>
is a subtype of
Function<..., ? extends Optional<? extends CharSequence>>
I found the reasoning behind this from Stuart Marks himself
http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html
This has to do with nested generics (Optional
is nested within Function
).
From the mail thread
Function<..., Optional<StringBuilder>>
is not a subtype of
Function<..., Optional<? extends CharSequence>>
To get around this, we have to add the outer wildcard as well, so that
Function<..., Optional<StringBuilder>>
is a subtype of
Function<..., ? extends Optional<? extends CharSequence>>
edited Dec 10 at 8:07
JAD
1,0441923
1,0441923
answered Dec 10 at 1:45
user7
9,15932242
9,15932242
8
+1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach"<V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper)
would not work in all circumstances.
– Stefan Zobel
Dec 10 at 8:48
add a comment |
8
+1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach"<V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper)
would not work in all circumstances.
– Stefan Zobel
Dec 10 at 8:48
8
8
+1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach"
<V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper)
would not work in all circumstances.– Stefan Zobel
Dec 10 at 8:48
+1. For me, the really mind-boggling thing here was why the easier "additional-type-parameter approach"
<V, U extends V> Optional<V> flatMap(Function<? super T, Optional<U>> mapper)
would not work in all circumstances.– Stefan Zobel
Dec 10 at 8:48
add a comment |
up vote
10
down vote
FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
These signatures do not allow for some combinations of seeds and UnaryOperator
s that are sound from a type perspective, e.g. the following doesn't compile:
UnaryOperator<String> op = s -> s;
Stream<CharSequence> scs = iterate("", op); // error
The proposed solution is to change the method signatures to
static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)
So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.
add a comment |
up vote
10
down vote
FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
These signatures do not allow for some combinations of seeds and UnaryOperator
s that are sound from a type perspective, e.g. the following doesn't compile:
UnaryOperator<String> op = s -> s;
Stream<CharSequence> scs = iterate("", op); // error
The proposed solution is to change the method signatures to
static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)
So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.
add a comment |
up vote
10
down vote
up vote
10
down vote
FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
These signatures do not allow for some combinations of seeds and UnaryOperator
s that are sound from a type perspective, e.g. the following doesn't compile:
UnaryOperator<String> op = s -> s;
Stream<CharSequence> scs = iterate("", op); // error
The proposed solution is to change the method signatures to
static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)
So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.
FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
These signatures do not allow for some combinations of seeds and UnaryOperator
s that are sound from a type perspective, e.g. the following doesn't compile:
UnaryOperator<String> op = s -> s;
Stream<CharSequence> scs = iterate("", op); // error
The proposed solution is to change the method signatures to
static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)
So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.
answered Dec 10 at 12:10
Stefan Zobel
2,44031828
2,44031828
add a comment |
add a comment |
up vote
9
down vote
Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple>
is an actual subtype of List<? extends Fruit>
(considering that Apple
extends Fruit
); this is also called covariance.
Or in the examples that you have shown, it means that Optional<StringBuilder>
is a subtype of Optional<? extends Optional<? extends CharSequence>>
, so you could for example do:
List<Optional<String>> left = new ArrayList<>();
List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();
right = left; // will compile
or assign a Function
to the other
add a comment |
up vote
9
down vote
Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple>
is an actual subtype of List<? extends Fruit>
(considering that Apple
extends Fruit
); this is also called covariance.
Or in the examples that you have shown, it means that Optional<StringBuilder>
is a subtype of Optional<? extends Optional<? extends CharSequence>>
, so you could for example do:
List<Optional<String>> left = new ArrayList<>();
List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();
right = left; // will compile
or assign a Function
to the other
add a comment |
up vote
9
down vote
up vote
9
down vote
Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple>
is an actual subtype of List<? extends Fruit>
(considering that Apple
extends Fruit
); this is also called covariance.
Or in the examples that you have shown, it means that Optional<StringBuilder>
is a subtype of Optional<? extends Optional<? extends CharSequence>>
, so you could for example do:
List<Optional<String>> left = new ArrayList<>();
List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();
right = left; // will compile
or assign a Function
to the other
Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple>
is an actual subtype of List<? extends Fruit>
(considering that Apple
extends Fruit
); this is also called covariance.
Or in the examples that you have shown, it means that Optional<StringBuilder>
is a subtype of Optional<? extends Optional<? extends CharSequence>>
, so you could for example do:
List<Optional<String>> left = new ArrayList<>();
List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();
right = left; // will compile
or assign a Function
to the other
edited Dec 10 at 12:48
answered Dec 10 at 12:31
Eugene
67.6k997160
67.6k997160
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53698401%2fwhy-are-optionals-or-and-flatmap-methods-supplier-type-parameters-wildcards%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Kinda seems like they're positioning it to not be a
final
class in future version?– nbrooks
Dec 10 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 at 1:45
3
My understanding of how this works is that, if a type argument is not for a wildcard type, the match must always be invariant. If you want to allow a subtype anywhere within the generic parameters of a type, then you need to use a wildcard type (or a new type variable) out to the outermost generic declaration. I think this is implied by section 18.2.3, "Subtyping Constraints", of the "Type Inference" chapter of the Java Language Specification. But that chapter is hard for me to wrap my brain around and I'm not confident enough in my understanding to write an answer spelling it out exactly.
– Daniel Pryden
Dec 10 at 17:52