Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl 6: how to check `new` for invalid arguments?

What is the simplest way to check if invalid arguments are passed to the constructor method new?

use v6;
unit class Abc;

has Int $.a;

my $new = Abc.new( :b(4) );
like image 751
sid_com Avatar asked Nov 29 '22 08:11

sid_com


2 Answers

The ClassX::StrictConstructor module should help. Install it with zef install ClassX::StrictConstructor and use it like so:

use ClassX::StrictConstructor;

class Stricter does ClassX::StrictConstructor {
    has $.thing;
}

throws-like { Stricter.new(thing => 1, bad => 99) }, X::UnknownAttribute;
like image 135
timotimo Avatar answered Dec 04 '22 12:12

timotimo


TLDR; If you are just worried about someone accidently mis-typing :a(4) as :b(4), it might be better to just mark $.a as required.

class ABC {
  has Int $.a is required;
}

ABC.new( :b(4) ); # error
# The attribute '$!a' is required, but you did not provide a value for it.

A quick hack would be to add a submethod TWEAK that makes sure any named values that you don't specify aren't there. It doesn't interfere with the normal workings of new and BUILD, so the normal type checks work without having to re-implement them.

class ABC {
  has Int $.a;

  submethod TWEAK (

    :a($), # capture :a so the next won't capture it

    *%     # capture remaining named
      ()   # make sure it is empty

  ) {}
}

A slightly more involved (but still hacky) way that should continue to work for subclasses, and that doesn't need to be updated with the addition of more attributes:

class ABC {
  has Int $.a;

  submethod TWEAK (

    *%_    # capture all named

  ) {

    # get the attributes that are known about
    # (should remove any private attributes from this list)
    my \accepted = say self.^attributes».name».subst(/.'!'/,'');

    # ignore any that we know about
    %_{|accepted}:delete;

    # fail if there are any left
    fail "invalid attributes %_.keys.List()" if %_

  }
}
like image 43
Brad Gilbert Avatar answered Dec 04 '22 13:12

Brad Gilbert