Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Perl6 signatures, types and multicall

167 views

Published on

Slides from my talk at TPC Glasgow 2018.

Published in: Technology
  • Be the first to comment

Perl6 signatures, types and multicall

  1. 1. Perl6 Signatures, Types and Multicall
  2. 2. About Me ● Simon Proctor ● Scimon in many places ● Senior Dev at Zoopla (we’re hiring) ● simon.proctor@gmail.com
  3. 3. Part 1 : Signatures
  4. 4. No Signature sub foo { @_.say; } ● Should be familiar to Perl devs ● All arguments put into lexical @_ array ● @_ array only populated with arguments in this case only ● I would not encourage using this
  5. 5. No Signature (Note) sub foo { @_.say; } foo( A => 1 ); *ERRORS* foo( ( A => 1 ) ); [A => 1] When calling a sub (or method) a Pair using either A => 1 or :A(1) syntax will be treated as a named argument. In Perl6 => is not just a fat comma.
  6. 6. Empty Signature sub foo() { say “I take orders from no one”; } ● Specifically states this subroutine takes no arguments. ● Will error (generally at compile time) if called with arguments. ● Not just constants ○ Variables in outer scope available ○ State variables for generators
  7. 7. Empty Signature (methods) method foo() { say self.bar; } ● Object methods with an empty signature also error if called with arguments. ● Have access to self (and the $ alias) though.
  8. 8. Positional Arguments sub foo($a,$b,$c) { say “$a : $b : $c”; } ● Maps arguments to lexical variables based on position ● Errors unless the exact number of arguments are passed
  9. 9. Positional Arguments (methods) method foo($foo: $a) { say “{$foo.attr} : $a”; } ● Optional initial argument separated with : defines another reference for self that can be used in the method ● Useful with where clauses and multi methods ● Also can be used to specify class methods
  10. 10. Positional Arguments : Defaults and optional sub foo($a, $b?, $c=5, $d=$c*2) { say “$a : $b : $c : $d”; } foo(1,2) 1 : 2 : 5 : 10 ● Any positions not filled will get their defaults ● Defaults are calculated for each call ● Defaults can be based on values earlier in the argument list. ● Mark an argument as optional with ? after the name.
  11. 11. Positional Arguments : Sigils sub foo(@a) { say @a; } foo(1,2) Errors foo( [1,2] ) [1,2] @ and % sigils are type signifiers for Positional and Associative roles.
  12. 12. Positional Arguments : Flattening Slurpy sub foo(*@a) { say @a; } foo(1,2) [1,2] foo( 1,[2,3] ) [1,2,3] Single * will slurp and flatten all remaining positional arguments. foo(1,(2,3)) [1,2,3] foo(1,{2 => 3}) [1,{2=>3}]
  13. 13. Positional Arguments : Non Flattening Slurpy sub foo(**@a) { say @a; } foo(1,2) [1,2] foo( 1,[2,3] ) [1,[2,3]] Double * will slurp all remaining positional arguments but not flatten lists or hashes. foo(1,(1,2)) [1,(1,2)] foo(1,{2 => 3}) [1,{2=>3}]
  14. 14. Positional Arguments : Single Rule Slurpy sub foo(+@a) { say @a; } foo(1) [1] foo( [2,3] ) [2,3] A + slurpy will flatten a single iterable object into the arguments array. Otherwise it works like **. foo(1,[2,3]) [1,[2,3]] foo(1,{2 => 3}) [1,{2=>3}]
  15. 15. Positional Arguments : Combinations sub foo($a,*@b) { say “$a : {@b.perl}”; } foo(1) 1 : [] foo( 1,[2,3] ) 1 : [2,3] ● You can combine positional and slurpy argument. ● The slurpy has to come last. ● You can only have one slurpy argument. foo(1,2,3) 1 : [2,3] foo(1,2,3,{a => 5}) 1:[2,3,:a(5)]
  16. 16. Named Arguments sub foo(:$a,:$b!) { say “$a & $b”; } foo(a=>“b”,b=>“c”) b & c foo(:a<bar>) Required named parameter 'b' not passed ● Define named arguments with a ‘:’ in front of the lexical variable. ● Named arguments are not required. ● Append the name with ! to make it required. foo(:b<bar>) & bar Use of uninitialized value $a of type Any in string context.
  17. 17. Alternate Named Arguments sub foo(:bar(:$b)) { say $b; } foo(b=>“a”) a foo(:bar<bar>) bar ● Alternate argument names can be nested multiple times : ○ :$val ○ :v($val) ■ :v() in call ○ :v(:$val) ■ :v() or :val() ○ :valid(:v(:$val)) ● All referenced as $val in the sub ● Useful for sub MAIN
  18. 18. Combining Named and Positional Arguments sub foo($a,:$b) { say $a if $b; } foo(“Hi”,:b) Hi foo(“Crickets”) ● Positional arguments have to be defined before named. ● You can combine a slurpy positional and named arguments.
  19. 19. Named Arguments : Slurpy Hash sub foo(*%a) { say %a; } foo(a=>b) {a => b} Using * on a hash will take all the named argument pairs and put them in the given hash. foo( b => [5,6], :a(b) ) {b => [5,6], a => b} foo( :a, :!b ) { a => True, b => False }
  20. 20. Constraints (Part 1) sub foo($a where * > 10) { say $a; } foo(5); Errors The where clause needs to be true or the system will throw an Exception. You can CATCH this normally. Where clauses can be chained: where * > 10 where *.is-prime foo(11); 11
  21. 21. Constraints (Part 2) sub foo($a where * > 10 where .is-prime) { say $a; } foo(5); Errors foo(12); Errors Where clauses can be chained foo(13); 13
  22. 22. Sub Signatures sub foo(@a ($b, $c)){ say “$b : $c”; } foo([1,2]); 1 : 2 foo(1,2); Errors foo([1,2,3]); Errors Positional and Associative objects can have sub signatures assigned to them. Sub signatures can be nested. (But you might want to think if there’s an easier plan)
  23. 23. Captures my $c = (1,2,3); sub foo(*@in) { [+] @in } say foo(|$c); 6 Signatures and Captures are both first class objects. You can introspect signatures to get information about them. Captures can be stored and reused and examined as well. For further information I’d advise looking at the docs: https://docs.perl6.org/type/Signature
  24. 24. Part 2 : Types
  25. 25. Simple Types sub foo(Int $a) { say $a; } foo(5) 5 foo(“bob”) Errors Depending on how you are calling your function you may get a run time or a compile time error. Types can be built in or newly created Classes (or Roles). Types can be applied to named or positional parameters
  26. 26. Type Coercion sub foo(Int() $a) { say $a; } If you want allow anything that can be cast to the given type. Note this will only ever give runtime errors. foo(5.5) 5 foo(5e5) 50000 foo(5) 5 foo(“bob”) Errors foo(“5”) 5
  27. 27. Advanced Type Coercion sub foo(Int(Numeric) $a) { say $a; } Type() == Type(Any) for coercion. You can give a more specific type if required though. foo(5.5) 5 foo(5e5) 50000 foo(5) 5 foo(“bob”) Errors foo(“5”) Errors
  28. 28. Return Type Constraints sub foo(Int $a --> Int) { return $a * 2; } Return types can have constraints added. my Int $b = foo(5); say $b; 10 my Rat $e = foo(5); Errors say foo(5); 10 $a = foo(5); say $a 10
  29. 29. Constraints (Part 3) sub foo(Int $a where * > 5) { say $a; } Type constraints can be combined with where clauses. foo(6) 6 foo(6.5) Errors foo(5) Errors foo(5.5) Errors
  30. 30. Subsets (Named Type Constraints) subset IntOver5 of Int where * > 5; sub foo(IntOver5 $a) { say $a; } Subset lets you name a type constraint You can add one or more where clause as well. foo(6) 6 foo(6.5) Errors foo(5) Errors foo(5.5) Errors
  31. 31. Subsets (Multiple Types) subset IntOrRat of Numeric where { $_ ~~ Int|Rat}; sub foo(IntOrRat $a) { say $a; } You can only constrain a variable to one type. But you can use subsets to allow multiple input types. Note you can’t use a wherever block due to precedence for Junctions.foo(6e5) Errors foo(6+i) Errors foo(5) 5 foo(5.5) 5.5
  32. 32. Type Captures sub foo(::T $a, T $b ) { say “{$a} and {$b} are type {T.perl}” } Type captures allow you to capture the type of the input and access it in the containing block. You can also reference it elsewhere in the signature and add constraints. foo(5,6) 5 and 6 are type Int foo(5.5,6.7) 5.5 and 6.7 are type Rat foo(“a”,”b”) a and b are type Str foo(“5”,5) Errors
  33. 33. Part 3 : Multi Call
  34. 34. Basic Multi Call multi sub foo(Int $a) { $a; } multi sub foo(Rat $a) { round($a); } If you define a subroutine or method as multi then the system will pick the signature that best matches the input variables. Return constraints are NOT included in the matching. say foo(“a”); Errors say foo(“1”); Errors say foo(5); 5 say foo(4.5); 5;
  35. 35. Constants multi sub fib(0) {1} multi sub fib(1) {1} multi sub fib(UInt $f) { fib($f-1) + fib($f-2) } Your type constraints can include constants. Note that a recursive subroutine like this will not be very performant. sub fib($x) { state @f = 1,1,*+*...*; @f[$x]; } say fib(1); 1 say fib(20); 10946
  36. 36. Prototypes proto foo(Int $a,|) {*} multi foo($a, Int $b) { $a+$b} multi foo($a, Rat $b) { $a+$b.denominator } If your subs or methods share inputs you can declare their constraints in the proto. * is replaced with the code for the final multi | is the anonymous capture representing the other variables. Note lone multi implies sub say foo(1,1); 2 say foo(1,1.5); 3
  37. 37. Only only sub foo($a) { $a; } … multi sub foo($a,$b) { $a ~~ $b } Declaring a sub or method as only will raise an Exception if the same name is used within the same namespace. It’s not required but it’s good defensive programing. Errors
  38. 38. Use Case : MAIN use Library; my %*SUB-MAIN-OPTS = :named-anywhere; multi MAIN( “action” ) { Library::action(); } multi MAIN( “action”, Bool :$help where ?* ) { Library::document_action(); } Using a Library gives you bytecode compiled data. MAIN takes command line args and maps them to positional and associative. %*SUB-MAIN-OPTS = :named-anywhere allows inputs types to mingle.
  39. 39. Example : App::Mi6 use v6; use App::Mi6; my %*SUB-MAIN-OPTS = :named-anywhere; my $app = App::Mi6.new; multi MAIN("version") { say $app.^ver; } multi MAIN("new", $module) { $app.cmd("new", $module); } multi MAIN("build") { $app.cmd("build"); } multi MAIN("release", Bool :$keep) { $app.cmd("release", :$keep); } multi MAIN("test", *@file, Bool :v(:$verbose), Int :j(:$jobs)) { $app.cmd("test", @file, :$verbose, :$jobs); } multi MAIN("dist") { $app.cmd("dist"); } multi MAIN("upload") { die "`mi6 upload` is removed, please execute `mi6 release` instead.n"; } multi MAIN("help") { USAGE(); } multi MAIN(:h(:$help)!) { USAGE(); } sub USAGE { require Pod::To::Text; ::("Pod::To::Text").render($=pod).say; exit 1; }
  40. 40. Bonus Slide : Operators sub infix:<£==> ( $gbp, $usd ) { $gbp =~= ( $usd / .7862 ) } say 100 £== 78.62; True sub prefix:<£> ( $gbp ) { “${$gbp * .7862}” } say £100; “$78.62” sub postfix:<!> ( UInt $num ) { [*] (1..$num) } say 5!; 120 sub circumfix:<FOO BAR> ( @a ) { “BAR {@a.reverse.join(‘ ’)} FOO” } say FOO 1..5 BAR;BAR 5 4 3 2 1 FOO sub postcircumfix:<d d> ( $year, $day ) { Date.new( “{$year}-01-01” ) + $day } say 1970d 100 d; 1970-04-11
  41. 41. Bonus Slide : Sub / Method Traits is assoc : Define an operators associativity (left, right, chain, list or non) is tighter, is looser, is equiv : Define an operators precedence is pure : Given a set of arguments will always return the same result. Do not use if you have side effects as this can be inlined. is export : Marks a sub as to be exported from the current namespace (you can specify when) is rw : The return value can be assigned to directly. is DEPRECATED : Flag your sub as deprecated, warnings will be raised if you use it is hidden-from-backtrace : Skip this function when giving a backtrace
  42. 42. Further Reading https://docs.perl6.org/type/Signature https://docs.perl6.org/language/functions https://docs.perl6.org/type/Capture https://www.amazon.co.uk/Think-Perl-Like-Computer-Scientist/dp/1491980559/ https://www.amazon.co.uk/Perl-Deep-Dive-manipulation-concurrency/dp/178728204X/ https://www.amazon.co.uk/Learning-Perl-6-Brian-Foy/dp/149197768X/ (Preorder)
  43. 43. Questions?

×