How can I know that I can call a Perl 6 method that with a particular signature? - signature

In Perl 6, a multi-dispatch language, you can find out if there is a method that matches a name. If there is, you get a list of Method objects that match that name:
class ParentClass {
multi method foo (Str $s) { ... }
}
class ChildClass is ParentClass {
multi method foo (Int $n) { ... }
multi method foo (Rat $r) { ... }
}
my $object = ChildClass.new;
for $object.can( 'foo' )
.flatmap( *.candidates )
.unique -> $candidate {
put join "\t",
$candidate.package.^name,
$candidate.name,
$candidate.signature.perl;
};
ParentClass foo :(ParentClass $: Str $s, *%_)
ChildClass foo :(ChildClass $: Int $n, *%_)
ChildClass foo :(ChildClass $: Rat $r, *%_)
That's fine, but it's a lot of work. I'd much rather have something simpler, such as:
$object.can( 'foo', $signature );
I can probably do a lot of work to make that possible, but am I missing something that's already there?

As I hit submit on that question I had this idea, which still seems like too much work. The cando method can test a Capture (the inverse of a signature). I can grep those that match:
class ParentClass {
multi method foo (Str $s) { ... }
}
class ChildClass is ParentClass {
multi method foo (Int $n) { ... }
multi method foo (Rat $r) { ... }
}
my $object = ChildClass.new;
# invocant is the first thing for method captures
my $capture = \( ChildClass, Str );
for $object.can( 'foo' )
.flatmap( *.candidates )
.grep( *.cando: $capture )
-> $candidate {
put join "\t",
$candidate.package.^name,
$candidate.name,
$candidate.signature.perl;
};
I'm not sure I like this answer though.

Related

Groovy closure $v

#CompileDynamic
ClassNode buildTemplateClass(ClassNode reference) {
def methodCount = constX(reference.methods.size())
def fieldCount = constX(reference.fields.size())
return new MacroClass() {
class Statistics {
java.lang.Integer getMethodCount() {
return $v { methodCount }
}
java.lang.Integer getFieldCount() {
return $v { fieldCount }
}
}
}
}
I am not able to get my head around this construct $v { fieldCount }. What does it mean and why is this needed here ? For a full reference of what the code is doing refer here.
In case it is not clear what the constX method does refer here.
As it's written in your doc, $v used inside a macro for substituting an expression
In order to substitute any expression inside the macro we need to use the $v method. $v receives a closure as an argument, and the closure is only allowed to substitute expressions, meaning classes inheriting org.codehaus.groovy.ast.expr.Expression.

bar.with{ ... this.#foo = ... }: groovy.lang.MissingMethodException: No signature of method: MyClass.setFoo() is applicable for argument types

(using Groovy 2.4.11)
The following pseudo-modified code:
enum EnumClass { a, b }
class Some {
Foo foo
Some() {
EnumClass.with{ this.#foo = new Foo( a ) }
}
Some setFoo( String _foo ) { ... }
}
is called like new Some() and brings up the following runtime exception:
groovy.lang.MissingMethodException: No signature of method: MyClass.setFoo() is applicable for argument types: (Foo) values: [Foo$12345] ...`
It looks as if the compiler thinks there would be some this.foo = ... instead of this.#foo = .... :-(
(This should not happen as I understand it and seems to be some bug)
Workaround: writing it like this (outside the with-closure) works ...
enum EnumClass { a, b }
class Some {
Foo foo
Some() {
//EnumClass.with{ this.#foo = new Foo( a ) } // throws exception
this.#foo = new Foo( EnumClass.a ) // works
}
Some setFoo( String _foo ) { ... }
}

Pass method as parameter in Groovy

Is there a way to pass a method as a parameter in Groovy without wrapping it in a closure? It seems to work with functions, but not methods. For instance, given the following:
def foo(Closure c) {
c(arg1: "baz", arg2:"qux")
}
def bar(Map args) {
println('arg1: ' + args['arg1'])
println('arg2: ' + args['arg2'])
}
This works:
foo(bar)
But if bar is a method in a class:
class Quux {
def foo(Closure c) {
c(arg1: "baz", arg2:"qux")
}
def bar(Map args) {
println('arg1: ' + args['arg1'])
println('arg2: ' + args['arg2'])
}
def quuux() {
foo(bar)
}
}
new Quux().quuux()
It fails with No such property: bar for class: Quux.
If I change the method to wrap bar in a closure, it works, but seems unnecessarily verbose:
def quuux() {
foo({ args -> bar(args) })
}
Is there a cleaner way?
.& operator to the rescue!
class Quux {
def foo(Closure c) {
c(arg1: "baz", arg2:"qux")
}
def bar(Map args) {
println('arg1: ' + args['arg1'])
println('arg2: ' + args['arg2'])
}
def quuux() {
foo(this.&bar)
}
}
new Quux().quuux()
// arg1: baz
// arg2: qux
In general, obj.&method will return a bound method, i.e. a closure that calls method on obj.
In addition to the method pointer operator (.&), for Groovy version 3.0.0 and above there's the equivalent, compatible, well known Java 8+ method reference operator (::).
def foo(Closure c) {
c(func: "foo")
}
def bar(Map args = [:]) {
println "$args.func bar"
}
println foo(this::bar)
Output:
foo bar
The method reference operator, as stated in Groovy's documentation:
[…] overlaps somewhat with the functionality provided by Groovy’s
method pointer operator. Indeed, for dynamic Groovy, the method
reference operator is just an alias for the method pointer operator.
For static Groovy, the operator results in bytecode similar to the
bytecode that Java would produce for the same context.

Coercion befuddlement in Groovy

Why does the following
class Test {
#Test
void go() {
def foo1 = new MockFoo1() as Foo
def foo2 = new MockFoo2() as Foo
}
interface Foo {}
class MockFoo1 {}
class MockFoo2 {}
}
Result in a java.lang.IllegalArgumentException: argument type mismatch on the foo2 coercion?
This only happens if I coerce 2 objects of 2 different types to the same interface during a single path of execution. The groovy approved way of using closures or maps to achieve this kind of duck typing works fine.
Any light shed appreciated.
It's a bug with the ProxyGenerator adapterCache. As a workaround, you can also use some Groovy trickery to make this work:
interface Foo {
static a = {
[MockFoo1, MockFoo2].each {
it.metaClass.asType = { Class klazz ->
try {
DefaultGroovyMethods.asType(delegate, klazz)
} catch (e) {
def cache = ProxyGenerator.INSTANCE.#adapterCache.#cache
cache.each { k, v ->
cache.remove(k)
}
DefaultGroovyMethods.asType(delegate, klazz)
}
}
}
}()
}
class MockFoo1 {}
class MockFoo2 {}
def a = new MockFoo1() as Foo
def b = new MockFoo2() as Foo
assert a instanceof Foo
assert b instanceof Foo
Hope this helps!

How to select specific field using Groovy Closure

Given:
class FruitBasket {
int apples = 0
int oranges = 0
}
I need to pick out apples from each FruitBasket. The work need to be done in processFruit:
def processFruit(list, picker) {
list.each {
println "processing " + picker(it)
}
}
def processAll() {
List fruitList = [
new FruitBasket("apples": 2, "oranges": 4),
new FruitBasket("apples": 3, "oranges": 5)
]
processFruit(fruitList, applePicker)
}
def applePicker(FruitBasket f) {
return f.getApples()
}
but it is complaining # runtime that
No such property: applePicker for class: FooTest
possibly a problem with the closures FruitBasket arg...
In that code, applePicker is a method, not a closure.
You can either use a method handle to pass the method as a parameter like so:
processFruit(fruitList, this.&applePicker)
Or change it to an actual closure:
def applePicker = { FruitBasket f -> return f.getApples()    }
You are passing applePicker to processFruit, but it is a method. You can only pass closures this way. Redefine applePicker as a closure like so:
applePicker = { FruitBasket f ->
return f.getApples()
}
Or convert the method to a closure when processFruit is called:
processFruit(fruitList, this.&applePicker)

Resources