Why are Optional's or and flatMap methods' supplier type parameters wildcards?
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 |
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 '18 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 '18 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 '18 at 17:52
add a comment |
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 '18 at 13:47
Boann
36.8k1289121
36.8k1289121
asked Dec 10 '18 at 1:25
user7user7
9,39932343
9,39932343
Kinda seems like they're positioning it to not be afinal
class in future version?
– nbrooks
Dec 10 '18 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 '18 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 '18 at 17:52
add a comment |
Kinda seems like they're positioning it to not be afinal
class in future version?
– nbrooks
Dec 10 '18 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 '18 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 '18 at 17:52
Kinda seems like they're positioning it to not be a
final
class in future version?– nbrooks
Dec 10 '18 at 1:42
Kinda seems like they're positioning it to not be a
final
class in future version?– nbrooks
Dec 10 '18 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 '18 at 1:45
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 '18 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 '18 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 '18 at 17:52
add a comment |
3 Answers
3
active
oldest
votes
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 '18 at 8:48
add a comment |
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 |
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',
autoActivateHeartbeat: false,
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
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 '18 at 8:48
add a comment |
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 '18 at 8:48
add a comment |
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 '18 at 8:07
JAD
1,0471923
1,0471923
answered Dec 10 '18 at 1:45
user7user7
9,39932343
9,39932343
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 '18 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 '18 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 '18 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 '18 at 8:48
add a comment |
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 |
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 |
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 '18 at 12:10
Stefan ZobelStefan Zobel
2,44031828
2,44031828
add a comment |
add a comment |
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 |
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 |
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 '18 at 12:48
answered Dec 10 '18 at 12:31
EugeneEugene
69.7k999165
69.7k999165
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.
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 '18 at 1:42
@nbrooks It is because of the nested generics (and yes.. partly to due with the future changes)
– user7
Dec 10 '18 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 '18 at 17:52