Day 18: Roles

As the snow falls outside, we grab a glass of mulled wine – or maybe a cup of eggnog – to enjoy as we explore today’s exciting gift – roles!

Traditionally in object oriented programming, classes have taken on two tasks: instance management and re-use. Unfortunately, this can end up pulling classes in two directions: re-use wants them to be small and minimal, but if they’re representing a complex entity then they need to support all of the bits it needs. In Perl 6, classes retain the task of instance management. Re-use falls to roles.

So what does a role look like? Imagine that we are building up a bunch of classes that represent different types of product. Some of them will have various bits of data and functionality in common. For example, we may have a BatteryPower role.

role BatteryPower {
    has $.battery-type;
    has $.batteries-included;
    method find-power-accessories() {
        return ProductSearch::find($.battery-type);
    }
}

At first glance, this looks a lot like a class: it has attributes and methods. However, we can not use a role on its own. Instead, we must compose it into a class, using the does keyword.

class ElectricCar does BatteryPower {
    has $.manufacturer;
    has $.model;
}

Composition takes the attributes and methods – including generated accessors – from the role and copies them into the class. From that point on, it is as if the attributes and methods had been declared in the class itself. Unlike with inheritance, where the parents are looked at during method dispatch, with roles there is no runtime link beyond the class knowing to say “yes” if asked if it does a particular role.

Where things get really interesting is when we start to compose multiple roles into the class. Suppose that we have another role, SocketPower.

role SocketPower {
    has $.adapter-type;
    has $.min-voltage;
    has $.max-voltage; 
    method find-power-accessories() {
        return ProductSearch::find($.adapter-type);
    }
}

Our laptop computer can be plugged in to the socket or battery powered, so we decide to compose in both roles.

class Laptop does BatteryPower does SocketPower {
}

We try to run this and…BOOM! Compile time fail! Unlike with inheritance and mix-ins, role composition puts all of the roles on a level playing field. If both provide a method of the same name – in this case, find-power-accessories – then the conflict will be detected as the class is being formed and you will be asked to resolve it. This can be done by supplying a method in our class that says what should be done.

class Laptop does BatteryPower does SocketPower {
    method find-power-accessories() {
        my $ss = $.adapter-type ~ ' OR ' ~ $.battery-type;
        return ProductSearch::find($ss);
    }
}

This is perhaps the most typical use of roles, but not the only one. Roles can also be taken and mixed in to an object (on a per-object basis, not a per-class basis) using the does and but operators, and if filled only with stub methods will act like interfaces in Java and C#. I won’t talk any more about those in this post, though: instead, I want to show you how roles are also Perl 6’s way of achieving generic programming, or parametric polymorphism.

Roles can also take parameters, which may be types or just values. For example, we may have a role that we apply to products that need to having a delivery cost calculated. However, we want to be able to provide alternative shipping calculation models, so we take a class that can handle the delivery calculation as a parameter to the role.

role DeliveryCalculation[::Calculator] {
    has $.mass;
    has $.dimensions;
    method calculate($destination) {
        my $calc = Calculator.new(
            :$!mass,
            :$!dimensions
        );
        return $calc.delivery-to($destination);
    }
}

Here, the ::Calculator in the square brackets after the role name indicates that we want to capture a type object and associate it with the name Calculator within the body of the role. We can then use that type object to call .new on it. Supposing we had written classes that did shipping calculations, such as ByDimension and ByMass, we could then write:

class Furniture does DeliveryCalculation[ByDimension] {
}
class HeavyWater does DeliveryCalculation[ByMass] {
}

In fact, when you declare a role with parameters, what goes in the square brackets is just a signature, and when you use a role what goes in the square brackets is just an argument list. Therefore you have the full power of Perl 6 signatures at your disposal. On top of that, roles are “multi” by default, so you can declare multiple roles with the same short name, but taking different types or numbers of parameters.

As well as being able to parametrize roles using the square bracket syntax, it is also possible to use the of keyword if each role takes just one parameter. Therefore, with these declarations:

role Cup[::Contents] { }
role Glass[::Contents] { }
class EggNog { }
class MulledWine { }

We may now write the following:

my Cup of EggNog $mug = get_eggnog();
my Glass of MulledWine $glass = get_wine();

You can even stack these up.

role Tray[::ItemType] { }
my Tray of Glass of MulledWine $valuable;

The last of these is just a more readable way of saying Tray[Glass[MulledWine]]. Cheers!

Day 17: Making Snowmen

I started out planning this day to be about complex numbers in Perl 6. But after I thought about it a bit, I decided that the complex number implementation is so straightforward explaining it would make a pretty boring gift. Instead, let’s explore the Mandelbrot set, which will let us do a bit of complex math, look at pretty pictures, and hint at some advanced features of Perl 6, too.

Without further ado, here’s the first version of the script:

use v6;

my $height = @*ARGS[0] // 31;
my $width = $height;
my $max_iterations = 50;

my $upper-right = -2 + (5/4)i;
my $lower-left = 1/2 - (5/4)i;

sub mandel(Complex $c) {
    my $z = 0i;
    for ^$max_iterations {
        $z = $z * $z + $c;
        return 1 if ($z.abs > 2);
    }
    return 0;
}

sub subdivide($low, $high, $count) {
    (^$count).map({ $low + ($_ / ($count - 1)) * ($high - $low) });
}

say "P1";
say "$width $height";

for subdivide($upper-right.re, $lower-left.re, $height) -> $re {
    my @line = subdivide($re + ($upper-right.im)i, $re + 0i, ($width + 1) / 2).map({ mandel($_) });
    my $middle = @line.pop;
    (@line, $middle, @line.reverse).join(' ').say;
}

So, lines 3-5 set up the pixel size of the graphic we will create. @*ARGS is the new name of the command line argument array. The // operator is the new “defined” operator; it returns its first argument if that argument is defined, its second otherwise. In other words, line 3 sets $height to be the first argument on the command line, or 31 if no such argument was set. $width is set equal to $height — the code is set up to generate a square graphic right now, but the variables are set apart for ease of future hacking. $max_iterations sets how many times the core Mandelbrot loop will iterate before it concludes a point is in the set. (Because we’re relying on the symmetry of the Mandelbrot set, $width must be odd.)

Lines 7-8 set the boundaries of our image on the complex plane. Introducing the imaginary component of a number is as simple as giving a number (or numeric expression) followed by i; this creates a number of the Complex type. Complex math works pretty much the way you would expect it to, for example, (as we see here) adding a Complex to an Int or a Rat yields another Complex.

Lines 10-17, then, are the core Mandelbrot function. To quickly explain, a complex number c is in the Mandrelbrot set if the equation z = z * z + c (with initial z of 0) stays bounded as we iterate the equation. This function implements exactly that in Perl 6. We set up a loop to iterate $max_iterations times. It is known that once |z| grows bigger than 2 it will not stay bounded, so we use $z.abs > 2 to check for that condition. If it is true, we leave the loop early, returning 1 from the function to indicate the corresponding pixel should be black. If the loop finishes the number of iterations without exceeding those bounds, we return 0 for the color white.

Lines 19-21 are a simple helper function to return a list of a simple arithmetic progression from $low to $high with $count elements. Note that $low and $high have no specified type, so any type (or even pair of types) that the basic arithmetic operators will work on will work here. (In this script, we use it first for Num, and then for Complex.)

Lines 23-24 print the header for the header for a PBM file.

Lines 26-30 print the actual image data. $upper-right.re is the real part of the complex number $upper-right, and $upper-right.im is the imaginary part. The loop iterates over the real part of the range. Inside the loop, we subdivide again along the imaginary part to generate a list of the complex values we are interested in examining for one half of this row of the image. We then run that list through the mandel function using map, generating a list of 0s and 1s for half of the row, including the midpoint.

We do it this way because the Mandelbrot set is symmetric about the imaginary axis. So we then pop that midpoint, and make a new list which is the old list (minus the midpoint), the midpoint, and the list (minus the midpoint) reversed. We then feed that to join to make a string for the entire line, and finally say to print it out.

Note that doing it this way rotates the Mandelbrot set 90 degrees from the way it is normally displayed, giving us a lovely snowman shape:
White on black Mandelbrot set

With the current Rakudo, this is quite slow, and prone to crash randomly depending on the size of the image you are generating. However, imagine for a minute that happy future day when Rakudo is not only snappy, but handles automatic hyperoperator threading as well. At that point, it will be easy to make a parallel version of this script by changing the map call to a hyperoperator.

There’s only one tricky bit: there’s no way to have a hyperoperator call a normal sub. They only call class methods and operators. So, as a first approximation which works in current Rakudo, we can “augment” the Complex class to have a .mandel.

use MONKEY_TYPING;

augment class Complex {
    method mandel() {
        my $z = 0i;
        for ^$max_iterations {
            $z = $z * $z + self;
            return 1 if ($z.abs > 2);
        }
        return 0;
    }
}

for subdivide($upper-right.re, $lower-left.re, $height) -> $re {
    my @line = subdivide($re + ($upper-right.im)i, $re + 0i, ($width + 1) / 2)>>.mandel;
    my $middle = @line.pop;
    (@line, $middle, @line.reverse).join(' ').say;
}

The only difference to mandel is it is now a method, and the role of the former $c argument is taken by self. Then instead of map({mandel($_)}) we use the hyperoperator.

As I said, this version works now. But personally, I’m a little uncomfortable augmenting an existing class like that; it feels dirty to my old C++ instincts. We can avoid it by turning mandel into an operator:

sub postfix:<☃>(Complex $c) {
    my $z = 0i;
    for ^$max_iterations {
        $z = $z * $z + $c;
        return 1 if ($z.abs > 2);
    }
    return 0;
}

for subdivide($upper-right.re, $lower-left.re, $height) -> $re {
    my @line = subdivide($re + ($upper-right.im)i, $re + 0i, ($width + 1) / 2)>>☃;
    my $middle = @line.pop;
    (@line, $middle, @line.reverse).join(' ').say;
}

This takes advantage of Perl 6’s Unicode ability to have a little fun, defining the operator using the snowman symbol. This ☃ operator works fine in Rakudo today, but alas the >>☃ hyperoperator does not work yet.

Thanks to Moritz and TimToady for suggests and help with this code. Two versions of the script (one full color) are up at github, if you’d like to play around with them.

Update (4/18/2010): I’ve ported the color version of the script at github to the latest version of Rakudo. It’s quite slow, and uses phenomenal amounts of memory, but unlike the previous version it is rock-solid stable. Here’s a 1001×1001 full color Mandelbrot set that took it 14 hours and 6.4 GB of memory to compute.

Day 16: We call it ‘the old switcheroo’

Another glorious day in Advent; another gift awaits us. It’s switch statements!

Well, the term for them is still “switch statement” in Perl 6, but the keyword has changed for linguistic reasons. It’s now given, as in “given today’s weather”:

given $weather {
  when 'sunny'  { say 'Aah! ☀'                    }
  when 'cloudy' { say 'Meh. ☁'                    }
  when 'rainy'  { say 'Where is my umbrella? ☂'   }
  when 'snowy'  { say 'Yippie! ☃'                 }
  default       { say 'Looks like any other day.' }
}

Here’s a minimal explanation of the semantics, just to get us started: in the above example, the contents of the variable $weather is tested against the strings 'sunny', 'cloudy', 'rainy', and 'snowy', one after the other. If either of them matches, the corresponding block runs. If none matches, the default block triggers instead.

Not so different from switch statements in other languages, in other words. (But wait!) We’ll note in passing that the when blocks don’t automatically fall through, so if you have several conditions which would match, only the first one will run:

given $probability {
  when     1.00 { say 'A certainty'   }
  when * > 0.75 { say 'Quite likely'  }
  when * > 0.50 { say 'Likely'        }
  when * > 0.25 { say 'Unlikely'      }
  when * > 0.00 { say 'Very unlikely' }
  when     0.00 { say 'Fat chance'  }
}

So if you have a $probability of 0.80, the above code will print Quite likely, but not Likely, Unlikely etc. (In the cases when you want to “fall through” from a when block, you can end it with the keyword continue.) (Update: after spec discussions that originated in the comments of this post, break/continue were renamed to succeed/proceed.)

Note that in the above code, strings and decimal numbers and comparisons are used as the when expression. How does Perl 6 know how to match the given value against the when value, when both can be of wildly varying types?

The answer is that the two values enter a negotiation process called smartmatching, mentioned briefly in Day 13. To summarize, smartmatching (written as $a ~~ $b) is a kind of “regex matching on steroids”, where the $b doesn’t have to be a regex, but can be of any type. For ranges, the smartmatch will check if the value we want to match is within the range. If $b is a class or a role or a subtype, the smartmatch will perform a type check. And so on. For values like Num and Str which represent themselves, some appropriate equivalence check is made.

The “whatever star” (*) has the peculiar property that it smartmatches on anything. Oh, and default is just sugar for when *.

To summarize the summary, smartmatching is DWIM in operator form. And the given/when construct runs on top of it.

Now for something slightly head-spinning: the given and when features are actually independant! While you complete the syllable “WHAT?”, let me explain how.

Given is actually a sort of once-only for loop.

given $punch-card {
  .bend;
  .fold;
  .mutilate;
}

See what happened there? All given does is set the topic, also known to Perl people as $_. The cute .method is actually short for $_.method.

Now it’s easier to see how when can be used without a given, too. when can be used inside any block which sets $_, implicitly or explicitly:

my $scanning;
for $*IN.lines {
  when /start/ { $scanning = True }
  when /stop/  { $scanning = False }

  if $scanning {
    # Do something which only happens between the
    # lines containing 'start' and 'stop'
  }
}

Note that those when blocks exhibit the same behaviour as the in a given block: they skip the rest of the surrounding block after executing, which in the above code means they go directly to the next line in the input.

Here’s another example, this time with $_ explicitly set:

sub fib(Int $_) {
  when * < 2 { 1 }
  default { fib($_ - 1) + fib($_ - 2) }
}

(This independence between given and when plays out in other ways too. For example, the way to handle exceptions is with a CATCH block, a variant of given which topicalizes on $!, the variable holding the most recent exception.)

To top it all off, both given and when come in statement-ending varieties, just as for, if and the others:

  say .[0] + .[1] + .[2] given @list;
  say 'My God, it's full of vowels!' when /^ <[aeiou]>+ $/;

You can even nest a when inside a given:

  say 'Boo!' when /phantom/ given $castle;

As given and when represent another striking blow against the Perl obfuscation track record, I hereby present you with the parting gift of an obfu DNA helix, knowing full well that it doesn’t quite make up for the damage caused. :)

$ perl6 -e 'for ^20 {my ($a,$b)=<AT CG>.pick.comb.pick(*);\
  my ($c,$d)=sort map {6+4*sin($_/2)},$_,$_+4;\
  printf "%{$c}s%{$d-$c}s\n",$a,$b}'
     G  C
      TA
     C G
   G    C
 C     G
 G     C
 T   A
  CG
 CG
 C   G
 T     A
  T     A
   T    A
     C G
      TA
    T   A
  T     A
 A     T
 C    G
 G  C

Day 15: .pick your game

Another college semester has ended, or is soon ending, for many of us in the United States. I feel it’s appropriate that this gift will involve some fun. The gift is the ability to .pick things.

.pick allows for picking random elements from a list. Perl 5 allowed doing so through this syntax:

my @dice = (1, 2, 3, 4, 5, 6);
my $index = int (rand() * scalar @dice);
print $dice[$index] . "\n"; 
> 5

Perl 6 allows simplifying this, while at the same time picking more than one element.

my @dice = 1..6;
say @dice.pick(2).join(" ");
> 3 4

With just a set of dice, it is already possible to have a role playing session with your friends. Now, let’s see how much attack I can do with 10 d6s…

my @dice = 1..6;
say @dice.pick(10).join(" ");
> 5 3 1 4 2 6

For those wondering, the above result is not a typo. .pick‘s behavior is actually consistent with its name. When you pick something out, you generally keep it out. If you want to put the item back in, allowing the same item to be drawn again, use the :replace adverb in the second parameter.

my @dice = 1..6;
say @dice.pick(10, :replace).join(" ");
> 4 1 5 6 4 3 3 5 1 1

Note to game masters: don’t invite me to your D&D games unless you need someone with terrible dice luck. ;)

There is no specific order the list items have to be in for .pick to work its magic. Take the values of monopoly money, for instance:

my @dice = <1 5 10 20 50 100 500>;
say @dice.pick(10, :replace).join(" ");
> 20 50 100 500 500 10 20 5 50 20

When dice aren’t available, a deck of cards is usually on hand. This version is very basic, but is meant to get ideas going.

use v6;
class Card
{
  has $.rank;
  has $.suit;

  multi method Str()
  {
    return $.rank ~ $.suit;
  }
}

my @deck;
for <A 2 3 4 5 6 7 8 9 T J Q K> -> $rank
{
  for <♥ ♣ ♦ ♠> -> $suit
  {
    @deck.push(Card.new(:$rank, :$suit));
  }
}
# Shuffle the cards.
@deck .= pick(*);
say @deck.Str;
> Not outputting the results here.

What does the pick(*) do? Call that a sneak peak for another gift. For now, see if you can improve on the card code and make a deck class.

With that, I hope I have proven that Perl 6 is fun. It certainly gets a high mark from me. ✓

Day 14: Going to the Rats

As I hinted at back in the in the Day 1 post, Perl 6 has rational numbers. They are created in the most straightforward fashion, by dividing an integer with another integer. But it can be a bit hard to see that there is anything unusual about the result:

> say (3/7).WHAT
Rat()
> say 3/7
0.428571428571429

When you convert a Rat to a Str (for example, to “say” it), it converts to a decimal representation. This is based on the principle of least surprise: people generally expect 1/4 to equal 0.25. But the precision of the Rat is exact, rather than the approximation you’d get from a floating point number like a Num:

> say (3/7).Num + (2/7).Num + (2/7).Num - 1;
-1.11022302462516e-16
> say 3/7 + 2/7 + 2/7 - 1
0

The most straightforward way to see what is going on inside the Rat is to use the .perl method. .perl is a standard Perl 6 method which returns a human-readable string which, when eval’d, recreates the original object as closely as is possible:

> say (3/7).perl
3/7

You can also pick at the components of the Rat:

> say (3/7).numerator
3
> say (3/7).denominator
7
> say (3/7).nude.perl
[3, 7]

All the standard numeric operators and operations work on Rats. The basic arithmetic operators will generate a result which is also a Rat if that is possible; the rest will generate Nums:

> my $a = 1/60000 + 1/60000; say $a.WHAT; say $a; say $a.perl
Rat()
3.33333333333333e-05
1/30000
> my $a = 1/60000 + 1/60001; say $a.WHAT; say $a; say $a.perl
Num()
3.33330555601851e-05
3.33330555601851e-05
> my $a = cos(1/60000); say $a.WHAT; say $a; say $a.perl
Num()
0.999999999861111
0.999999999861111

(Note that the 1/60000 + 1/60000 didn’t work in the last official release of Rakudo, but is fixed in the Rakudo github repository.)

There also is a nifty method on Num which creates a Rat within a given tolerance of the Num (default is 1e-6):

> say 3.14.Rat.perl
157/50
> say pi.Rat.perl
355/113
> say pi.Rat(1e-10).perl
312689/99532

One interesting development which has not made it into the main Rakudo build yet is decimal numbers in the source are now spec’d to be Rats. Luckily this is implemented in the ng branch, so it is possible to demo how it will work once it is in mainstream Rakudo:

> say 1.75.WHAT
Rat()
> say 1.75.perl
7/4
> say 1.752.perl
219/125

One last thing: in Rakudo, the Rat class is entirely implemented in Perl 6. The source code is thus a pretty good example of how to implement a numeric class in Perl 6.

Day 13: Junctions

Among the many exciting things in Perl 6, junctions are one of my favourites. While I know I don’t really comprehend everything you can do with them, there are a few useful tricks which I think most people will appreciate, and it is those which I’m going to cover as today’s gift.

Junctions are values which have (potentially) more than one value at once. That sounds odd, so let’s get thinking about some code which uses them. First, let’s take an example. Suppose you want to check a variable for a match against a set of numbers:

if $var == 3 || $var == 5 || $var == 7 { ... }

I’ve never liked that kind of testing, seeing as how it requires much repetition. With an any junction we can rewrite this test:

if $var == any(3, 5, 7) { ... }

How does this work? Right near the core of Perl 6 is a concept called junctive autothreading. What this means is that, most of the time, you can pass a junction to anything expecting a single value. The code will run for each member of the junction, and the result will be all those results combined in the same kind of junction which was originally passed.

In the sample above, the infix:<==> operator is run for each element of the junction to compare them with $var. The results of each test are combined into a new any junction, which is then evaluated in Boolean context by the if statement. An any junction in Boolean context is true if any of its values are true, so if $var matches any value in the junction, the test will pass.

This can save a lot of duplicated code, and looks quite elegant. There’s another way to write it, as any junctions can also be constructed using the infix:<|> operator:

if $var == 3|5|7 { ... }

What if you want to invert this kind of test? There’s another kind of junction that’s very helpful, and it’s called none:

if $var == none(3, 5, 7) { ... }

As you may have guessed, a none junction in Boolean context is true only if none of its elements are true.

Junctive autothreading also applies in other circumstances, such as:

my $j = any(1, 2, 3);
my $k = $j + 2;

What will this do? By analogy to the first example, you can probably guess that $k will end up being any(3, 4, 5).

There is an important point to note in these examples. We’re talking about junctive autothreading, which should give you a hint. By the Perl 6 spec, the compiler is free to run these multiple operations on junctions in different threads so that they can execute in parallel. Much as with hyperoperators, you need to be aware that this could happen and avoid anything which would make a mess if run simultaneously.

The last thing I want to talk about is how junctions work with smartmatching. This is really just another instance of autothreading, but there are some other junction types which become particularly useful with smartmatching.

Say you have a text string, and you want to see if it matches all of a set of regexes:

$string ~~ /<first>/ & /<second>/ & /<third>/

Assuming, of course, you have defined regexes called first, second and third. Rather like |, & is an infix operator which creates junctions, this time all junctions which are only true if all their members are true.

The great thing about junctions is that they have this behaviour without the routine you’re passing them to having to know about it, so you can pass junctions to almost any library or core function and expect this kind of behaviour (it is possible for a routine to deliberately notice junctions and treat them how it prefers rather than using the normal autothreading mechanism). So if you have a routine which takes a value to smartmatch something against, you can pass it a junction and get that flexibility in the smartmatch for free. We use this in the Perl 6 test suite, with functions like Test::Util::is_run, which runs some code in another interpreter and smartmatches against its output.

To finish off, here are some other useful things you can do with junctions. First, checking if $value is present in @list:

any(@list) == $value

Junction constructors can work quite happily with the elements of arrays, so this opens up many possibilities. Others include:

all(@list) > 0; # All members greater than zero?
all(@a) == any(@b); # All elements of @a present in @b?

Go experiment, and have fun!

Day 12: Modules and Exporting

Today I’d like to talk about a fairly fundamental subject: libraries.

To write a library in Perl 6, we use the “module” keyword:

module Fancy::Utilities {
    sub lolgreet($who) {
        say "O HAI " ~ uc $who;
    }
}

Put that in Fancy/Utilities.pm somewhere in $PERL6LIB and we can use it like the following:

use Fancy::Utilities;
Fancy::Utilities::lolgreet('Tene');

That’s hardly ideal.  Just like in Perl 5, we can indicate that some symbols from the module should be made available in the lexical scope of the code loading the module.  We’ve got a rather different syntax for it, though:

# Utilities.pm
module Fancy::Utilities {
  sub lolgreet($who) is export {
    say "O HAI " ~ uc $who;
  }
}

# foo.pl
use Fancy::Utilities;
lolgreet('Jnthn');

If you don’t specify further, symbols marked “is export” are exported by default.  We can also choose to label symbols as being exported as part of a different named group:

module Fancy::Utilities {
 sub lolgreet($who) is export(:lolcat, :greet) {
  say "O HAI " ~ uc $who;
 }
 sub nicegreet($who) is export(:greet, :DEFAULT) {
  say "Good morning, $who!"; # Always morning?
 }
 sub shortgreet is export(:greet) {
  say "Hi!";
 }
 sub lolrequest($item) is export(:lolcat) {
  say "I CAN HAZ A {uc $item}?";
 }
}

Those tags can be referenced in the code loading this module to choose which symbols to import:

use Fancy::Utilities; # Just get the DEFAULTs
use Fancy::Utilities :greet, :lolcat;
use Fancy::Utilities :ALL; # Everything marked is export

Multi subs are export by default, so you only need to label them if you want to change that.

multi sub greet(Str $who) { say "Good morning, $who!" }
multi sub greet() { say "Hi!" }
multi sub greet(Lolcat $who) { say "O HAI " ~ $who.name }

Classes are just a specialization of modules, so you can export things from them as well.  In addition, you can export a method to make it available as a multi sub.  For example, the setting exports the “close” method from the IO class so you can call “close($fh);”

class IO {
    ...
    method close() is export {
        ...
    }
    ...
}

Perl 6 does support importing symbols by name from a library, but Rakudo does not yet implement it.