Why is Set<? extends Foo> allowed, but Set<Foo> is not
I want to know how generics work in this kind of situation and why
Set<? extends Foo<?>> set3 = set1;
is allowed but Set<Foo<?>> set2 = set1;
is not?
import java.util.HashSet;
import java.util.Set;
public class TestGenerics {
public static <T> void test() {
Set<T> set1 = new HashSet<>();
Set<?> set2 = set1; // OK
}
public static <T> void test2() {
Set<Foo<T>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // COMPILATION ERROR
Set<? extends Foo<?>> set3 = set1; // OK
}
}
class Foo<T> {}
java generics
New contributor
add a comment |
I want to know how generics work in this kind of situation and why
Set<? extends Foo<?>> set3 = set1;
is allowed but Set<Foo<?>> set2 = set1;
is not?
import java.util.HashSet;
import java.util.Set;
public class TestGenerics {
public static <T> void test() {
Set<T> set1 = new HashSet<>();
Set<?> set2 = set1; // OK
}
public static <T> void test2() {
Set<Foo<T>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // COMPILATION ERROR
Set<? extends Foo<?>> set3 = set1; // OK
}
}
class Foo<T> {}
java generics
New contributor
An interesting reading about this "issue": stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
3
Possible duplicate of What is PECS (Producer Extends Consumer Super)?
– Lino
1 hour ago
1
@Lino: This question is similar to and related to "What is PECS", but not exactly the same. This question is about PECS, but specifically applied to the case when the type arguments themselves are types which have type parameters. That makes this a particularly tricky special case, which warrants its own question. (But I'd be surprised if there is no other exactly duplicate question some where.)
– Lii
36 mins ago
add a comment |
I want to know how generics work in this kind of situation and why
Set<? extends Foo<?>> set3 = set1;
is allowed but Set<Foo<?>> set2 = set1;
is not?
import java.util.HashSet;
import java.util.Set;
public class TestGenerics {
public static <T> void test() {
Set<T> set1 = new HashSet<>();
Set<?> set2 = set1; // OK
}
public static <T> void test2() {
Set<Foo<T>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // COMPILATION ERROR
Set<? extends Foo<?>> set3 = set1; // OK
}
}
class Foo<T> {}
java generics
New contributor
I want to know how generics work in this kind of situation and why
Set<? extends Foo<?>> set3 = set1;
is allowed but Set<Foo<?>> set2 = set1;
is not?
import java.util.HashSet;
import java.util.Set;
public class TestGenerics {
public static <T> void test() {
Set<T> set1 = new HashSet<>();
Set<?> set2 = set1; // OK
}
public static <T> void test2() {
Set<Foo<T>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // COMPILATION ERROR
Set<? extends Foo<?>> set3 = set1; // OK
}
}
class Foo<T> {}
java generics
java generics
New contributor
New contributor
edited 32 mins ago
Lii
6,87044159
6,87044159
New contributor
asked 3 hours ago
Stoyan RadnevStoyan Radnev
864
864
New contributor
New contributor
An interesting reading about this "issue": stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
3
Possible duplicate of What is PECS (Producer Extends Consumer Super)?
– Lino
1 hour ago
1
@Lino: This question is similar to and related to "What is PECS", but not exactly the same. This question is about PECS, but specifically applied to the case when the type arguments themselves are types which have type parameters. That makes this a particularly tricky special case, which warrants its own question. (But I'd be surprised if there is no other exactly duplicate question some where.)
– Lii
36 mins ago
add a comment |
An interesting reading about this "issue": stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
3
Possible duplicate of What is PECS (Producer Extends Consumer Super)?
– Lino
1 hour ago
1
@Lino: This question is similar to and related to "What is PECS", but not exactly the same. This question is about PECS, but specifically applied to the case when the type arguments themselves are types which have type parameters. That makes this a particularly tricky special case, which warrants its own question. (But I'd be surprised if there is no other exactly duplicate question some where.)
– Lii
36 mins ago
An interesting reading about this "issue": stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
An interesting reading about this "issue": stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
3
3
Possible duplicate of What is PECS (Producer Extends Consumer Super)?
– Lino
1 hour ago
Possible duplicate of What is PECS (Producer Extends Consumer Super)?
– Lino
1 hour ago
1
1
@Lino: This question is similar to and related to "What is PECS", but not exactly the same. This question is about PECS, but specifically applied to the case when the type arguments themselves are types which have type parameters. That makes this a particularly tricky special case, which warrants its own question. (But I'd be surprised if there is no other exactly duplicate question some where.)
– Lii
36 mins ago
@Lino: This question is similar to and related to "What is PECS", but not exactly the same. This question is about PECS, but specifically applied to the case when the type arguments themselves are types which have type parameters. That makes this a particularly tricky special case, which warrants its own question. (But I'd be surprised if there is no other exactly duplicate question some where.)
– Lii
36 mins ago
add a comment |
5 Answers
5
active
oldest
votes
Perhaps the issue becomes clearer if you leave the generic parameter of Foo out of the equation.
Consider
final Set<Foo> set1 = new HashSet<>();
Set<Object> set2 = set1;
This makes the compile error more obvious. If this was valid, it would be possible to insert an object into set2, thus into set1 violating the type constraint.
Set<? extends Foo> set3 = set1;
This is perfectly valid because set1 would also accept types derived from Foo.
why did you transformSet<Foo<?>>
toSet<Object>
after type erasure? I guess wildcard will be replaced byObject
since it is closest bound?
– Sergey Prokofiev
2 hours ago
Foo<?>
is notObject
, it isFoo
"of something". What allows the assignment toset3
is the covariance.
– kagmole
2 hours ago
Also you answer implies thatset3
is writable, which is not the case. See more about covariance and contravariance here : stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
add a comment |
Simply said, this is because Set<? extends Foo<?>>
is covariant (with the extends
keyword). Covariant types are read-only and the compiler will refuse any write action, like Set.add(..)
.
Set<Foo<?>>
is not covariant. It does not block write or read actions.
This...
Set<Foo<String>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // KO by compiler
... is illegal because I could for example write an Integer in set1
with set2
.
set2.add(new Foo<Integer>()); // Whoopsie
But...
Set<Foo<String>> set1 = new HashSet<>();
Set<? extends Foo<?>> set3 = set1; // OK
... is covariant (extends
keyword), so it is legal. The compiler will refuse a set3.add(42)
. You can only read from set3
, not write.
set3.add(new Foo<Integer>()); // KO by compiler
See these posts for a better explanation:
- https://stackoverflow.com/a/4343547/7709086
- https://medium.freecodecamp.org/understanding-java-generic-types-covariance-and-contravariance-88f4c19763d2
3
Did you meanFoo<Integer> foo; set2.add(foo);
becauseset2.add(42)
42 isn't aFoo<?>
.
– matt
1 hour ago
Oops thank you @matt, I fixed my answer.
– kagmole
1 hour ago
add a comment |
Additionally to the answers given already I'll add some formal explanation.
Given by 4.10.2 (emp. mine)
Given a generic type declaration C (n > 0), the direct
supertypes of the parameterized type C, where Ti (1 ≤ i ≤
n) is a type, are all of the following:
D < U1 θ,...,Uk θ>, where D is a generic type which is a
direct supertype of the generic type C and θ is the
substitution [F1:=T1,...,Fn:=Tn].
C < S1,...,Sn> , where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
The type Object, if C is a generic interface type with no
direct superinterfaces.
The raw type C.
Rule for contains
are specified at 4.5.1:
A type argument T1 is said to contain another type argument T2,
written T2 <= T1, if the set of types denoted by T2 is provably a
subset of the set of types denoted by T1 under the reflexive and
transitive closure of the following rules (where <: denotes subtyping
(§4.10)):
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
Since T <= ? super T <= ? extends Object = ?
so applying 4.10.2 Foo<T> <: Foo<?>
we have ? extends Foo<T> <= ? extends Foo<?>
. But Foo<T> <= ? extends Foo<T>
so we have Foo<T> <= ? extends Foo<?>
.
Applying 4.10.2 we have that Set<? extends Foo<?>>
is a direct supertype of Set<Foo<T>>
.
The formal answer to why your first example does not compile may be got by assuming a contradiction. Percisely:
If Set<Foo<T>> <: Set<Foo<?>>
we have that Foo<T> <= Foo<?>
which is not possible to prove applying reflexive or transitive relations to rules from 4.5.1.
add a comment |
That's because Foo<?>
does not extend Foo<T>
Even in the case where ? is replaced by a class that actually extends T.
Example : Integer extends Number, but Foo<Integer>
does not extend Foo<Number>
add a comment |
I think simply because the Set
element Datatype is different while it must be the same except for Generic Datatype.
the first set Set<Foo<T>>
datatype is Foo<T>
,
then second set Set<Foo<?>>
is Foo<?>
,
As I can see the element datatype is different Foo<T> != Foo<?>
and not generic type because it use Foo
, so then would cause compilation error.
It is same as below invalid different datatype example :
Set<List<T>> set3 = new HashSet<>();
Set<List<?>> set4 = set3; // compilation error due to different element datatype List<T> != List<?>
Set<? extends Foo<?>> set3 = set1;
can because it have ? datatype
which is generic and have purpose can accept any datatype.
ex :
Set<List<T>> set4 = new HashSet<>();
Set<?> set5 = set4; // would be Ok
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
});
}
});
Stoyan Radnev is a new contributor. Be nice, and check out our Code of Conduct.
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%2f54105832%2fwhy-is-set-extends-foo-allowed-but-setfoo-is-not%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
Perhaps the issue becomes clearer if you leave the generic parameter of Foo out of the equation.
Consider
final Set<Foo> set1 = new HashSet<>();
Set<Object> set2 = set1;
This makes the compile error more obvious. If this was valid, it would be possible to insert an object into set2, thus into set1 violating the type constraint.
Set<? extends Foo> set3 = set1;
This is perfectly valid because set1 would also accept types derived from Foo.
why did you transformSet<Foo<?>>
toSet<Object>
after type erasure? I guess wildcard will be replaced byObject
since it is closest bound?
– Sergey Prokofiev
2 hours ago
Foo<?>
is notObject
, it isFoo
"of something". What allows the assignment toset3
is the covariance.
– kagmole
2 hours ago
Also you answer implies thatset3
is writable, which is not the case. See more about covariance and contravariance here : stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
add a comment |
Perhaps the issue becomes clearer if you leave the generic parameter of Foo out of the equation.
Consider
final Set<Foo> set1 = new HashSet<>();
Set<Object> set2 = set1;
This makes the compile error more obvious. If this was valid, it would be possible to insert an object into set2, thus into set1 violating the type constraint.
Set<? extends Foo> set3 = set1;
This is perfectly valid because set1 would also accept types derived from Foo.
why did you transformSet<Foo<?>>
toSet<Object>
after type erasure? I guess wildcard will be replaced byObject
since it is closest bound?
– Sergey Prokofiev
2 hours ago
Foo<?>
is notObject
, it isFoo
"of something". What allows the assignment toset3
is the covariance.
– kagmole
2 hours ago
Also you answer implies thatset3
is writable, which is not the case. See more about covariance and contravariance here : stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
add a comment |
Perhaps the issue becomes clearer if you leave the generic parameter of Foo out of the equation.
Consider
final Set<Foo> set1 = new HashSet<>();
Set<Object> set2 = set1;
This makes the compile error more obvious. If this was valid, it would be possible to insert an object into set2, thus into set1 violating the type constraint.
Set<? extends Foo> set3 = set1;
This is perfectly valid because set1 would also accept types derived from Foo.
Perhaps the issue becomes clearer if you leave the generic parameter of Foo out of the equation.
Consider
final Set<Foo> set1 = new HashSet<>();
Set<Object> set2 = set1;
This makes the compile error more obvious. If this was valid, it would be possible to insert an object into set2, thus into set1 violating the type constraint.
Set<? extends Foo> set3 = set1;
This is perfectly valid because set1 would also accept types derived from Foo.
edited 2 hours ago
answered 3 hours ago
leftbitleftbit
541414
541414
why did you transformSet<Foo<?>>
toSet<Object>
after type erasure? I guess wildcard will be replaced byObject
since it is closest bound?
– Sergey Prokofiev
2 hours ago
Foo<?>
is notObject
, it isFoo
"of something". What allows the assignment toset3
is the covariance.
– kagmole
2 hours ago
Also you answer implies thatset3
is writable, which is not the case. See more about covariance and contravariance here : stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
add a comment |
why did you transformSet<Foo<?>>
toSet<Object>
after type erasure? I guess wildcard will be replaced byObject
since it is closest bound?
– Sergey Prokofiev
2 hours ago
Foo<?>
is notObject
, it isFoo
"of something". What allows the assignment toset3
is the covariance.
– kagmole
2 hours ago
Also you answer implies thatset3
is writable, which is not the case. See more about covariance and contravariance here : stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
why did you transform
Set<Foo<?>>
to Set<Object>
after type erasure? I guess wildcard will be replaced by Object
since it is closest bound?– Sergey Prokofiev
2 hours ago
why did you transform
Set<Foo<?>>
to Set<Object>
after type erasure? I guess wildcard will be replaced by Object
since it is closest bound?– Sergey Prokofiev
2 hours ago
Foo<?>
is not Object
, it is Foo
"of something". What allows the assignment to set3
is the covariance.– kagmole
2 hours ago
Foo<?>
is not Object
, it is Foo
"of something". What allows the assignment to set3
is the covariance.– kagmole
2 hours ago
Also you answer implies that
set3
is writable, which is not the case. See more about covariance and contravariance here : stackoverflow.com/a/4343547/7709086– kagmole
2 hours ago
Also you answer implies that
set3
is writable, which is not the case. See more about covariance and contravariance here : stackoverflow.com/a/4343547/7709086– kagmole
2 hours ago
add a comment |
Simply said, this is because Set<? extends Foo<?>>
is covariant (with the extends
keyword). Covariant types are read-only and the compiler will refuse any write action, like Set.add(..)
.
Set<Foo<?>>
is not covariant. It does not block write or read actions.
This...
Set<Foo<String>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // KO by compiler
... is illegal because I could for example write an Integer in set1
with set2
.
set2.add(new Foo<Integer>()); // Whoopsie
But...
Set<Foo<String>> set1 = new HashSet<>();
Set<? extends Foo<?>> set3 = set1; // OK
... is covariant (extends
keyword), so it is legal. The compiler will refuse a set3.add(42)
. You can only read from set3
, not write.
set3.add(new Foo<Integer>()); // KO by compiler
See these posts for a better explanation:
- https://stackoverflow.com/a/4343547/7709086
- https://medium.freecodecamp.org/understanding-java-generic-types-covariance-and-contravariance-88f4c19763d2
3
Did you meanFoo<Integer> foo; set2.add(foo);
becauseset2.add(42)
42 isn't aFoo<?>
.
– matt
1 hour ago
Oops thank you @matt, I fixed my answer.
– kagmole
1 hour ago
add a comment |
Simply said, this is because Set<? extends Foo<?>>
is covariant (with the extends
keyword). Covariant types are read-only and the compiler will refuse any write action, like Set.add(..)
.
Set<Foo<?>>
is not covariant. It does not block write or read actions.
This...
Set<Foo<String>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // KO by compiler
... is illegal because I could for example write an Integer in set1
with set2
.
set2.add(new Foo<Integer>()); // Whoopsie
But...
Set<Foo<String>> set1 = new HashSet<>();
Set<? extends Foo<?>> set3 = set1; // OK
... is covariant (extends
keyword), so it is legal. The compiler will refuse a set3.add(42)
. You can only read from set3
, not write.
set3.add(new Foo<Integer>()); // KO by compiler
See these posts for a better explanation:
- https://stackoverflow.com/a/4343547/7709086
- https://medium.freecodecamp.org/understanding-java-generic-types-covariance-and-contravariance-88f4c19763d2
3
Did you meanFoo<Integer> foo; set2.add(foo);
becauseset2.add(42)
42 isn't aFoo<?>
.
– matt
1 hour ago
Oops thank you @matt, I fixed my answer.
– kagmole
1 hour ago
add a comment |
Simply said, this is because Set<? extends Foo<?>>
is covariant (with the extends
keyword). Covariant types are read-only and the compiler will refuse any write action, like Set.add(..)
.
Set<Foo<?>>
is not covariant. It does not block write or read actions.
This...
Set<Foo<String>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // KO by compiler
... is illegal because I could for example write an Integer in set1
with set2
.
set2.add(new Foo<Integer>()); // Whoopsie
But...
Set<Foo<String>> set1 = new HashSet<>();
Set<? extends Foo<?>> set3 = set1; // OK
... is covariant (extends
keyword), so it is legal. The compiler will refuse a set3.add(42)
. You can only read from set3
, not write.
set3.add(new Foo<Integer>()); // KO by compiler
See these posts for a better explanation:
- https://stackoverflow.com/a/4343547/7709086
- https://medium.freecodecamp.org/understanding-java-generic-types-covariance-and-contravariance-88f4c19763d2
Simply said, this is because Set<? extends Foo<?>>
is covariant (with the extends
keyword). Covariant types are read-only and the compiler will refuse any write action, like Set.add(..)
.
Set<Foo<?>>
is not covariant. It does not block write or read actions.
This...
Set<Foo<String>> set1 = new HashSet<>();
Set<Foo<?>> set2 = set1; // KO by compiler
... is illegal because I could for example write an Integer in set1
with set2
.
set2.add(new Foo<Integer>()); // Whoopsie
But...
Set<Foo<String>> set1 = new HashSet<>();
Set<? extends Foo<?>> set3 = set1; // OK
... is covariant (extends
keyword), so it is legal. The compiler will refuse a set3.add(42)
. You can only read from set3
, not write.
set3.add(new Foo<Integer>()); // KO by compiler
See these posts for a better explanation:
- https://stackoverflow.com/a/4343547/7709086
- https://medium.freecodecamp.org/understanding-java-generic-types-covariance-and-contravariance-88f4c19763d2
edited 1 hour ago
answered 2 hours ago
kagmolekagmole
1,012317
1,012317
3
Did you meanFoo<Integer> foo; set2.add(foo);
becauseset2.add(42)
42 isn't aFoo<?>
.
– matt
1 hour ago
Oops thank you @matt, I fixed my answer.
– kagmole
1 hour ago
add a comment |
3
Did you meanFoo<Integer> foo; set2.add(foo);
becauseset2.add(42)
42 isn't aFoo<?>
.
– matt
1 hour ago
Oops thank you @matt, I fixed my answer.
– kagmole
1 hour ago
3
3
Did you mean
Foo<Integer> foo; set2.add(foo);
because set2.add(42)
42 isn't a Foo<?>
.– matt
1 hour ago
Did you mean
Foo<Integer> foo; set2.add(foo);
because set2.add(42)
42 isn't a Foo<?>
.– matt
1 hour ago
Oops thank you @matt, I fixed my answer.
– kagmole
1 hour ago
Oops thank you @matt, I fixed my answer.
– kagmole
1 hour ago
add a comment |
Additionally to the answers given already I'll add some formal explanation.
Given by 4.10.2 (emp. mine)
Given a generic type declaration C (n > 0), the direct
supertypes of the parameterized type C, where Ti (1 ≤ i ≤
n) is a type, are all of the following:
D < U1 θ,...,Uk θ>, where D is a generic type which is a
direct supertype of the generic type C and θ is the
substitution [F1:=T1,...,Fn:=Tn].
C < S1,...,Sn> , where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
The type Object, if C is a generic interface type with no
direct superinterfaces.
The raw type C.
Rule for contains
are specified at 4.5.1:
A type argument T1 is said to contain another type argument T2,
written T2 <= T1, if the set of types denoted by T2 is provably a
subset of the set of types denoted by T1 under the reflexive and
transitive closure of the following rules (where <: denotes subtyping
(§4.10)):
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
Since T <= ? super T <= ? extends Object = ?
so applying 4.10.2 Foo<T> <: Foo<?>
we have ? extends Foo<T> <= ? extends Foo<?>
. But Foo<T> <= ? extends Foo<T>
so we have Foo<T> <= ? extends Foo<?>
.
Applying 4.10.2 we have that Set<? extends Foo<?>>
is a direct supertype of Set<Foo<T>>
.
The formal answer to why your first example does not compile may be got by assuming a contradiction. Percisely:
If Set<Foo<T>> <: Set<Foo<?>>
we have that Foo<T> <= Foo<?>
which is not possible to prove applying reflexive or transitive relations to rules from 4.5.1.
add a comment |
Additionally to the answers given already I'll add some formal explanation.
Given by 4.10.2 (emp. mine)
Given a generic type declaration C (n > 0), the direct
supertypes of the parameterized type C, where Ti (1 ≤ i ≤
n) is a type, are all of the following:
D < U1 θ,...,Uk θ>, where D is a generic type which is a
direct supertype of the generic type C and θ is the
substitution [F1:=T1,...,Fn:=Tn].
C < S1,...,Sn> , where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
The type Object, if C is a generic interface type with no
direct superinterfaces.
The raw type C.
Rule for contains
are specified at 4.5.1:
A type argument T1 is said to contain another type argument T2,
written T2 <= T1, if the set of types denoted by T2 is provably a
subset of the set of types denoted by T1 under the reflexive and
transitive closure of the following rules (where <: denotes subtyping
(§4.10)):
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
Since T <= ? super T <= ? extends Object = ?
so applying 4.10.2 Foo<T> <: Foo<?>
we have ? extends Foo<T> <= ? extends Foo<?>
. But Foo<T> <= ? extends Foo<T>
so we have Foo<T> <= ? extends Foo<?>
.
Applying 4.10.2 we have that Set<? extends Foo<?>>
is a direct supertype of Set<Foo<T>>
.
The formal answer to why your first example does not compile may be got by assuming a contradiction. Percisely:
If Set<Foo<T>> <: Set<Foo<?>>
we have that Foo<T> <= Foo<?>
which is not possible to prove applying reflexive or transitive relations to rules from 4.5.1.
add a comment |
Additionally to the answers given already I'll add some formal explanation.
Given by 4.10.2 (emp. mine)
Given a generic type declaration C (n > 0), the direct
supertypes of the parameterized type C, where Ti (1 ≤ i ≤
n) is a type, are all of the following:
D < U1 θ,...,Uk θ>, where D is a generic type which is a
direct supertype of the generic type C and θ is the
substitution [F1:=T1,...,Fn:=Tn].
C < S1,...,Sn> , where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
The type Object, if C is a generic interface type with no
direct superinterfaces.
The raw type C.
Rule for contains
are specified at 4.5.1:
A type argument T1 is said to contain another type argument T2,
written T2 <= T1, if the set of types denoted by T2 is provably a
subset of the set of types denoted by T1 under the reflexive and
transitive closure of the following rules (where <: denotes subtyping
(§4.10)):
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
Since T <= ? super T <= ? extends Object = ?
so applying 4.10.2 Foo<T> <: Foo<?>
we have ? extends Foo<T> <= ? extends Foo<?>
. But Foo<T> <= ? extends Foo<T>
so we have Foo<T> <= ? extends Foo<?>
.
Applying 4.10.2 we have that Set<? extends Foo<?>>
is a direct supertype of Set<Foo<T>>
.
The formal answer to why your first example does not compile may be got by assuming a contradiction. Percisely:
If Set<Foo<T>> <: Set<Foo<?>>
we have that Foo<T> <= Foo<?>
which is not possible to prove applying reflexive or transitive relations to rules from 4.5.1.
Additionally to the answers given already I'll add some formal explanation.
Given by 4.10.2 (emp. mine)
Given a generic type declaration C (n > 0), the direct
supertypes of the parameterized type C, where Ti (1 ≤ i ≤
n) is a type, are all of the following:
D < U1 θ,...,Uk θ>, where D is a generic type which is a
direct supertype of the generic type C and θ is the
substitution [F1:=T1,...,Fn:=Tn].
C < S1,...,Sn> , where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
The type Object, if C is a generic interface type with no
direct superinterfaces.
The raw type C.
Rule for contains
are specified at 4.5.1:
A type argument T1 is said to contain another type argument T2,
written T2 <= T1, if the set of types denoted by T2 is provably a
subset of the set of types denoted by T1 under the reflexive and
transitive closure of the following rules (where <: denotes subtyping
(§4.10)):
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
Since T <= ? super T <= ? extends Object = ?
so applying 4.10.2 Foo<T> <: Foo<?>
we have ? extends Foo<T> <= ? extends Foo<?>
. But Foo<T> <= ? extends Foo<T>
so we have Foo<T> <= ? extends Foo<?>
.
Applying 4.10.2 we have that Set<? extends Foo<?>>
is a direct supertype of Set<Foo<T>>
.
The formal answer to why your first example does not compile may be got by assuming a contradiction. Percisely:
If Set<Foo<T>> <: Set<Foo<?>>
we have that Foo<T> <= Foo<?>
which is not possible to prove applying reflexive or transitive relations to rules from 4.5.1.
edited 1 hour ago
answered 1 hour ago
St.AntarioSt.Antario
9,4061551138
9,4061551138
add a comment |
add a comment |
That's because Foo<?>
does not extend Foo<T>
Even in the case where ? is replaced by a class that actually extends T.
Example : Integer extends Number, but Foo<Integer>
does not extend Foo<Number>
add a comment |
That's because Foo<?>
does not extend Foo<T>
Even in the case where ? is replaced by a class that actually extends T.
Example : Integer extends Number, but Foo<Integer>
does not extend Foo<Number>
add a comment |
That's because Foo<?>
does not extend Foo<T>
Even in the case where ? is replaced by a class that actually extends T.
Example : Integer extends Number, but Foo<Integer>
does not extend Foo<Number>
That's because Foo<?>
does not extend Foo<T>
Even in the case where ? is replaced by a class that actually extends T.
Example : Integer extends Number, but Foo<Integer>
does not extend Foo<Number>
answered 2 hours ago
Florian NicolasFlorian Nicolas
113
113
add a comment |
add a comment |
I think simply because the Set
element Datatype is different while it must be the same except for Generic Datatype.
the first set Set<Foo<T>>
datatype is Foo<T>
,
then second set Set<Foo<?>>
is Foo<?>
,
As I can see the element datatype is different Foo<T> != Foo<?>
and not generic type because it use Foo
, so then would cause compilation error.
It is same as below invalid different datatype example :
Set<List<T>> set3 = new HashSet<>();
Set<List<?>> set4 = set3; // compilation error due to different element datatype List<T> != List<?>
Set<? extends Foo<?>> set3 = set1;
can because it have ? datatype
which is generic and have purpose can accept any datatype.
ex :
Set<List<T>> set4 = new HashSet<>();
Set<?> set5 = set4; // would be Ok
add a comment |
I think simply because the Set
element Datatype is different while it must be the same except for Generic Datatype.
the first set Set<Foo<T>>
datatype is Foo<T>
,
then second set Set<Foo<?>>
is Foo<?>
,
As I can see the element datatype is different Foo<T> != Foo<?>
and not generic type because it use Foo
, so then would cause compilation error.
It is same as below invalid different datatype example :
Set<List<T>> set3 = new HashSet<>();
Set<List<?>> set4 = set3; // compilation error due to different element datatype List<T> != List<?>
Set<? extends Foo<?>> set3 = set1;
can because it have ? datatype
which is generic and have purpose can accept any datatype.
ex :
Set<List<T>> set4 = new HashSet<>();
Set<?> set5 = set4; // would be Ok
add a comment |
I think simply because the Set
element Datatype is different while it must be the same except for Generic Datatype.
the first set Set<Foo<T>>
datatype is Foo<T>
,
then second set Set<Foo<?>>
is Foo<?>
,
As I can see the element datatype is different Foo<T> != Foo<?>
and not generic type because it use Foo
, so then would cause compilation error.
It is same as below invalid different datatype example :
Set<List<T>> set3 = new HashSet<>();
Set<List<?>> set4 = set3; // compilation error due to different element datatype List<T> != List<?>
Set<? extends Foo<?>> set3 = set1;
can because it have ? datatype
which is generic and have purpose can accept any datatype.
ex :
Set<List<T>> set4 = new HashSet<>();
Set<?> set5 = set4; // would be Ok
I think simply because the Set
element Datatype is different while it must be the same except for Generic Datatype.
the first set Set<Foo<T>>
datatype is Foo<T>
,
then second set Set<Foo<?>>
is Foo<?>
,
As I can see the element datatype is different Foo<T> != Foo<?>
and not generic type because it use Foo
, so then would cause compilation error.
It is same as below invalid different datatype example :
Set<List<T>> set3 = new HashSet<>();
Set<List<?>> set4 = set3; // compilation error due to different element datatype List<T> != List<?>
Set<? extends Foo<?>> set3 = set1;
can because it have ? datatype
which is generic and have purpose can accept any datatype.
ex :
Set<List<T>> set4 = new HashSet<>();
Set<?> set5 = set4; // would be Ok
edited 52 mins ago
answered 1 hour ago
M Fauzan AbdiM Fauzan Abdi
24617
24617
add a comment |
add a comment |
Stoyan Radnev is a new contributor. Be nice, and check out our Code of Conduct.
Stoyan Radnev is a new contributor. Be nice, and check out our Code of Conduct.
Stoyan Radnev is a new contributor. Be nice, and check out our Code of Conduct.
Stoyan Radnev is a new contributor. Be nice, and check out our Code of Conduct.
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%2f54105832%2fwhy-is-set-extends-foo-allowed-but-setfoo-is-not%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
An interesting reading about this "issue": stackoverflow.com/a/4343547/7709086
– kagmole
2 hours ago
3
Possible duplicate of What is PECS (Producer Extends Consumer Super)?
– Lino
1 hour ago
1
@Lino: This question is similar to and related to "What is PECS", but not exactly the same. This question is about PECS, but specifically applied to the case when the type arguments themselves are types which have type parameters. That makes this a particularly tricky special case, which warrants its own question. (But I'd be surprised if there is no other exactly duplicate question some where.)
– Lii
36 mins ago