Simplify the invocation of a common method
As Curt Tilmes already pointed out, you could make your Foo
object act as an Associative
(or Hash
):
class Foo {
method some-method(Str $name) { ... }
method AT-KEY(Str $name) { self.some-method($name) }
}
my $foo = Foo.new;
say $foo<peter>; # same as $foo.some-method("peter")
Of course, the AT-KEY
method can be a multi, so you could play all sorts of tricks with that as well.
class Foo {
method some-method(Str $name) { "$name is ok" }
multi method AT-KEY("peter") { "peter is special" }
multi method AT-KEY(Str $name) { self.some-method($name) }
}
my $foo = Foo.new;
say $foo<peter>; # "peter is special"
say $foo<joe>; # "joe is ok"
There is a way that you can use FALLBACK
for more than one operation, provided they are different in some way.
By checking some property of the object:
class Foo { # this could be set as part of `new`/`BUILD` has %!special = ( "peter" => 42 ); multi method FALLBACK ( $name where (%!special{$name}:exists) ) { %!special{$name} } multi method FALLBACK ( $other ) { $other.tc } } with Foo.new { say .paul; # Paul say .peter; # 42 }
This has the potential problem of action-at-a-distance.
With different number or types of arguments:
class Bar { multi method FALLBACK ( Str:D $name ) { $name.tc } multi method FALLBACK ( Str:D $name, Real:D $number ) { $name.tc, 1 / $number } multi method FALLBACK ( Str:D $name, Str:D $other ) { $name.tc, $other.uc } } with Bar.new { say .paul; # Paul say .peter(42); # Peter, 0.02381 say .peter('Paul'); # Peter, PAUL }
You can use .[…]
for an Int argument.
class Baz {
method AT-POS ( $arg ) { say "Baz[$arg]" }
}
Baz.new[42,32]; # Baz[42]
# Baz[32]
The built-in postcircumfix:« [ ] »
coerces the arguments to Int, but you could add a new one into the mix.
(There are a bunch of caveats with doing this.)
multi sub postcircumfix:<[ ]> ( Baz:D $b, $a ) is export {
# $b.AT-POS( $a )
$b.some-method( $a )
}
You can use .<…>
for space separated Strs or .{…}
for arbitrary values.
class Other {
multi method AT-KEY ( Str:D $name ){
$name.tc
}
multi method AT-KEY ( Real:D $number ){
1 / $number
}
}
with Other.new {
say $_<peter>; # Peter
say $_.<paul>; # Paul
say .<peter paul>; # Peter Paul
# note that AT-Key got called twice
say $_{42,'peter'}; # 0.02381, Peter
# note that AT-Key got called twice
}
You can make it so that your object is callable.
class Fubar {
multi method CALL-ME ( Str:D $name ){
$name.tc
}
multi method CALL-ME ( Real:D $number ){
1 / $number
}
multi method CALL-ME ( +@args ){
@args.map: {self.CALL-ME($_)}
}
}
with Fubar.new {
say $_('peter'); # Peter
say $_(42); # 0.02381
# this calls the +@args one
say $_('paul',32); # Paul, 0.03125
}
You should really think about your API before doing any of these.