Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplify the invocation of a common method

I have a class like this:

class Foo {
    method some-method(Str $name) { ... }
}

Simple usage:

my $foo = Foo.new;

$foo.some-method("peter");

Since the "some-method" will be called quite frequently, I'd like to do something to allow users to use it like below:

$foo.peter;

I know FALLBACK will do the job, but it has been used for another method. I tried to define an infix operator:

sub infix:<%>(Foo $foo, $name) {
    $foo.some-method($name);
}

The code below works, but the double quote is annoying.

$foo % "peter";

So is there any way to avoid the quote mark? Or any way to simplify the invocation?

like image 838
lovetomato Avatar asked Jan 31 '19 02:01

lovetomato


People also ask

What is the meaning of Remote Method Invocation?

RMI (Remote Method Invocation) is a way that a programmer, using the Java programming language and development environment, can write object-oriented programming in which objects on different computers can interact in a distributed network.

Which method is used for Remote Method Invocation?

RMI stands for Remote Method Invocation. It is a mechanism that allows an object residing in one system (JVM) to access/invoke an object running on another JVM. RMI is used to build distributed applications; it provides remote communication between Java programs.

What is RMI and how it works?

RMI treats a remote object differently from a non-remote object when the object is passed from one Java virtual machine to another Java virtual machine. Rather than making a copy of the implementation object in the receiving Java virtual machine, RMI passes a remote stub for a remote object.

What is the basic principle of RMI architecture?

The RMI architecture is based on a very important principle which states that the definition of the behavior and the implementation of that behavior, are separate concepts. RMI allows the code that defines the behavior and the code that implements the behavior to remain separate and to run on separate JVMs.


2 Answers

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"
like image 65
Elizabeth Mattijsen Avatar answered Oct 10 '22 03:10

Elizabeth Mattijsen


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.

like image 6
Brad Gilbert Avatar answered Oct 10 '22 04:10

Brad Gilbert