Содержание
Perl usually decides which function to call based on the name of the function or the contents of a function reference. This is simple to understand. Perl can also examine the contents of the arguments provided to decide which of several variants of a function--variants each with the same name--to call. In this case, the amount and types of the function's arguments help to distinguish between multiple variants of a function. This is multidispatch, and the functions to which Perl can dispatch in this case are multis.
Javascript Object Notation (JSON) is a simple data exchange format often
used for communicating with web services. It supports arrays, hashes, numbers,
strings, boolean values, and null, the undefined value.
JSON::Tiny is a minimal library used to convert Perl 6 data structures to
JSON. See for the other part of that module, which parses JSON and
turns it into Perl 6 data structures. The full code, containing additional
documentation and tests, is available from <U>http://github.com/moritz/json/</U>.
This snippet demonstrates how multis make the code simpler and more obvious:
multi to-json(Real $d) { ~$d }
multi to-json(Bool $d) { $d ?? 'true' !! 'false'; }
multi to-json(Str $d) {
'"'
~ $d.trans(['"', '\\', "\b", "\f", "\n", "\r", "\t"]
=> ['\"', '\\\\', '\b', '\f', '\n', '\r', '\t'])
~ '"'
}
multi to-json(Array $d) {
return '[ '
~ $d.values.map({ to-json($_) }).join(', ')
~ ' ]';
}
multi to-json(Hash $d) {
return '{ '
~ $d.pairs.map({ to-json(.key)
~ ' : '
~ to-json(.value) }).join(', ')
~ ' }';
}
multi to-json($d where {!defined $d}) { 'null' }
multi to-json($d) {
die "Can't serialize an object of type " ~ $d.WHAT.perl
}
This code defines a single multi sub named to-json, which takes one argument
and turns that into a string. to-json has many candidates; these subs all
have the name to-json but differ in their signatures. Every candidate
resembles:
multi to-json(Bool $data) { ... }
multi to-json(Real $data) { ... }
Which one is actually called depends on the type of the data passed to the
subroutine. A call such as to-json(Bool::True) invokes the first candidate.
Passing a numeric value of type Real instead invokes the second.
The candidate for handling Real is very simple; because JSON's
and Perl 6's number formats coincide, the JSON converter can rely on Perl's
conversion of these numbers to strings. The Bool candidate returns a literal
string 'true' or 'false'.
The Str candidate does more work: it wraps its parameter in quotes and
escapes literal characters that the JSON spec does not allow in strings--a
tab character becomes \t, a newline \n, and so on.
The to-json(Array $d) candidate converts all elements of the array to JSON
with recursive calls to to-json, joins them with commas, and surrounds them
with square brackets. The recursive calls demonstrate a powerful truth of
multidispatch: these calls do not necessarily recurse to the Array
candidate, but dispatch to the appropriate candidate based on the types of
their arguments.
The candidate that processes hashes turns them into the form { "key1" :
"value1", "key2" : [ "second", "value" ] }. It does this again by recursing
into to-json.