Perl6-Pugs

 view release on metacpan or  search on metacpan

docs/articles/tpr.pod  view on Meta::CPAN


  sub my_func {
      my($foo, $bar, $baz) = @_;
      # ...

Beginners (and insufficiently caffeinated late-night hackers) can easily
make one of the following disastrous mistakes:

      my ($foo, $bar, $baz);         # oops, forgot " = @_"
      my ($foo, $bar, $baz) = shift; # oops, used shift() instead of "@_"
      my $single_arg = @_;           # oops, will usually be 1

The Perl 6 compiler has syntax to save you from all this. Here's how
you spell out the car example:

  sub make_car ($model, $color? = "black", Int $doors? = 4) { ... }

This single line does more than the four Perl 5 lines did. First, it
specifies that the function receives three parameters, one of which is
mandatory. The C<?> in C<$black?> and C<$doors?> means they are optional;
in both cases default values are supplied.  You don't have to give one:
the default default is undef.  On the other hand, if you do give a default,
the C<?> itself becomes optional.

The C<Int> mark on the last parameter means calling the function with a
non-integer will raise an error. As you can see, this is an optional feature:
you don't have to declare types everywhere.

How is this C<make_car> used? These are obvious:

[[ (EM) Maybe source code examples should adhere to PBP ?? ]]

  make_car("VW Beetle", "green", 2);
  make_car("Ford Model T");              # black, 4-doored
  make_car();                            # error: model not supplied
  make_car("Fiat", "Red", 3, "sunroof"); # error: too many args

But there's more. Ever used a library that has functions with many
parameters? It can get kind of hard to keep track of their order. This
is why many complex libraries use hashes for named args, but coding up
validation for that is once again tedious. Perl 6 lets I<any> function
be called with named args automatically:

  make_car(doors => 2, model => "VW Beetle")

  $widget.add_accelerator(signal => "clicked",
                          group  => $accel_group,
                          key    => GDK_n,
                          mods   => GDK_MOD1_MASK,
                          flags  => GTK_ACCEL_VISIBLE);

You've probably seen Perl 5 functions that go out of their way to accept
either positional args, or a hash or hashref with named args. There's no
need to do that any more. If you have a function you'll be calling many
times with a changing set of arguments, you can keep them in a hash and
use the I<comma reduce> operator C<[,]> to flatten it:

  sub make_many_cars ($howmany) {
      my @cars;
      for 1 .. $howmany {         # the parens can be omitted here in Perl 6
          my %car_prefs = get_user_prefs();
          push @cars, make_car([,]%car_prefs);
      }
      return @cars;
  }

=item Lightweight closure syntax

Every block acts like a closure in Perl 6. The syntax is at once simplified
-- you don't need to say C<sub> to declare anonymous pieces of code -- and
extended to include formal parameters.

  my $beeper = { say "beep!" };   # $beeper is a coderef. No need for "sub".
  $beeper();                      # says "beep!". No perl5ish "->" here.

  my $square = -> $x { $x * $x }; # use "->" to introduce args
  my @squares = map $square, 1 .. 10;

Control structures typically take closures, so you can, as in the example
below, iterate with C<for> with more than one element every time. C<zip>
is a function that takes a few lists and returns interleaves their
elements:

  for zip @Xs, @Ys -> $x, $y {
      push @differences, $x - $y;
  }

Of course, this kind of thing is usually better expressed with map,
which can also take more than one element at a time.

  # Infix "Â¥" means the same thing as "zip"; this is a visual analogy.
  # See the sidebar on Unicode operators for details.
  my @differences = map -> $x, $y { $x - $y }, @Xs ¥ @Ys;

There's even a feature for the extremely lazy: formal parameters with
no predeclaration. Variables mentioned in a closure that have the C<^>
secondary sigil (called "twigil" in Perl 6 speak) are all inferred as
parameters to the block.

  my @differences = map { $^x - $^y }, @Xs ¥ @Ys;

How does this compare with Perl 5? If C<@Xs> and C<@Ys> can be assumed to be
the same length, then this isn't too bad, though the explicit subscripting
does make it less elegant:

  my @differences = map { $Xs[$_] - $Ys[$_] } 0 .. $#Xs;

If we want to allow for lists of different length, though, we need a
solution that's much more involved:

  sub map2 (&@) {
      my ($code, @list) = @_;
      my @output;
      
      while (@list) {
          my($x, $y) = splice @list, 0, 2;
          push @output, $code->($x, $y);
      }
      
      return @output;
  }
  



( run in 0.665 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )