Perl 6 has a REPL. That’s a tiny, language-specific shell that Reads a line, Evaluates it, Prints the result, and Loops to do it again. It can remember the previous results in the same session.
Let’s start with something simple. Run the perl6 command with no arguments and wait for the prompt:
$ perl6 To exit type 'exit' or '^D' >
I can try the usual “Hello World” program:
> 'Hello World!' Hello World!
I can try it with say
, which outputs the string with a newline on the end. That’s how I would need to output it inside a program; inside the REPL, that doesn’t look different than
what I already did:
> say 'Hello World!' Hello World!
In Perl 6 land, a string is an object, so I can call methods on the string. Perl 6 uses the dot as the method call operator:
> 'Hello World!'.say Hello World!
What else can I do with ? Perl 6 values are themselves objects. The
WHAT
“meta” method knows what thingys are:
> 'Hello World!'.WHAT (Str)
The (Str)
is the name of the class in parentheses. I don’t need to know the type of thing it is to figure out what I can do. Or, read another way, I don’t need to look at the docs for Str to see what methods I can call. The .^methods
method (ahem) tells me what the object can respond to:
> 'Hello World!'.^methods (BUILD Int Num chomp pred succ simplematch match ords samecase samemark samespace word-by-word trim-leading trim-trailing trim encode NFC NFD NFKC NFKD wordcase trans indent codes chars uc lc tc fc tclc flip ord WHY WHICH Bool Str Stringy DUMP ACCEPTS chop starts-with ends-with substr-eq contains indices index rindex Numeric gist perl comb subst-mutate subst lines split words)
That .^methods
looks weird, but it’s really just a shortcut for .HOW.methods
. The Higher Order Workings class has many ways to introspect a thingy. This is an amazing boon to learning the language since you can, at least partly, discover things about the objects from inside the language. All your Ruby friends will say “Welcome to 1995!”.
Notice that say
is not in the list. By default, .^methods
doesn’t show methods from certain base classes. I can ask for different slices of that list by adding the :all
adverb:
> 'Hello World!'.^methods(:all) (BUILD Int Num chomp pred succ simplematch match ords samecase samemark samespace word-by-word trim-leading trim-trailing trim encode NFC NFD NFKC NFKD wordcase trans indent codes chars uc lc tc fc tclc flip ord WHY WHICH Bool Str Stringy DUMP ACCEPTS chop starts-with ends-with substr-eq contains indices index rindex Numeric gist perl comb subst-mutate subst lines split words trans fmt comb acosech cotan sin fc contains EVAL cosec atan2 abs ord trim-trailing ords acotan asec ceiling unpolar acosec acos indices log10 exp match subst chrs acosh truncate acotanh Num path floor UInt words flip asin codes univals asech chomp split cotanh ...)
That’s right, I said adverb. Things that start with a colon are modifiers for an action. You can worry about those later. In this case, :all
modifies how .^methods
responds.
Still, I don’t see say
in that list, which is truncated with ...
. Perl 6 displays the result as a “gist”, or, the general idea of the result in a human-readable form. It’s the same thing as this:
> 'Hello World!'.^methods(:all).gist
This gist an amazing feature. I’ve wished that Data::Dumper was built into Perl 5 so many times. Now it’s available to most objects automatically, but it is not going to overload you with output. I’ll have to do a bit of work on my own for that.
If that’s too high-level for you, the perl
method is closer to the internal representation. You can run this yourself if you’d like to see the very long and complicated output that’s pretty useless to all but 11 people in the world:
> 'Hello World!'.^methods(:all).perl
But, I want to find that say
method. What do I get back from ^methods()
? I call WHAT
again and see that I get a List object:
> 'Hello World!'.^methods(:all).WHAT (List)
That’s a list, but what’s in the list? I can call map
on the List. I cheat a bit here because I know that there should be something like map
and I looked at the documentation. I’d much rather discover that through exploration, but that’s how it is at the moment:
> 'Hello World!'.^methods(:all).map( {.WHAT.gist} ).unique ((Submethod) (Method) (Method+{Callable[Int:D]}) (Method+{<anon|140546676469920>}))
The map
gets each item in the list and passes it to the block argument. Perl 6 does some impressive stuff with blocks, but for now think of it as an inline subroutine. Inside this map
, I call .WHAT.gist
. What’s up with the leading dot?
Perl 6 has a default variable, which it calls the topic. If there’s no object in front of the method-calling dot, it uses that topic.
Once I’ve constructed that list I call unique
to make a list of just the types it saw. Each thing is a some sort of Method.
A Method knows its name (if it has one). This in itself is quite interesting. If I call can
on an object and that object can respond to a method of that name, it gives me back a list of methods? (A list? Yep! Because Perl 6 has multi dispatch based on the arguments I pass!). Even though I have a list of one item, I only want to first item. I store that in $method
(which I must declare before use):
> my $method = 'Hello World!'.can( 'say' ).first say
The REPL remembers what I stored in that variable. It’s a Method and I can ask it its name. I can also use the variable in place of the literal method name to operate on my string:
> $method.name say > 'Hello World!'.$method Hello World!
It’s a bit easier to see if I use a different method, such as uc
to uppercase
> my $method = 'Hello World!'.can( 'uc' ).first uc > 'Hello World!'.$method HELLO WORLD!
This is very exciting! It might not seem like much, but when these things are objects that know things about themselves, a big world of programming opens up.
But, I started off looking for say
but I haven’t found it yet.
I can make a new list of just the names by calling map
and sort
that. When I give only one argument to the block in sort
, it uses that result to compare elements. It also remembers that value so it does not calculate it again (so, no Schwartzian Transform needed!):
> 'Hello World!'.^methods(:all).map( { .name } ).sort( { .lc } ).unique.join( "\n" )
This creates a really long string, but it’s all the methods available on "Hello World"
. I can make a shorter list with grep
by looking for things that have sa
at the start of the string:
> 'Hello World!'.^methods(:all).map( {.name} ).grep( { /^^ sa/ } ).join( "\n" ) samecase samemark samespace samecase say
And, I’ve found say
! It took me a bit, but I was able to find out quite a bit starting with just the object.
I can define my own class with some attributes. Here’s a Butterfly
class that has a name and a type attribute. I
can create an object in that class, then look at the
> class Butterfly { has Str $.name; has Str $.type; } (Butterfly) > my $camelia = Butterfly.new( name => 'Camelia', type => 'Monarch' ); Butterfly.new(name => "Camelia", type => "Monarch") > $camelia.WHAT (Butterfly) > $camelia.^attributes (Str $!name Str $!type)
I could keep going like this to try bits of Perl 6. I don’t have to write programs for the very short experiements. Personally, I like to keep the experiments in files because I keep changing things. It’s better than retyping.
Hi Brian, trying the examples in P6 (-v reports, ‘This is perl6 version 2014.07 built on parrot 6.6.0 revision 0’) on RaspberryPi… (This is a really old build.) The below code returns nothing…
> ‘Hello World!’.^methods(:all).WHAT
>
returns nothing. Trying [0] …
> ‘Hello World!’.^methods(:all).WHAT.gist
> (Parcel)
I think the version of rakudo/parrot I’ve installed, stock on latest P6 pre-build on RPi Raspian is borked. I think I’ll build from the source to see what happens in a later build. Thanks for adding these posts, great way to go through Perl6.
[0] SO
Yep, a source build upgrade on the RPi to the latest “Perl 6 with MoarVM” using this method [0] yeilds the right response.
> ‘Hello World!’.^methods(:all).WHAT
(List)
[0] https://www.tyil.nl/tutorials/perl6-setting-up-a-raspberry-perl/#installing-perl-6