The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Copyright (C) 2001-2012, Parrot Foundation.

=pod

=head1 NAME

docs/user/pir/objects.pod - Using Objects in Parrot. 

=head1 DESCRIPTION

This document covers object oriented programming in PIR.

=head1 PROGRAMMING PARROT -- USING OBJECTS

Yes, you've read correctly. Parrot has the ability to create
and manipulate objects (aka, object oriented programming).
While it may seem strange for a low-level language like
PIR to have the facility for object oriented programming,
it makes perfect sense in this particular case. Remember,
the original goal of Parrot was to be the underlying
implementation for Perl6, which has object oriented
features. Parrot's secondary goal is to provide a good
platform for other dynamic languages such as Python, Ruby,
PHP, Javascript, etc. and those languages too have the
ability (if not the requirement) to be object oriented. Thus
Parrot contains facilities for a manipulating objects so
that language implementors can easily express the
appropriate object semantics for their language of interest.

=head2 Namespaces

Before I begin talking about how to create classes and
instantiate objects, I first need to talk about an
intimately related subject: namespaces. Namespaces serve a
twofold purpose, they allow you to group related routines
together and they allow you to give several subroutines the
same name but different, domain specific, implementations.
These characteristics are, oddly enough, similar to the
basic requirements for a class.

For instance, you may put all of your subroutines dealing
with people in a C<Person> namespace and all of your
subroutines dealing with computer programs in the C<Process>
namespace. Both namespaces may have a subroutine called
C<run()> but with radically different implementations. Below
is some code to illustrate this example:

=head3 Example 1:

=begin PIR

    .namespace [ "Person" ]

    .sub run
        say "Run Forrest, Run!"
    .end

    .namespace [ "Process" ]

    .sub run
        say "Running process #53"
    .end

=end PIR

As you might guess, the C<.namespace> directive tells Parrot
what namespace to group subroutines under.  A namespace ends when
another C<.namespace> directive changes the namespace or when
the end of the file is reached. A C<.namespace> directive
with no names in the brackets changes back to the root namespace.

Perl programmers will recognize that Parrot
C<.namespace> declarations are just like Perl C<package>
declarations, albeit with different syntax.
But there are a few other differences. I'll
talk more about how Parrot uses namespaces and classes
together in just a minute.

=head2 PIR with class

Creating classes in Parrot is relatively easy. There are
opcodes for it. The easiest to start with is C<newclass>;
just say C<$P0 = newclass 'Foo'> where $P0 is a PMC
register, and 'Foo' is the name of the class you want to create.

When you wish to instantiate objects that belong to the class
you've created, it's equally simple.  Just say C<myobj = new
"Foo"> where C<myobj> is a PMC and "Foo" is the classname you've
created with C<newclass>.  Here's a simple example:

=head3 Example 2: A classic Dog

=begin PIR

    .sub _ :main
        $P0 = newclass 'Dog'
        .local pmc spot
        spot = new 'Dog'
    .end

=end PIR

You may notice that I didn't use the return value of
C<newclass>.  That's only because this is a simple example.  :-)
I'll talk about what to do with the return value of C<newclass>
a little later. Right now, let's talk about methods.

=head2 Madness ... er, Methods

So now that I've created a C<Dog> class, how do I add methods
to it?  Remember before when I talked about namespaces?  Well,
that's the answer. To add methods to a class, you create a
namespace with the same name as the class and then put your
subroutines in that namespace. PIR also provides a syntactic
marker to let everyone know these subroutines are methods. When
declaring the subroutine, add the C<:method> modifier after the
subroutine name. Here's a familiar example to anyone who has
read L<perlboot>.

=head3 Example 3: Barnyard animals

=begin PIR

    .namespace [ "Cow" ]

    .sub speak :method
        print "Moo\n"
    .end

    .namespace [ "Dog" ]

    .sub speak :method
        print "Woof\n"
    .end

    .namespace [ "Pig" ]

    .sub speak :method
        print "Oink\n"
    .end

    .namespace []

    .sub _ :main
        $P0 = newclass "Cow"
        $P0 = newclass "Dog"
        $P0 = newclass "Pig"

        .local pmc elsie, fido, porky

        elsie   = new "Cow"
        fido    = new "Dog"
        porky   = new "Pig"

        elsie.'speak'()
        fido.'speak'()
        porky.'speak'()
    .end

=end PIR

It's important to note that even though I've declared the
namespaces and put subroutines in them, this does not
automatically create classes. The C<newclass> declarations
tell Parrot to create a class and as a side effect,
namespaces with the same name as the class may be used to
store methods for that class.

One thing you may notice about method calls is that the
method names are quoted. Why is that? If you would have left out
the quotes, then the identifier is assumed to be a declared
C<.local> symbol. So, instead of writing:

=begin PIR_FRAGMENT

    .local pmc elsie
    elsie.'speak'()

=end PIR_FRAGMENT

you could also have written:

=begin PIR_FRAGMENT

    .local pmc elsie
    .local string speak
    speak = 'speak'
    elsie.speak()

=end PIR_FRAGMENT

Another example of this is shown below.

=head3 Example 4: variable methods

=begin PIR

    .namespace [ 'Foo' ]

    .sub foo :method
        print "foo\n"
    .end

    .sub bar :method
        print "bar\n"
    .end

    .namespace []

    .sub _ :main
        $P0 = newclass "Foo"
        .local pmc f
        f = new "Foo"

        .local string m
        m = "foo"
        f.m()
        m = "bar"
        f.m()
    .end

=end PIR

=head2 But where do I store my stuff?

So far I've talked about namespaces and creating classes
and associating methods with those classes, but what about
storing data in the class? Remember how the C<newclass>
opcode returned a PMC that I didn't do anything to/with?
Well, here's where it's used. The PMC returned from
C<newclass> is the handle by which you manipulate the class.
One such manipulation involves class "attributes".  Attributes
are where you store your class-specific data.

Parrot has several opcodes for manipulating attributes; they
are: C<addattribute>, C<setattribute>, and C<getattribute>.
The C<addattribute> opcode lets you add a spot in the class
for storing a particular value which may be get and set with
C<getattribute> and C<setattribute> respectively.  The only
restriction on these values is that currently all
attributes must be PMCs.

So, say I wanted to give my barnyard animals names (I'll
illustrate with just one animal and you can infer how to do the
same for the rest):

=head3 Example 5: Naming my animals

=begin PIR

    .namespace [ "Dog" ]

    .sub name :method
        .local pmc name
        name = getattribute self, "name"
        print name
    .end

    .sub speak :method
        print "woof"
    .end

    .namespace []

    .sub _ :main
        $P0 = newclass "Dog"
        addattribute $P0, "name"

        .local pmc dog
        dog = new "Dog"
        $P0 = new "String"
        $P0 = "Phideaux"
        setattribute dog, "name", $P0

        dog.'name'()
        print " says "
        dog.'speak'()
        print "!\n"
    .end

=end PIR

Whew! There's a lot of new stuff in this code. I'll take them
starting from the top of the program and working towards the
bottom.

One of the benefits of tagging your subroutines as methods
is that they get a PMC named C<self> that represents the
object they are acting on behalf of. The C<name> method
takes advantage of this to retrieve the attribute called
"name" from the C<self> PMC and print it.

Immediately after I create the class called "Dog", I use the
PMC handle returned from C<newclass> to add an attribute called
"name" to the class. This just allocates a slot in the class for
the value, it does nothing more.

Next, I create a new Dog and give it a name. Because
attributes may only be PMCs, in order to give the Dog a
name, I first have to create a new String PMC (this is one
of the PMCs builtin to Parrot) and assign the name I wish
to give the dog to this PMC. Then I can pass this PMC as a
parameter to C<setattribute> to give my Dog a name.

Seems kind of complicated, doesn't it? Especially when you think
about doing this for each animal. Each animal namespace
would have an identical version of the C<name> method.  For each
call to C<newclass> I'd need to also call C<addattribute> so
that all of the animals may have a name.  Each time I wish to
assign a name to an animal, I'd first need to create a
C<String> and call C<setattribute> on it. Et cetera.

Surely there's a better way?!?  There is ...

=head2 Inheritance

You saw it coming didn't you? What's object oriented
programming without inheritance? Parrot has an opcode
C<subclass> that lets you inherit data and methods from an
existing class. We can use this ability to create a base
class called "Animal" that contains the "name" attribute and
two methods that are common to all animals: C<setname> and
C<getname> Then, to create new animals, I just inherit from
the Animal base class like so:

=head3 Example 6: inheriting

=begin PIR_FRAGMENT

    $P0 = newclass "Animal"
    addattribute $P0, "name"
    $P0 = subclass "Animal", "Cow"
    $P0 = subclass "Animal", "Dog"
    $P0 = subclass "Animal", "Pig"
    # ...
    .local pmc cow
    cow = new 'Cow'
    cow.'setname'("Elsie")
    # ...
    cow.'getname'()

=end PIR_FRAGMENT

Each subclass will contain an attribute called "name" that can be
used to store the name of the animal.  The C<setname> method
abstracts out the process of creating a C<String> PMC and
calling C<setattribute> on it. And finally the C<getname> method
becomes a wrapper around C<getattribute>.

=head2 Wrapup

I hope this gives you an idea of how to do object oriented
programming using Parrot. The opcodes illustrated here are what
any language implementor that targets Parrot would use to
implement object oriented features in their language. Of course
there are more opcodes for richer object oriented behavior
available in Parrot.  This article only covers the basics.  For
more information see parrot/docs/pdds/pdd15_objects.pod.

At the end of this article is a more complete listing of the
program that gives my barnyard animals voices. There are
many improvements that can be made to this code so take this
opportunity to read and experiment and learn more about OOP
in Parrot.

=head2 Acknowledgements

=over 4

* Thanks to Randal Schwartz for providing a neat set of
  examples in L<perlboot> from which this article
  shamelessly borrows.
* Thanks to the Parrot people for feedback

=back

=head2 Author

Jonathan Scott Duff

=head3 Example 6: Full barnyard listing

=begin PIR

    .namespace [ "Animal" ]

    .sub setname :method
        .param string name
        $P0 = new 'String'
        $P0 = name
        setattribute self, "name", $P0
    .end

    .sub getname :method
        $P0 = getattribute self, "name"
        .return($P0)
    .end

    .sub speak :method
        .local string name, sound
        name = self.'getname'()
        sound = self.'sound'()
        print name
        print " says "
        print sound
        print "\n"
    .end

    .namespace [ "Cow" ]

    .sub sound :method
        .return( "moo" )
    .end

    .namespace [ "Dog" ]

    .sub sound :method
        .return( "woof" )
    .end

    .namespace [ "Pig" ]

    .sub sound :method
        .return( "oink" )
    .end

    .namespace []

    .sub _ :main
        $P0 = newclass "Animal"
        addattribute $P0, "name"
        $P0 = subclass "Animal", "Cow"
        $P0 = subclass "Animal", "Dog"
        $P0 = subclass "Animal", "Pig"

        .local pmc cow, dog, pig

        cow   = new "Cow"
        cow.'setname'("Elsie")
        dog    = new "Dog"
        dog.'setname'("Snoopy")
        pig   = new "Pig"
        pig.'setname'("Porky")

        cow.'speak'()
        dog.'speak'()
        pig.'speak'()
    .end

=end PIR

=cut