More OO Support, Captures and Ranges

After yesterday's day of Rakudo hacking, I was too tired to write up what had happened coherently, so I left it until today. I did quite a few different things throughout the day, so rather than taking them in order I'll group them in a way that makes it a bit easier to follow.

First, I dealt with some things from the perl6-compilers list. There was a patch from Moritz to factor out a large chunk of one of the methods in the parser actions file to help make it more readable, which I applied. There was also a bug report from Chris Fields, pointing out that typed variables had stopped working. After trying to work out why from some debugging, I then started working out which check-in had caused the problem, which soon led to a fix. So, type annotations will now work again.

I had tried to get some basic capture support in place before, but it was based upon the Capture PMC. For some reason, this didn't work out so well, and I was keen to have captures for something else I was going to implement later on. Therefore, I did a quick PIR version. I also implemented the $( ), @( ) and %( ) contextualizers (which put whatever is inside the brackets into item, list and hash context respectively). Therefore, you can now do things like:

my $x = \(1, 2, 3, foo => 42);
say $x[1]; # 2
say $x<foo>; # 42
for @($x) -> $val {
    say $val; # 1\n2\n3\n
}

There's plenty more to do on captures, but you have the basics now. And of course, the contextualizers work much more generally than just with captures, but we've some work to do in order to make these useful in the general case.

Each week I'm implementing a little more of S12 (the objects specification). This week was no exception. We now have basic support in for declaring and calling private methods.

class A {
    my method private {
        12;
    }
    method public {
        self!private
    }
}
say A.new().public; # 12

Notice how they are called with an entirely different syntax, so its obvious when looking at the code that you're calling something private. Talking of different calling syntaxes, there are some other variations to just writing "." to call a method. .? will call a method of that given name if there is one, or just return an undef (rather than throwing an exception) if there is no such method. .* will call all methods in the class hierarchy with that name, including inherited ones, and return a list of captures containing the values that were returned, and if there are no methods you will just get an empty list. .+ is like .*, but if it can't find at least one method to call it throws an exception. Think of them like quantifiers on regexes, but relating to method calls instead.

class Dog {
    method bark { say "WOOF" }
}
class Puppy is Dog {
    method bark { say "woof" }
}
my Puppy $x .= new();
$x.?bark(); # woof\n
$x.?doesnotexist(); # no exception
$x.+bark(); # woof\nWOOF\n

I haven't collected return values into captures in these examples, but it works too.

Something else that had been on the want list for a while was allowing explicit specification on a variable to hold the invocant of a method. This turned out to be trivial to implement, so rather than just having the self keyword you can now say:

class Foo {
    method test($inv: $x, $y) {
        say $inv.WHAT();
        say $x + $y;
    }
}
my $x = Foo.new();
$x.test(14, 28); # Foo\n42\n

As a slightly ad-hoc thing, I implemented the prefix ^ operator. On the name of a class, this gets the meta-class. On a number, it generates a range from 0 up to that value minus one. So the following prints the numbers 0 through 4, each on a line of their own.

for ^5 -> $n {
    say $n
}

This was actually just a trivial task I spotted while persuing the specification for ranges. We just fake them up in Rakudo at the moment to produce a list, but they are supposed to be lazy and have a whole load of other semantics. I stubbed in a Range class to get us started in that direction, but it needs quite a bit more work before we're ready to actually get Rakudo's ".." operator to construct it. For now it just stores its start and end points and knows how to give a Perl representation of itself.

Once again, thanks for Vienna.pm for sponsoring this work. Also, thanks to everyone else contributing to Rakudo, be it with patches, bug reports or general feedback. :-)

Categories:

5 Comments

bbkr Author Profile Page said:

When i try to run this Dog/Puppy example i get:

get_bool() not implemented in class 'Puppy'
current instr.: 'parrot;PCT::HLLCompiler;command_line' pc 1290 (src/PCT/HLLCompiler.pir:688)
called from Sub 'parrot;Perl6::Compiler;main' pc 10202 (perl6.pir:187)

bbkr@bbkr:~/prog/parrot> svn info
Path: .
URL: https://svn.perl.org/parrot/trunk
Repository Root: https://svn.perl.org/parrot
Repository UUID: d31e2699-5ff4-0310-a27c-f18f2fbe73fe
Revision: 27634
Node Kind: directory
Schedule: normal
Last Changed Author: fperrad
Last Changed Rev: 27632
Last Changed Date: 2008-05-19 12:05:43 +0200 (Mon, 19 May 2008)

bbkr Author Profile Page said:

And the first example dies when i quote PAIR key:

my $x = \(1, 2, 3, 'foo' => 42);

As of a patch I put in just now, you can now quote pair keys (but don't try doing stuff like $name => 42 yet, since that won't work...and probably won't until Parrot changes a little...).



For the Puppy/Dog example, I'm not sure why it's not running for you; it works here. Did you try it in a file or at the command line? But even at the command line, provided I shuffle stuff onto single lines (like the entire class definition), it still works here for me here. So not quite sure what problem you're running into here, sorry.



Thanks for feedback,



Jonathan

bbkr Author Profile Page said:

Dog/Puppy example was in file. Even empty class gives this error:

------------------------------------------
class Dog {}
my $d = Dog.new();
------------------------------------------

I'll try to checkout whole parrot again, maybe something got messy during update.


BTW: quoting hash keys works (except unicode), cool!

Jean-Christophe Zeus Author Profile Page said:

I must say that I get the same error with parrot-0.6.1 through parrot-0.6.4. With 0.6.4:

$ ../../parrot perl6.pbc roles.pl 
get_bool() not implemented in class 'Puppy'
current instr.: 'parrot;PCT::HLLCompiler;command_line' pc 1311 (src/PCT/HLLCompiler.pir:711)
called from Sub 'parrot;Perl6::Compiler;main' pc 13793 (perl6.pir:172)

Basic Perl6 programs do work, it's only when I introduce a class that I get this error message.

I would be glad to help track this down.

Leave a comment

About this Entry

This page contains a single entry by Jonathan Worthington published on May 17, 2008 1:01 PM.

Perl 6 Design Minutes for 07 May 2008 was the previous entry in this blog.

Perl 6 Design Minutes for 14 May 2008 is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Subscribe

    Subscribe to rakudo.org

Powered by Movable Type 4.1
Technorati Profile