You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@groovy.apache.org by "Winnebeck, Jason" <Ja...@windstream.com> on 2015/12/02 15:44:15 UTC

CompileStatic and right-hand-side literals

Is there a way to avoid awkward typing issues with literals as in this case:

@CompileStatic
void f() {
  Map<String, Object> x = [a: '1']
  println x + [b: 2]
}

This results in the following errors in 2.4.5:

[Static type checking] - Incompatible generic argument types. Cannot assign java.util.LinkedHashMap <java.lang.String, java.lang.String> to: java.util.Map <String, Object>
 at line: 3, column: 27

[Static type checking] - Cannot call <K,V> java.util.LinkedHashMap <java.lang.String, java.lang.String>#plus(java.util.Map <java.lang.String, java.lang.String>) with arguments [java.util.LinkedHashMap <java.lang.String, java.lang.Integer>] 
 at line: 4, column: 13

It seems that the static compiler has issues with inferring RHS types. I think it might be similar to this case I run into from time to time:

@CompileStatic
void g(List<Integer> items) {}

@CompileStatic
void h() {
  g(Collections.emptyList())
}

Results in:
[Static type checking] - Cannot call ConsoleScript6#g(java.util.List <java.lang.Integer>) with arguments [java.util.List <T extends java.lang.Object>]

Jason Winnebeck

----------------------------------------------------------------------
This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.

Re: CompileStatic and right-hand-side literals

Posted by Dinko Srkoč <di...@gmail.com>.
On 2 December 2015 at 16:26, Cédric Champeau <ce...@gmail.com> wrote:
> You are actually talking about the second error, but it's a direct
> consequence of flow typing (that Scala doesn't have). And if we didn't have
> that, no doubt that even more frustration would come (look at the history of
> type checking bugs for type inference of literals to get an idea).

Yes, sorry, the second error.

Anyway, here by reducing the type information, we can actually help
the type checker.
Less is indeed more. :-)

  ([a: 'foo'] as Map) + [b: 1]  // this works

Cheers,
Dinko

>
> 2015-12-02 16:23 GMT+01:00 Dinko Srkoč <di...@gmail.com>:
>>
>> On 2 December 2015 at 15:48, Cédric Champeau <ce...@gmail.com>
>> wrote:
>> > I think that the type checker is technically correct here. The RHS is
>> > correctly inferred (it's a `Map<String, String>`). And since you are
>> > trying
>> > to assign it to `Map<String, Object>` it fails. It's a consequence of
>> > inference of literals (Java doesn't have such literals so no such
>> > issues).
>> > You have to separate declaration from assignment, or use a cast.
>>
>> It may be technically correct, but it also seems a bit too rigid. If
>> it tried to calculate the LUB of those type parameters, it would infer
>> the type as `Map<String, Object>` and wouldn't report the error.
>>
>> As it happens, I encountered this very problem (from Jason's example,
>> at line: 4, calling `#plus`) today.
>>
>> I reluctantly call upon Scala, but it has a solid type system and it
>> does the right thing here:
>>
>>   scala> Map("a" -> 1) ++ Map("b" -> "foo")
>>   res0: scala.collection.immutable.Map[String,Any] = Map(a -> 1, b -> foo)
>>
>> I'm not saying this is how Groovy must behave, just that current
>> behaviour is a bit surprising. ;-)
>>
>> Cheers,
>> Dinko
>>
>> >
>> > 2015-12-02 15:44 GMT+01:00 Winnebeck, Jason
>> > <Ja...@windstream.com>:
>> >>
>> >> Is there a way to avoid awkward typing issues with literals as in this
>> >> case:
>> >>
>> >> @CompileStatic
>> >> void f() {
>> >>   Map<String, Object> x = [a: '1']
>> >>   println x + [b: 2]
>> >> }
>> >>
>> >> This results in the following errors in 2.4.5:
>> >>
>> >> [Static type checking] - Incompatible generic argument types. Cannot
>> >> assign java.util.LinkedHashMap <java.lang.String, java.lang.String> to:
>> >> java.util.Map <String, Object>
>> >>  at line: 3, column: 27
>> >>
>> >> [Static type checking] - Cannot call <K,V> java.util.LinkedHashMap
>> >> <java.lang.String, java.lang.String>#plus(java.util.Map
>> >> <java.lang.String,
>> >> java.lang.String>) with arguments [java.util.LinkedHashMap
>> >> <java.lang.String, java.lang.Integer>]
>> >>  at line: 4, column: 13
>> >>
>> >> It seems that the static compiler has issues with inferring RHS types.
>> >> I
>> >> think it might be similar to this case I run into from time to time:
>> >>
>> >> @CompileStatic
>> >> void g(List<Integer> items) {}
>> >>
>> >> @CompileStatic
>> >> void h() {
>> >>   g(Collections.emptyList())
>> >> }
>> >>
>> >> Results in:
>> >> [Static type checking] - Cannot call ConsoleScript6#g(java.util.List
>> >> <java.lang.Integer>) with arguments [java.util.List <T extends
>> >> java.lang.Object>]
>> >>
>> >> Jason Winnebeck
>> >>
>> >> ----------------------------------------------------------------------
>> >> This email message and any attachments are for the sole use of the
>> >> intended recipient(s). Any unauthorized review, use, disclosure or
>> >> distribution is prohibited. If you are not the intended recipient,
>> >> please
>> >> contact the sender by reply email and destroy all copies of the
>> >> original
>> >> message and any attachments.
>> >
>> >
>
>

Re: CompileStatic and right-hand-side literals

Posted by Cédric Champeau <ce...@gmail.com>.
You are actually talking about the second error, but it's a direct
consequence of flow typing (that Scala doesn't have). And if we didn't have
that, no doubt that even more frustration would come (look at the history
of type checking bugs for type inference of literals to get an idea).

2015-12-02 16:23 GMT+01:00 Dinko Srkoč <di...@gmail.com>:

> On 2 December 2015 at 15:48, Cédric Champeau <ce...@gmail.com>
> wrote:
> > I think that the type checker is technically correct here. The RHS is
> > correctly inferred (it's a `Map<String, String>`). And since you are
> trying
> > to assign it to `Map<String, Object>` it fails. It's a consequence of
> > inference of literals (Java doesn't have such literals so no such
> issues).
> > You have to separate declaration from assignment, or use a cast.
>
> It may be technically correct, but it also seems a bit too rigid. If
> it tried to calculate the LUB of those type parameters, it would infer
> the type as `Map<String, Object>` and wouldn't report the error.
>
> As it happens, I encountered this very problem (from Jason's example,
> at line: 4, calling `#plus`) today.
>
> I reluctantly call upon Scala, but it has a solid type system and it
> does the right thing here:
>
>   scala> Map("a" -> 1) ++ Map("b" -> "foo")
>   res0: scala.collection.immutable.Map[String,Any] = Map(a -> 1, b -> foo)
>
> I'm not saying this is how Groovy must behave, just that current
> behaviour is a bit surprising. ;-)
>
> Cheers,
> Dinko
>
> >
> > 2015-12-02 15:44 GMT+01:00 Winnebeck, Jason
> > <Ja...@windstream.com>:
> >>
> >> Is there a way to avoid awkward typing issues with literals as in this
> >> case:
> >>
> >> @CompileStatic
> >> void f() {
> >>   Map<String, Object> x = [a: '1']
> >>   println x + [b: 2]
> >> }
> >>
> >> This results in the following errors in 2.4.5:
> >>
> >> [Static type checking] - Incompatible generic argument types. Cannot
> >> assign java.util.LinkedHashMap <java.lang.String, java.lang.String> to:
> >> java.util.Map <String, Object>
> >>  at line: 3, column: 27
> >>
> >> [Static type checking] - Cannot call <K,V> java.util.LinkedHashMap
> >> <java.lang.String, java.lang.String>#plus(java.util.Map
> <java.lang.String,
> >> java.lang.String>) with arguments [java.util.LinkedHashMap
> >> <java.lang.String, java.lang.Integer>]
> >>  at line: 4, column: 13
> >>
> >> It seems that the static compiler has issues with inferring RHS types. I
> >> think it might be similar to this case I run into from time to time:
> >>
> >> @CompileStatic
> >> void g(List<Integer> items) {}
> >>
> >> @CompileStatic
> >> void h() {
> >>   g(Collections.emptyList())
> >> }
> >>
> >> Results in:
> >> [Static type checking] - Cannot call ConsoleScript6#g(java.util.List
> >> <java.lang.Integer>) with arguments [java.util.List <T extends
> >> java.lang.Object>]
> >>
> >> Jason Winnebeck
> >>
> >> ----------------------------------------------------------------------
> >> This email message and any attachments are for the sole use of the
> >> intended recipient(s). Any unauthorized review, use, disclosure or
> >> distribution is prohibited. If you are not the intended recipient,
> please
> >> contact the sender by reply email and destroy all copies of the original
> >> message and any attachments.
> >
> >
>

Re: CompileStatic and right-hand-side literals

Posted by Dinko Srkoč <di...@gmail.com>.
On 2 December 2015 at 15:48, Cédric Champeau <ce...@gmail.com> wrote:
> I think that the type checker is technically correct here. The RHS is
> correctly inferred (it's a `Map<String, String>`). And since you are trying
> to assign it to `Map<String, Object>` it fails. It's a consequence of
> inference of literals (Java doesn't have such literals so no such issues).
> You have to separate declaration from assignment, or use a cast.

It may be technically correct, but it also seems a bit too rigid. If
it tried to calculate the LUB of those type parameters, it would infer
the type as `Map<String, Object>` and wouldn't report the error.

As it happens, I encountered this very problem (from Jason's example,
at line: 4, calling `#plus`) today.

I reluctantly call upon Scala, but it has a solid type system and it
does the right thing here:

  scala> Map("a" -> 1) ++ Map("b" -> "foo")
  res0: scala.collection.immutable.Map[String,Any] = Map(a -> 1, b -> foo)

I'm not saying this is how Groovy must behave, just that current
behaviour is a bit surprising. ;-)

Cheers,
Dinko

>
> 2015-12-02 15:44 GMT+01:00 Winnebeck, Jason
> <Ja...@windstream.com>:
>>
>> Is there a way to avoid awkward typing issues with literals as in this
>> case:
>>
>> @CompileStatic
>> void f() {
>>   Map<String, Object> x = [a: '1']
>>   println x + [b: 2]
>> }
>>
>> This results in the following errors in 2.4.5:
>>
>> [Static type checking] - Incompatible generic argument types. Cannot
>> assign java.util.LinkedHashMap <java.lang.String, java.lang.String> to:
>> java.util.Map <String, Object>
>>  at line: 3, column: 27
>>
>> [Static type checking] - Cannot call <K,V> java.util.LinkedHashMap
>> <java.lang.String, java.lang.String>#plus(java.util.Map <java.lang.String,
>> java.lang.String>) with arguments [java.util.LinkedHashMap
>> <java.lang.String, java.lang.Integer>]
>>  at line: 4, column: 13
>>
>> It seems that the static compiler has issues with inferring RHS types. I
>> think it might be similar to this case I run into from time to time:
>>
>> @CompileStatic
>> void g(List<Integer> items) {}
>>
>> @CompileStatic
>> void h() {
>>   g(Collections.emptyList())
>> }
>>
>> Results in:
>> [Static type checking] - Cannot call ConsoleScript6#g(java.util.List
>> <java.lang.Integer>) with arguments [java.util.List <T extends
>> java.lang.Object>]
>>
>> Jason Winnebeck
>>
>> ----------------------------------------------------------------------
>> This email message and any attachments are for the sole use of the
>> intended recipient(s). Any unauthorized review, use, disclosure or
>> distribution is prohibited. If you are not the intended recipient, please
>> contact the sender by reply email and destroy all copies of the original
>> message and any attachments.
>
>

RE: CompileStatic and right-hand-side literals

Posted by "Winnebeck, Jason" <Ja...@windstream.com>.
It is technically correct, but for example I was able to assign [a: ‘1’] to a Map<String, Object>, so for variable assignment it works, but not for plus.

In my second example I use Collections.emptyList(), which in Java exists expressly to avoid casts that are required when using Collections.EMPTY_LIST. So this is code that would work in Java exactly as-is but does not work in Groovy. It means that the ability to return template generic type seems not to exist in Groovy.

In both cases, I can use a cast to fix the issue, although in IntelliJ it’s annoying because it thinks you can’t cast a Map<String, Integer> to a Map<String, Object> (which would be true in Java code), although groovyc itself allows it. So then you have the awkward workaround of [b: (Object)2], which seems very anti-Groovy (especially given the very recent conversation on this list about removing unnecessary syntax around closures). In the second case, I can use Collections.<Integer>emptyList(), but in this case the Groovy code is more verbose than the Java code.

Jason

From: Cédric Champeau [mailto:cedric.champeau@gmail.com]
Sent: Wednesday, December 02, 2015 9:48 AM
To: users@groovy.apache.org
Subject: Re: CompileStatic and right-hand-side literals

I think that the type checker is technically correct here. The RHS is correctly inferred (it's a `Map<String, String>`). And since you are trying to assign it to `Map<String, Object>` it fails. It's a consequence of inference of literals (Java doesn't have such literals so no such issues). You have to separate declaration from assignment, or use a cast.

2015-12-02 15:44 GMT+01:00 Winnebeck, Jason <Ja...@windstream.com>>:
Is there a way to avoid awkward typing issues with literals as in this case:

@CompileStatic
void f() {
  Map<String, Object> x = [a: '1']
  println x + [b: 2]
}

This results in the following errors in 2.4.5:

[Static type checking] - Incompatible generic argument types. Cannot assign java.util.LinkedHashMap <java.lang.String, java.lang.String> to: java.util.Map <String, Object>
 at line: 3, column: 27

[Static type checking] - Cannot call <K,V> java.util.LinkedHashMap <java.lang.String, java.lang.String>#plus(java.util.Map <java.lang.String, java.lang.String>) with arguments [java.util.LinkedHashMap <java.lang.String, java.lang.Integer>]
 at line: 4, column: 13

It seems that the static compiler has issues with inferring RHS types. I think it might be similar to this case I run into from time to time:

@CompileStatic
void g(List<Integer> items) {}

@CompileStatic
void h() {
  g(Collections.emptyList())
}

Results in:
[Static type checking] - Cannot call ConsoleScript6#g(java.util.List <java.lang.Integer>) with arguments [java.util.List <T extends java.lang.Object>]

Jason Winnebeck

----------------------------------------------------------------------
This email message and any attachments are for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message and any attachments.


Re: CompileStatic and right-hand-side literals

Posted by Cédric Champeau <ce...@gmail.com>.
I think that the type checker is technically correct here. The RHS is
correctly inferred (it's a `Map<String, String>`). And since you are trying
to assign it to `Map<String, Object>` it fails. It's a consequence of
inference of literals (Java doesn't have such literals so no such issues).
You have to separate declaration from assignment, or use a cast.

2015-12-02 15:44 GMT+01:00 Winnebeck, Jason <Ja...@windstream.com>
:

> Is there a way to avoid awkward typing issues with literals as in this
> case:
>
> @CompileStatic
> void f() {
>   Map<String, Object> x = [a: '1']
>   println x + [b: 2]
> }
>
> This results in the following errors in 2.4.5:
>
> [Static type checking] - Incompatible generic argument types. Cannot
> assign java.util.LinkedHashMap <java.lang.String, java.lang.String> to:
> java.util.Map <String, Object>
>  at line: 3, column: 27
>
> [Static type checking] - Cannot call <K,V> java.util.LinkedHashMap
> <java.lang.String, java.lang.String>#plus(java.util.Map <java.lang.String,
> java.lang.String>) with arguments [java.util.LinkedHashMap
> <java.lang.String, java.lang.Integer>]
>  at line: 4, column: 13
>
> It seems that the static compiler has issues with inferring RHS types. I
> think it might be similar to this case I run into from time to time:
>
> @CompileStatic
> void g(List<Integer> items) {}
>
> @CompileStatic
> void h() {
>   g(Collections.emptyList())
> }
>
> Results in:
> [Static type checking] - Cannot call ConsoleScript6#g(java.util.List
> <java.lang.Integer>) with arguments [java.util.List <T extends
> java.lang.Object>]
>
> Jason Winnebeck
>
> ----------------------------------------------------------------------
> This email message and any attachments are for the sole use of the
> intended recipient(s). Any unauthorized review, use, disclosure or
> distribution is prohibited. If you are not the intended recipient, please
> contact the sender by reply email and destroy all copies of the original
> message and any attachments.
>