0

This code works as expected (output is j.doe):

class Sample {

    Closure formatFirstName
    Closure formatLastName

    void doStuff (String fname, String lname, Closure callback) {
        formatFirstName(fname) { String fnameError, String formattedFname ->
            formatLastName(lname) { String lnameError, String formattedLname ->
                String errors = "${fnameError ? "${fnameError}, " : ''}${lnameError ?: ''}"
                callback(errors, formattedFname, formattedLname)
            }
        }    
    }

}

Closure ffn = { String fname, Closure callback ->
    String firstInitial = fname?.substring(0,1)

    if (!firstInitial)
        callback('invalid first name', null)
    else
        callback(null, firstInitial.toLowerCase())
}

Closure fln = { String lname, Closure callback ->
    String lastPrefix = lname?.size() > 2 ? lname.substring(0,3) : null

    if (!lastPrefix)
        callback('invalid last name', null)
    else
        callback(null, lastPrefix.toLowerCase())
}

Sample sample = new Sample(formatFirstName: ffn, formatLastName: fln)

sample.doStuff('John', 'Doe') { String errors, String formattedFname, String formattedLname ->
    if (errors)
        println errors
    else 
        println "${formattedFname}.${formattedLname}"
}

Adding the @CompileStatic annotation causes an exception:

groovy.lang.MissingMethodException: No signature of method: Sample$_doStuff_closure1.doCall() is applicable for argument types: (java.lang.String, Sample$_doStuff_closure1_closure2) values: [Doe, Sample$_doStuff_closure1_closure2@bb70963]
Possible solutions: doCall(java.lang.String, java.lang.String), findAll(), findAll()
    at Sample$_doStuff_closure1.doCall(ConsoleScript226:11)
    at ConsoleScript226$_run_closure1.doCall(ConsoleScript226:26)
    at Sample.doStuff(ConsoleScript226:10)
    at Sample$doStuff.call(Unknown Source)
    at ConsoleScript226.run(ConsoleScript226:40)

(Code with @CompileStatic annotation)

import groovy.transform.CompileStatic

@CompileStatic
class Sample {

    Closure formatFirstName
    Closure formatLastName

    void doStuff (String fname, String lname, Closure callback) {
        formatFirstName(fname) { String fnameError, String formattedFname ->
            formatLastName(lname) { String lnameError, String formattedLname ->
                String errors = "${fnameError ? "${fnameError}, " : ''}${lnameError ?: ''}"
                callback(errors, formattedFname, formattedLname)
            }
        }    
    }

}

Closure ffn = { String fname, Closure callback ->
    String firstInitial = fname?.substring(0,1)

    if (!firstInitial)
        callback('invalid first name', null)
    else
        callback(null, firstInitial.toLowerCase())
}

Closure fln = { String lname, Closure callback ->
    String lastPrefix = lname?.size() > 2 ? lname.substring(0,3) : null

    if (!lastPrefix)
        callback('invalid last name', null)
    else
        callback(null, lastPrefix.toLowerCase())
}

Sample sample = new Sample(formatFirstName: ffn, formatLastName: fln)

sample.doStuff('John', 'Doe') { String errors, String formattedFname, String formattedLname ->
    if (errors)
        println errors
    else 
        println "${formattedFname}.${formattedLname}"
}

Using explicit invocation (i.e. closure.call) this now works again:

import groovy.transform.CompileStatic

@CompileStatic
class Sample {

    Closure formatFirstName
    Closure formatLastName

    void doStuff (String fname, String lname, Closure callback) {
        formatFirstName.call(fname) { String fnameError, String formattedFname ->
            formatLastName.call(lname) { String lnameError, String formattedLname ->
                String errors = "${fnameError ? "${fnameError}, " : ''}${lnameError ?: ''}"
                callback(errors, formattedFname, formattedLname)
            }
        }    
    }

}

Closure ffn = { String fname, Closure callback ->
    String firstInitial = fname?.substring(0,1)

    if (!firstInitial)
        callback('invalid first name', null)
    else
        callback(null, firstInitial.toLowerCase())
}

Closure fln = { String lname, Closure callback ->
    String lastPrefix = lname?.size() > 2 ? lname.substring(0,3) : null

    if (!lastPrefix)
        callback('invalid last name', null)
    else
        callback(null, lastPrefix.toLowerCase())
}

Sample sample = new Sample(formatFirstName: ffn, formatLastName: fln)

sample.doStuff('John', 'Doe') { String errors, String formattedFname, String formattedLname ->
    if (errors)
        println errors
    else 
        println "${formattedFname}.${formattedLname}"
}

So my question is: why do I have to use explicit closure invocation for member closures when using compile static? Is it simply because Java doesn't have implicit invocation? If this was the case wouldn't we have to explicitly invoke the callback closure being passed to the doStuff method as well?

jckdnk111
  • 2,280
  • 5
  • 33
  • 43

0 Answers0