I created https://issues.apache.org/jira/browse/GROOVY-11621 for this.
On 2025-04-14, 13:09, "Per Nyfelt" <per.nyf...@nordnet.se <mailto:per.nyf...@nordnet.se>> wrote: Oh, and property assignment with null for maps works with @CompileStatic e.g. def map = [a: 'foo', b: 'bar', c: 'baz'] map.b = null assert map['b'] == null I would assume we want bracket notation and property notation to be functionally equivalent right? On 2025-04-14, 11:37, "Per Nyfelt" <per.nyf...@nordnet.se <mailto:per.nyf...@nordnet.se> <mailto:per.nyf...@nordnet.se <mailto:per.nyf...@nordnet.se>>> wrote: Thank you for the workaround! For a slightly more complex case of overriding putAt I found that I can do like this if I also provide a getAt which might be of interest for others trying to do similar things: class TwoD { List<List<?>> rows = [] TwoD(List rows) { this.rows = rows } def putAt(List list, Object value) { println "putAt: $list : $value" Integer rowIdx = list[0] as Integer Integer colIdx = list[1] as Integer // Must add parenthesis for assignment to work (rows[rowIdx][colIdx]) = value } // This is never called in putAt but when compiling static, it must exists for it to compile, otherwise we get the following compilation error: // [Static type checking] - Cannot find matching method PutAtTest$TwoD#getAt(java.util.List<E>). Please check if the declared type is correct and if the method exists. def getAt(List where) { println "getAt: $where" Integer rowIdx = where[0] as Integer Integer colIdx = where[1] as Integer return rows[rowIdx][colIdx] } String toString() { StringBuilder sb = new StringBuilder() rows.each { List row -> row.each {sb.append(it).append(', ')} sb.append('\n') } sb } } @CompileStatic @Test void testOverride() { def d = new TwoD([[1,2,3], ['a', 'b', 'c']]) println d d[0,1] = null println d assert d[0,1] == null assert d[1,2] == 'c' } Which will output 1, 2, 3, a, b, c, putAt: [0, 1] : null 1, null, 3, a, b, c, getAt: [0, 1] getAt: [1, 2] Regards, Per On 2025-04-14, 10:57, "Paul King" <pa...@asert.com.au <mailto:pa...@asert.com.au> <mailto:pa...@asert.com.au <mailto:pa...@asert.com.au>> <mailto:pa...@asert.com.au <mailto:pa...@asert.com.au> <mailto:pa...@asert.com.au <mailto:pa...@asert.com.au>>>> wrote: A workaround is to cast, e.g. list[1] = (String) null I don't see why that is needed for null. On GROOVY_4_0_X, the map also needs the cast. On master, only the list needs the cast. I can't explain that either (yet). Paul. On Mon, Apr 14, 2025 at 5:37 PM Per Nyfelt <per.nyf...@nordnet.se <mailto:per.nyf...@nordnet.se> <mailto:per.nyf...@nordnet.se <mailto:per.nyf...@nordnet.se>> <mailto:per.nyf...@nordnet.se <mailto:per.nyf...@nordnet.se> <mailto:per.nyf...@nordnet.se <mailto:per.nyf...@nordnet.se>>>> wrote: > > Hi, > > I was recently experimenting with @CompileStatic for performance improvements > and noticed that when using the short notation of putAt to assign a null > value I get the following error > > [Static type checking] - Cannot call <T> > org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.List<T>, > int, T) with arguments [java.util.List<java.lang.String>, int, > java.lang.Object] > > > > Here is an example: > > > > import groovy.transform.CompileStatic > import org.junit.jupiter.api.Test > > @CompileStatic > class PutAtTest { > > @Test > void testList() { > // These all work > def list = ['a', 'b', 'c'] > list[0] = 'aa' > assert list[0] == 'aa' > > list.set(2, null) > assert list[2] == null > > list.putAt(0, null) > assert list[0] == null > > // This Fails > list[1] = null > assert list[1] == null : "Short notation not working when assigning null" > } > > @Test > void testMap() { > // These all work > def map = [a: 'foo', b: 'bar', c: 'baz'] > map['a'] = 'aa' > assert map['a'] == 'aa' > > map.put('c', null) > assert map['c'] == null > > map.putAt('a', null) > assert map['a'] == null > > // This Fails > map['b'] = null > assert map['b'] == null : "Short notation not working when assigning null" > } > } > > > > Is this expected behavior or a bug? Does anyone know of workaround? > > > > Regards, > > Per