Skip to content

Commit

Permalink
Merge branch 'master' of http://github.com/perl6/book
Browse files Browse the repository at this point in the history
  • Loading branch information
jest committed Sep 28, 2010
2 parents 10ba984 + ba5aef7 commit aa6657f
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 18 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ else
src/basics.pod \
src/operators.pod \
src/subs-n-sigs.pod \
src/multi-dispatch.pod \
src/classes-and-objects.pod \
src/multi-dispatch.pod \
src/roles.pod \
src/subtypes.pod \
src/regexes.pod \
Expand Down
2 changes: 1 addition & 1 deletion lib/book.sty
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@
Hongwen Qiu, Alex Elsayed, Solomon Foster, Nuno Carvalho, Will Coleda,
Aaron Sherman, Prakash Kailasa, Carlin Bingham, Dean Serenevy,
Jason Felds, Piotr Fusik, Tadeusz Sośnierz, Ralf Valerien,
Tim Bunce, Matt Follett, molecules and snarkyboojum.
Tim Bunce, Matt Follett, Patrick Donelan, James E. Keenan, molecules and snarkyboojum.
\end{description}
}
\lowertitleback{
Expand Down
89 changes: 89 additions & 0 deletions src/classes-and-objects.pod
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ Which package?
=end for

X<type object>
X<defined>
X<.defined>

Declaring a class creates a I<type object>, which by default gets installed
into the package (just like a variable declared with C<our> scope). This type
Expand All @@ -80,6 +82,21 @@ Perl 6 built-in classes. The example uses the class name C<Task> so that other
code can refer to it later, such as to create class instances by calling the
C<new> method.

Type objects are I<undefined>, in the sense that they return C<False> if you
call the C<.defined> method on them. You can use this method to find out if a
given object is a type object or not:

=begin programlisting

my $obj = Int;
if $obj.defined {
say "Type object";
} else {
say "Ordinary, defined object";
}

=end programlisting

=head1 I can has state?

X<attributes>
Expand Down Expand Up @@ -493,6 +510,78 @@ check out the Roles chapter.

=end programlisting

=head1 Introspection

Introspection is the process of gathering information about some objects in
your program, not by reading the source code, but by querying the object (or a
controlling object) for some properties, like its type.

Given an object C<$p>, and the class definitions from the previous sections,
we can ask it a few questions:

=begin programlisting

if $o ~~ Employee { say "It's an employee" };
if $o ~~ GeekCook { say "It's a geeky cook" };
say $o.WHAT;
say $o.perl;
say $o.^methods(:local).join(', ');

=end programlisting

The output can look like this:

=begin screen

It's an employee
Programmer()
Programmer.new(known_languages => ["Perl", "Python", "Pascal"], favorite_editor => "gvim", salary => "too small")
code_to_solve, known_languages, favorite_editor

=end screen

The first two tests each smart-match against a class name. If the object is
of that class, or of an inheriting class, it returns true. So the object in
question is of class C<Employee> or one that inherits from it, but not
C<GeekCook>.

The C<.WHAT> method returns the type object associated with the object C<$o>,
which tells the exact type of C<$o>: in this case C<Programmer>.

C<$o.perl> returns a string that can be executed as Perl code, and reproduces
the original object C<$o>. While this does not work perfectly in all
casesN<for example closures cannot easily be reproduced this way; if you don't
know what a closure is don't worry. Also current implementations have problems
with dumping cyclic data structures this way, but they are expected to be
handlded correctly by C<.perl> at some point.>, it
is very useful for debugging simple objects.

Finally C<$o.^methods(:local)> produces a list of methods that can be called
on C<$o>. The C<:local> named argument limits the returned methods to those
defined in the C<Employee> class, and excludes the inherited methods.

The syntax of calling method with C<.^> instead of a single dot means that it
is actually a method call on the I<meta class>, which is a class managing the
properties of the C<Employee> class - or any other class you are interested
in. This meta class enables other ways of introspection too:

=begin programlisting

say $o.^attributes.join(', ');
say $o.^parents.join(', ');

=end programlisting

Introspection is very useful for debugging, and for learning the language
and new libraries. When a function or method
returns an object you don't know about, finding its type with C<.WHAT>, a
construction recipe for it with C<.perl> and so on you'll get a good idea what
this return value is. With C<.^methods> you can learn what you can do with it.

But there are other applications too: a routine that serializes objects to a
bunch of bytes needs to know the attributes of that object, which it can find
out via introspection.

=head1 Exercises

B<1.> The method C<add-dependency> in C<Task> permits the creation of I<cycles>
Expand Down
31 changes: 15 additions & 16 deletions src/multi-dispatch.pod
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ this to count how often a type check occurs:

my $counter = 0;

multi a(Int $x) { };
multi a(Int $x) { }
multi a($x) { }
multi a($x where { $counter++; True }) { };
multi a($x where { $counter++; True }) { }

a(3);
say $counter; # says B<0>
Expand Down Expand Up @@ -254,18 +254,20 @@ more specific match in the nominal type.

This restriction allows a clever compiler optimization: it can sort all
candidates by narrowness once to find the candidate with the best matching
signature by examining nominal type constraints. These are far cheaper to check than constraint checks. Constraint checking occurs next, then the compiler considers the nominal types of candidates.
signature by examining nominal type constraints. These are far cheaper to
check than constraint checks. Constraint checking occurs next, and only if
the constraint check of the narrowest candidate fails, other candidates are
tried that are lass narrow by nominal type.

=for author

I could use a table or figure here to illustrate the hierarchy of narrowing.

=end for

With some trickery it is possible to get an object which conforms to a built-in
type (C<Num>, for example) but which is also an undefined value. In this case
the candidate that is specific to C<Num> wins, because the nominal type check
is narrower than the C<where {!defined $d}> constraint.
The C<Int> type object both conforms to C<Int>, but it is also an undefined
value. If you pass it to the multi C<a>, the second candidate, which is
specific to C<Int> wins, because nominal types are checked first.

=head1 Multiple arguments

Expand All @@ -275,11 +277,10 @@ narrowness of a match:

=begin programlisting

# RAKUDO has problems with an enum here,
# it answers with "Player One wins\nDraw\nDraw"
# using separate classes would fix that,
# but is not as pretty.
enum Symbol <Rock Paper Scissors>;
class Rock { }
class Paper { }
class Scissors { }

multi wins(Scissors $, Paper $) { +1 }
multi wins(Paper $, Rock $) { +1 }
multi wins(Rock $, Scissors $) { +1 }
Expand Down Expand Up @@ -311,10 +312,8 @@ paper, or scissors). Scissors win against paper, paper wraps rock, and
scissors can't cut rock, but go blunt trying. If both players select the same
item, it's a draw.

X<enum>

The code creates a type for each possible symbol by declaring an enumerated
type, or I<enum>. For each combination of chosen symbols for which Player One
The code creates a class for each possible symbol.
For each combination of chosen symbols for which Player One
wins there's a candidate of the form:

=begin programlisting
Expand Down

0 comments on commit aa6657f

Please sign in to comment.