.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "asa 3pm" .TH asa 3pm "2019-11-02" "perl v5.30.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" asa \- Lets your class/object say it works like something else .SH "VERSION" .IX Header "VERSION" version 1.04 .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& ######################################### \& # Your Code \& \& package My::WereDuck; \& \& use base \*(AqMy::Lycanthrope\*(Aq; \& use asa \*(AqDuck\*(Aq; \& \& sub quack { \& return "Hi! errr... Quack!"; \& } \& \& ################################################ \& # Their Code \& \& sub strangle { \& my $duck = shift; \& unless ( $duck\->isa(\*(AqDuck\*(Aq) ) { \& die "We only strangle ducks"; \& } \& print "Farmer Joe wrings the duck\*(Aqs neck\en"; \& print "Said the duck, \*(Aq" . $duck\->quack . "\*(Aq\en"; \& print "We ate well that night.\en"; \& } .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" Perl 5 doesn't natively support Java-style interfaces, and it doesn't support Perl 6 style roles either. .PP You can get both of these things in half a dozen different ways via various \s-1CPAN\s0 modules, but they usually require that you buy into \*(L"their way\*(R" of implementing your code. .PP Other have turned to \*(L"duck typing\*(R". .PP This is, for the most part, a fairly naive check that says \*(L"can you do this method\*(R", under the \*(L"if it looks like a duck, and quacks like a duck, then it must be a duck\*(R". .PP It assumes that if you have a \f(CW\*(C`\->quack\*(C'\fR method, then they will treat you as a duck, because doing things like adding \f(CW\*(C`Duck\*(C'\fR to your \f(CW@ISA\fR array means you are also forced to take their implementation. .PP There is, of course, a better way. .PP For better or worse, Perl's \f(CW\*(C`\->isa\*(C'\fR functionality to determine if something is or is not a particular class/object is defined as a \fBmethod\fR, not a function, and so that means that as well as adding something to you \&\f(CW@ISA\fR array, so that Perl's \f(CW\*(C`UNIVERSAL::isa\*(C'\fR method can work with it, you are also allowed to simply overload your own \f(CW\*(C`isa\*(C'\fR method and answer directly whether or not you are something. .PP The simplest form of the idiom looks like this. .PP .Vb 4 \& sub isa { \& return 1 if $_[1] eq \*(AqDuck\*(Aq; \& shift\->SUPER::isa(@_); \& } .Ve .PP This reads \*(L"Check my type as normal, but if anyone wants to know if I'm a duck, then tell them yes\*(R". .PP Now, there are a few people that have argued that this is \*(L"lying\*(R" about your class, but this argument is based on the idea that \f(CW@ISA\fR is somehow more \*(L"real\*(R" than using the method directly. .PP It also assumes that what you advertise you implement needs to be in sync with the method resolution for any given function. But in the best and cleanest implementation of code, the \s-1API\s0 is orthogonal (although most often related) to the implementation. .PP And although \f(CW@ISA\fR is about implementation \fBand\fR \s-1API,\s0 overloading \f(CW\*(C`isa\*(C'\fR to let you change your \s-1API\s0 is not at all bad when seen in this light. .SS "What does asa.pm do?" .IX Subsection "What does asa.pm do?" Much as base provides convenient syntactic sugar for loading your parent class and setting \f(CW@ISA\fR, this pragma will provide convenient syntactic sugar for creating your own custom overloaded isa functions. .PP Beyond just the idiom above, it implements various workarounds for some edge cases, so you don't have to, and allows clear separation of concerns. .PP You should just be able to use it, and if something ever goes wrong, then it's my fault, and I'll fix it. .SS "What doesn't asa.pm do?" .IX Subsection "What doesn't asa.pm do?" In Perl, highly robust introspection is \fBreally\fR hard. Which is why most modules that provide some level of interface functionality require you to explicitly define them in multiple classes, and start to tread on your toes. .PP This class does \fBnot\fR do any strict enforcement of interfaces. 90% of the time, what you want to do, and the methods you need to implement, are going to be pretty obvious, so it's your fault if you don't provide them. .PP But at least this way, you can implement them however you like, and \f(CW\*(C`asa\*(C'\fR will just take care of the details of safely telling everyone else you are a duck :) .SS "What if a Duck method clashes with a My::Package method?" .IX Subsection "What if a Duck method clashes with a My::Package method?" Unlike Perl 6, which implements a concept called \*(L"multi-methods\*(R", Perl 5 does not have a native approach to solving the problem of \*(L"\s-1API\s0 collision\*(R". .PP Originally from the Java/\*(C+ world, the problem of overcoming language \&\s-1API\s0 limitations can be done through the use of one of several \*(L"design patterns\*(R". .PP For you, the victim of \s-1API\s0 collision, you might be interested in the \&\*(L"Adapter\*(R" pattern. .PP For more information on implementing the Adapter pattern in Perl, see Class::Adapter, which provides a veritable toolkit for creating an implementation of the Adapter pattern which can solve your problem. .SH "SEE ALSO" .IX Header "SEE ALSO" .SH "SUPPORT" .IX Header "SUPPORT" Bugs may be submitted through the \s-1RT\s0 bug tracker (or bug\-asa@rt.cpan.org ). .SH "AUTHOR" .IX Header "AUTHOR" Adam Kennedy, .SH "CONTRIBUTORS" .IX Header "CONTRIBUTORS" .IP "\(bu" 4 Adam Kennedy .IP "\(bu" 4 Karen Etheridge .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is copyright (c) 2006 by Adam Kennedy. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.