Re: Odd behaviour of List to Map coercion within function arguments

Paul King <[email protected]>
Newsgroups gmane.comp.lang.groovy.user
Message-ID <CAMbkE7RFW78Y1ihEScQi1triD0tYt6jRYzA-5LcrMi2DyS1fpA@mail.gmail.com>
I am not sure I have the full history of when support started (at
least 15+ years ago) but dynamic Groovy unwraps a list as arguments:

def avg(int a, int b, int c) { (a + b + c)/3 }
assert avg(1, 2, 3) == 2    // normal invocation
def nums = [10, 20, 30]
assert avg(nums) == 20    // args are a list

It will only do this if the argument is a single List and no method
matching a single List argument was found. Relevant implementation:

https://github.com/apache/groovy/blob/master/src/main/java/groovy/lang/MetaClassImpl.java#L1242
https://github.com/apache/groovy/blob/master/src/main/java/groovy/lang/MetaClassImpl.java#L1246-L1253

You can turn this feature off with @TypeChecked/@CompileStatic.

Cheers, Paul.

<https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
Virus-free.www.avast.com
<https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail>
<#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>

On Sat, Mar 9, 2024 at 7:58 AM Simon Sadedin <[email protected]> wrote:
>
> Hi,
>
> I am trying to understand some behaviour that is causing subtle and odd bugs in our code.
>
> The behaviour is essentially that under very specific circumstances, Groovy is coercing a List of Maps to a single Map. A condensed example is:
>
>    class Foo {
>         def foo(Map obj) {
>             println(obj)
>         }
>     }
>     z = [
>         [ a: 1, b:2]
>     ]
>     f = new Foo()
>     f.foo(z)
>
> In here, even though the foo() method requires a Map, the call does not throw a type mismatch exception. Instead, the foo() method receives the Map object that is the first entry of the list as its argument. Consequently, it prints:
>
> [a:1, b:2]
>
> If instead, it is passed a list containing two Maps, eg: z = [ [ a: 1, b:2], [c:1, d:2] ], then it does throw a type conversion error. Also notable is that it will always throw the type conversion error if you attempt to coerce it outside the context of a function call, for example, using z.asType(Map).
>
> So it seems that under very specific circumstances that is both code context and data dependent, Groovy will perform a different type of type conversion to what it would do otherwise.
>
> Can anyone explain why it does this and what the rationale is?
>
> Cheers,
>
> Simon
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.