Download - Advanced Perl Programming, 2nd Editionsoftouch.on.ca/kb/data/Advanced Perl Programming. 2nd Edition.pdfPerl changed in other ways, too: the announcement of Perl 6 in 2000 ironically

Transcript
  • AdvancedPerlProgramming,2ndEditionBySimonCozens...............................................Publisher:O'ReillyPubDate:June2005ISBN:0-596-00456-7Pages:304

    TableofContents|Index

    Withaworldwidecommunityofusersandmorethanamilliondedicatedprogrammers,Perlhasproventobethemosteffectivelanguageforthelatesttrendsincomputingandbusiness.

    Everyprogrammermustkeepupwiththelatesttoolsandtechniques.ThisupdatedversionofAdvancedPerlProgrammingfromO'ReillygivesyoutheessentialknowledgeofthemodernPerlprogrammer.WhateveryourcurrentlevelofPerlexpertise,thisbookwillhelpyoupushyourskillstothenextlevelandbecomeamoreaccomplishedprogrammer.

    O'Reilly'smosthigh-levelPerltutorialtodate,AdvancedPerlProgramming,SecondEditionteachesyouallthecomplextechniquesforproduction-readyPerlprograms.Thiscompletelyupdatedguideclearlyexplainsconceptssuchasintrospection,overridingbuilt-ins,extendingPerl'sobject-orientedmodel,andtestingyourcodeforgreaterstability.

    Othertopicsinclude:

    Complexdatastructures

    Parsing

    Templatingtoolkits

    Workingwithnaturallanguagedata

    Unicode

    InteractionwithCandotherlanguages

    Inaddition,thisguidedemystifiesoncecomplextopicslikeobject-relationalmappingandevent-baseddevelopment-armingyouwitheverythingyouneedtocompletelyupgradeyourskills.

    PraisefortheSecondEdition:

  • "Sometimesthebiggesthurdletoproblemsolvingisn'tthesubjectitselfbutratherthesheernumberofmodulesPerlprovides.AdvancedPerlProgrammingwalksyouthroughPerl'sTMTOWTDI("There'sMoreThanOneWayToDoIt")forest,explainingandcomparingthebestmodulesforeachtasksoyoucanintelligentlyapplytheminavarietyofsituations."--RoccoCaputo,leaddeveloperofPOE

    "IthasbeensaidthatsufficientlyadvancedPerlcodeisindistinguishablefrommagic.Thisbookofspellsgoesalongwaytounlockingthosesecrets.IthasthepowertotransformthemosthumbleprogrammerintoaPerlwizard."--AndyWardley

    "Theinformationhereisn'ttheoretical.Itpresentstoolsandtechniquesforsolvingrealproblemscleanlyandelegantly."--Curtis'Ovid'Poe

    "AdvancedPerlProgrammingcollectshard-earnedknowledgefromsomeofthebestprogrammersinthePerlcommunity,andexplainsitinawaythatevennovicescanapplyimmediately."--chromatic,EditorofPerl.com

  • AdvancedPerlProgramming,2ndEditionBySimonCozens...............................................Publisher:O'ReillyPubDate:June2005ISBN:0-596-00456-7Pages:304

    TableofContents|Index

    Copyright Preface Audience Contents ConventionsUsedinThisBook UsingCodeExamples We'dLiketoHearfromYou Safari®Enabled Acknowledgments Chapter1.AdvancedTechniques Section1.1.Introspection Section1.2.MessingwiththeClassModel Section1.3.UnexpectedCode Section1.4.Conclusion Chapter2.ParsingTechniques Section2.1.Parse::RecDescentGrammars Section2.2.Parse::Yapp Section2.3.OtherParsingTechniques Section2.4.Conclusion Chapter3.TemplatingTools Section3.1.FormatsandText::Autoformat Section3.2.Text::Template Section3.3.HTML::Template Section3.4.HTML::Mason Section3.5.TemplateToolkit

  • Section3.6.AxKit Section3.7.Conclusion Chapter4.Objects,Databases,andApplications Section4.1.BeyondFlatFiles Section4.2.ObjectSerialization Section4.3.ObjectDatabases Section4.4.DatabaseAbstraction Section4.5.PracticalUsesinWebApplications Section4.6.Conclusion Chapter5.NaturalLanguageTools Section5.1.PerlandNaturalLanguages Section5.2.HandlingEnglishText Section5.3.ModulesforParsingEnglish Section5.4.CategorizationandExtraction Section5.5.Conclusion Chapter6.PerlandUnicode Section6.1.Terminology Section6.2.WhatIsUnicode? Section6.3.UnicodeTransformationFormats Section6.4.HandlingUTF-8Data Section6.5.Encode Section6.6.UnicodeforXSAuthors Section6.7.Conclusion Chapter7.POE Section7.1.ProgramminginanEvent-DrivenEnvironment Section7.2.Top-LevelPieces:Components Section7.3.Conclusion Chapter8.Testing Section8.1.Test::Simple Section8.2.Test::More Section8.3.Test::Harness Section8.4.Test::Builder Section8.5.Test::Builder::Tester Section8.6.KeepingTestsandCodeTogether Section8.7.UnitTests Section8.8.Conclusion Chapter9.InlineExtensions Section9.1.SimpleInline::C Section9.2.MoreComplexTaskswithInline::C

  • Section9.3.Inline::EverythingElse Section9.4.Conclusion Chapter10.FunwithPerl Section10.1.Obfuscation Section10.2.JustAnotherPerlHacker Section10.3.PerlGolf Section10.4.PerlPoetry Section10.5.Acme::* Section10.6.Conclusion Colophon AbouttheAuthor Colophon Index

  • AdvancedPerlProgramming,SecondEdition

    bySimonCozens

    Copyright©2005,1997O'ReillyMedia,Inc.Allrightsreserved.

    PrintedintheUnitedStatesofAmerica.

    PublishedbyO'ReillyMedia,Inc.,1005GravensteinHighwayNorth,Sebastopol,CA95472.

    O'Reillybooksmaybepurchasedforeducational,business,orsalespromotionaluse.Onlineeditionsarealsoavailableformosttitles(safari.oreilly.com).Formoreinformation,contactourcorporate/institutionalsalesdepartment:(800)[email protected].

    Editor: AllisonRandal

    ProductionEditor: DarrenKelly

    CoverDesigner: EdieFreedman

    InteriorDesigner: DavidFutato

    ProductionServices: nSight,Inc.

    PrintingHistory:

    August1997: FirstEdition.

    June2005: SecondEdition.

    NutshellHandbook,theNutshellHandbooklogo,andthe

    mailto:[email protected]

  • O'ReillylogoareregisteredtrademarksofO'ReillyMedia,Inc.AdvancedPerlProgramming,theimageofaofablackleopard,andrelatedtradedressaretrademarksofO'ReillyMedia,Inc.

    Manyofthedesignationsusedbymanufacturersandsellerstodistinguishtheirproductsareclaimedastrademarks.Wherethosedesignationsappearinthisbook,andO'ReillyMedia,Inc.wasawareofatrademarkclaim,thedesignationshavebeenprintedincapsorinitialcaps.

    Whileeveryprecautionhasbeentakeninthepreparationofthisbook,thepublisherandauthorassumenoresponsibilityforerrorsoromissions,orfordamagesresultingfromtheuseoftheinformationcontainedherein.

    ISBN:0-596-00456-7

    [M]

  • PrefaceItwasallNathanTorkington'sfault.OurAntipodeanprogrammer,editor,andO'ReillyconferencesupremofriendaskedmetoupdatetheoriginalAdvancedPerlProgrammingwaybackin2002.

    ThePerlworldhadchangeddrasticallyinthefiveyearssincethepublicationofthefirstedition,anditcontinuestochange.Particularly,we'veseenashiftawayfromtechniquesandtowardresourcesfromdoingthingsyourselfwithPerltousingwhatotherpeoplehavedonewithPerl.Inessence,advancedPerlprogramminghasbecomemoreamatterofknowingwheretofindwhatyouneedontheCPAN,[*]ratherthanamatterofknowingwhattodo.

    [*]TheComprehensivePerlArchiveNetwork(http://www.cpan.org)istheprimaryresourceforuser-contributedPerlcode.

    Perlchangedinotherways,too:theannouncementofPerl6in2000ironicallycausedarenewedinterestinPerl5,withpeoplestretchingPerlinnewandinterestingdirectionstoimplementsomeoftheideasandblue-skiesthinkingaboutPerl6.Contrarytowhatweallthoughtbackthen,farfromkillingoffPerl5,Perl6'sdevelopmenthasmadeitstrongerandensureditwillbearoundlonger.

    SoitwasinthiscontextthatitmadesensetoupdateAdvancedPerlProgrammingtoreflectthechangesinPerlandintheCPAN.WealsowantedtheneweditiontobemoreinthespiritofPerltofocusonhowtoachievepracticaltaskswithaminimumoffuss.Thisiswhyweputtogetherchaptersonparsingtechniques,ondealingwithnaturallanguagedocuments,ontestingyourcode,andsoon.

    Butthisbookisjustabeginning;howevertemptingitwasto

    http://www.cpan.org

  • trytogetdowneverythingIeverwantedtosayaboutPerl,itjustwasn'tpossible.First,becausePerlusagecoverssuchawidespreadontheCPAN,thereareready-mademodulesforfoldingDNAsequences,payingbillsonline,checkingtheweather,andplayingpoker.Andmorearebeingaddedeveryday,fasterthananyauthorcankeepup.Second,aswe'vementioned,becausePerlischanging.Idon'tknowwhatthenextbigadvanceinPerlwillbe;Icanonlytakeyouthroughsomeofthemoreimportanttechniquesandresourcesavailableatthemoment.

    Hopefully,though,attheendofthisbookyou'llhaveagoodideaofhowtousewhat'savailable,howyoucansaveyourselftimeandeffortbyusingPerlandthePerlresourcesavailabletogetyourjobdone,andhowyoucanbereadytouseandintegratewhateverdevelopmentscomedowntheline.

    InthewordsofLarryWall,mayyoudogoodmagicwithPerl!

  • Audience

    Ifyou'vereadLearningPerlandProgrammingPerlandwonderwheretogofromthere,thisbookisforyou.It'llhelpyouclimbtothenextlevelofPerlwisdom.Ifyou'vebeenprogramminginPerlforyears,you'llstillfindnumerouspracticaltoolsandtechniquestohelpyousolveyoureverydayproblems.

  • Contents

    Chapter1,AdvancedTechniques,introducesafewcommontricksadvancedPerlprogrammersusewithexamplesfrompopularPerlmodules.

    Chapter2,ParsingTechniques,coversparsingirregularorunstructureddatawithParse::RecDescentandParse::Yapp,plusparsingHTMLandXML.

    Chapter3,TemplatingTools,detailssomeofthemostcommontoolsfortemplatingandwhentousethem,includingformats,Text::Template,HTML::Template,HTML::Mason,andtheTemplateToolkit.

    Chapter4,Objects,Databases,andApplications,explainsvariouswaystoefficientlystoreandretrievecomplexdatausingobjectsaconceptcommonlycalledobject-relationalmapping.

    Chapter5,NaturalLanguageTools,showssomeofthewaysPerlcanmanipulatenaturallanguagedata:inflections,conversions,parsing,extraction,andBayesiananalysis.

    Chapter6,PerlandUnicode,reviewssomeoftheproblemsandsolutionstomakethemostofPerl'sUnicodesupport.

    Chapter7,POE,looksatthepopularPerlevent-basedenvironmentfortaskscheduling,multitasking,andnon-blockingI/Ocode.

    Chapter8,Testing,coverstheessentialsoftestingyourcode.

    Chapter9,InlineExtensions,talksabouthowtoextendPerlbywritingcodeinotherlanguages,usingtheInline::*modules.

    Chapter10,FunwithPerl,closesonalighternotewithafew

  • recreational(andeducational)usesofPerl.

  • ConventionsUsedinThisBook

    Thefollowingtypographicalconventionsareusedinthisbook:

    Plaintext

    Indicatesmenutitles,menuoptions,menubuttons,andkeyboardaccelerators(suchasAltandCtrl).

    Italic

    Indicatesnewterms,URLs,emailaddresses,filenames,fileextensions,pathnames,directories,andUnixutilities.

    Constantwidth

    Indicatescommands,options,switches,variables,attributes,keys,functions,classes,namespaces,methods,modules,parameters,values,XMLtags,HTMLtags,thecontentsoffiles,ortheoutputfromcommands.

    Constantwidthbold

    Showscommandsorothertextthatshouldbetypedliterallybytheuser.

    Constantwidthitalic

  • Showstextthatshouldbereplacedwithuser-suppliedvalues.

    Thisiconsignifiesatip,suggestion,orgeneralnote.

    Thisiconindicatesawarningorcaution.

  • UsingCodeExamples

    Thisbookisheretohelpyougetyourjobdone.Ingeneral,youmayusethecodeinthisbookinyourprogramsanddocumentation.Youdonotneedtocontactusforpermissionunlessyou'rereproducingasignificantportionofthecode.Forexample,writingaprogramthatusesseveralchunksofcodefromthisbookdoesnotrequirepermission.SellingordistributingaCD-ROMofexamplesfromO'Reillybooksdoesrequirepermission.Answeringaquestionbycitingthisbookandquotingexamplecodedoesnotrequirepermission.Incorporatingasignificantamountofexamplecodefromthisbookintoyourproduct'sdocumentationdoesrequirepermission.

    Weappreciate,butdonotrequire,attribution.Anattributionusuallyincludesthetitle,author,publisher,andISBN.Forexample:"AdvancedPerlProgramming,SecondEditionbySimonCozens.Copyright2005O'ReillyMedia,Inc.0-596-00456-7."

    Ifyoufeelyouruseofcodeexamplesfallsoutsidefairuseorthepermissiongivenabove,[email protected].

    mailto:[email protected]

  • We'dLiketoHearfromYou

    Pleaseaddresscommentsandquestionsconcerningthisbooktothepublisher:

    O'ReillyMedia1005GravensteinHighwayNorthSebastopol,CA95472(800)998-9938(intheUnitedStatesorCanada)(707)829-0515(internationalorlocal)(707)829-0104(fax)

    Wehaveawebpageforthisbook,wherewelisterrata,examples,andanyadditionalinformation.Youcanaccessthispageat:

    http://www.oreilly.com/catalog/advperl2/

    Tocommentorasktechnicalquestionsaboutthisbook,sendemailto:

    [email protected]

    Formoreinformationaboutourbooks,conferences,ResourceCenters,andtheO'ReillyNetwork,seeourwebsiteat:

    http://www.oreilly.com

    http://www.oreilly.com/catalog/advperl2/mailto:[email protected]://www.oreilly.com

  • Safari®Enabled

    WhenyouseeaSafariEnabledicononthecoverofyourfavoritetechnologybook,thatmeansthebookisavailableonlinethroughtheO'ReillyNetworkSafariBookshelf.

    Safarioffersasolutionthat'sbetterthane-books.It'savirtuallibrarythatletsyoueasilysearchthousandsoftoptechbooks,cutandpastecodesamples,downloadchapters,andfindquickanswerswhenyouneedthemostaccurate,currentinformation.Tryitforfreeathttp://safari.oreilly.com.

    http://safari.oreilly.com

  • Acknowledgments

    I'vealreadyblamedNatTorkingtonforcommissioningthisbook;Ishouldthankhimaswell.Asmuchaswritingabookcanbefun,thisonehasbeen.Ithascertainlybeenhelpedbymyeditors,beginningwithNatandTatianaApandi,andendingwiththehugelytalentedAllisonRandal,whohasalmostsingle-handedlycorrectedcode,collatedcomments,andconvertedmyramblingthoughtsintosomethingpublishable.TheproductionteamatO'Reillydeservesaspecialmention,ifonlybecauseofthetortureIputthemthroughinhavingachapteronUnicode.

    Allisonalsoroundedupagreatcrewofhighlyknowledgeablereviewers:mythankstoTonyBowden,PhilippeBruhat,SeanBurke,PiersCawley,NicholasClark,JamesDuncan,RafaelGarcia-Suarez,ThomasKlausner,TomMcTighe,CurtisPoe,chromatic,andAndyWardley.

    Andfinally,thereareafewpeopleI'dliketothankpersonally:thankstoHeatherLang,GraemeEverist,andJulietHumphreyforputtingupwithmelastyear,andtoJillFordandtherestofhergroupatAllNationsChristianCollegewhohavetoputupwithmenow.TonyBowdentaughtmemoreaboutgoodPerlprogrammingthaneitherofuswouldprobablyadmit,andSimonPonsonbytaughtmemoreabouteverythingelsethanherealises.ThankstoAlandJamieforbeingthere,andtoMalcolmandCarolineMacdonaldandNorikoandAkioKawamuraforlaunchingmeonthecurrentexcitingstageofmylife.

  • Chapter1.AdvancedTechniquesOnceyouhavereadtheCamelBook(ProgrammingPerl),oranyothergoodPerltutorial,youknowalmostallofthelanguage.Therearenosecretkeywords,noothermagicsigilsthatturnonPerl'sadvancedmodeandrevealhiddenfeatures.Inonesense,thisbookisnotgoingtotellyouanythingnewaboutthePerllanguage.

    WhatcanItellyou,then?Iusedtobeastudentofmusic.Musicisverysimple.Thereare12possiblenotesinthescaleofWesternmusic,althoughsomeofthemostwonderfulmelodiesintheworldonlyuse,atmost,eightofthem.Therearearoundfourdifferentdurationsofanoteusedincommonmelodies.Thereisn'tamassivemusicalvocabularytochoosefrom.AndmusichasbeenaroundagooddeallongerthanPerl.Iusedtowonderwhetherornotallthepossibledecentmelodieswouldsoonbefiguredout.SometimesIlistentotheTop10andthinkIwasprobablyrightbackthen.

    Butofcourseit'sabitmorecomplicatedthanthat.Newmusicisstillbeingproduced.Knowingallthenotesdoesnottellyouthebestwaytoputthemtogether.I'vesaidthattherearenosecretswitchestoturnonadvancedfeaturesinPerl,andthismeansthateveryonestartsonalevelplayingfield,injustthesamewaythatJohannSebastianBachandalittlekidplayingwithaxylophonehavepreciselythesamerawmaterialstoworkwith.ThekeytoproducingadvancedPerloradvancedmusicdependsontwothings:knowledgeoftechniquesandexperienceofwhatworksandwhatdoesn't.

    Theaimofthisbookistogiveyousomeofeachofthesethings.Ofcourse,nobookcanimpartexperience.Experienceissomethingthatmustbe,well,experienced.However,abooklikethiscanshowyousomeexistingsolutionsfromexperiencedPerlprogrammersandhowtousethemtosolvetheproblems

  • youmaybefacing.

    Ontheotherhand,abookcancertainlyteachtechniques,andinthischapterwe'regoingtolookatthethreemajorclassesofadvancedprogrammingtechniquesinPerl.First,we'lllookatintrospection:programslookingatprograms,figuringouthowtheywork,andchangingthem.ForPerlthisinvolvesmanipulatingthesymboltableespeciallyatruntime,playingwiththebehaviorofbuilt-infunctionsandusingAUTOLOADtointroducenewsubroutinesandcontrolbehaviorofsubroutinedispatchdynamically.We'llalsobrieflylookatbytecodeintrospection,whichistheabilitytoinspectsomeofthepropertiesofthePerlbytecodetreetodeterminepropertiesoftheprogram.

    Thesecondideawe'lllookatistheclassmodel.Writingobject-orientedprogramsandmodulesissometimesregardedasadvancedPerl,butIwouldcategorizeitasintermediate.Asthisisanadvancedbook,we'regoingtolearnhowtosubvertPerl'sobject-orientedmodeltosuitourgoals.

    Finally,there'sthetechniqueofwhatIcallunexpectedcodecodethatrunsinplacesyoumightnotexpectitto.Thismeansrunningcodeinplaceofoperatorsinthecaseofoverloading,someadvancedusesoftying,andcontrollingwhencoderunsusingnamedblocksandeval.

    Thesethreeareas,togetherwiththespecialcaseofPerlXSprogrammingwhichwe'lllookatinChapter9onInlinedelineatethefundamentaltechniquesfromwhichalladvancedusesofPerlaremadeup.

  • 1.1.Introspection

    First,though,introspection.Theseintrospectiontechniquesappeartimeandtimeagaininadvancedmodulesthroughoutthebook.Assuch,theycanberegardedasthemostfundamentaloftheadvancedtechniqueseverythingelsewillbuildontheseideas.

    1.1.1.PreparatoryWork:FunwithGlobs

    GlobsareoneofthemostmisunderstoodpartsofthePerllanguage,butatthesametime,oneofthemostfundamental.Thisisashame,becauseaglobisarelativelysimpleconcept.

    WhenyouaccessanyglobalvariableinPerlthatis,anyvariablethathasnotbeendeclaredwithmytheperlinterpreterlooksupthevariablenameinthesymboltable.Fornow,we'llconsiderthesymboltabletobeamappingbetweenavariable'snameandsomestorageforitsvalue,asinFigure1-1.

    Notethatwesaythatthesymboltablemapstostorageforthevalue.Introductoryprogrammingtextsshouldtellyouthatavariableisessentiallyaboxinwhichyoucangetandsetavalue.Oncewe'velookedup$a,weknowwheretheboxis,andwecangetandsetthevaluesdirectly.InPerlterms,thesymboltablemapstoareferenceto$a.

    Figure1-1.Consultingthesymboltable,take1

  • Youmayhavenoticedthatasymboltableissomethingthatmapsnamestostorage,whichsoundsalotlikeaPerlhash.Infact,you'dbeaheadofthegame,sincethePerlsymboltableisindeedimplementedusinganordinaryPerlhash.Youmayalsohavenoticed,however,thatthereareseveralthingscalledainPerl,including$a,@a,%a,&a,thefilehandlea,andthedirectoryhandlea.

    Thisiswheretheglobcomesin.Thesymboltablemapsanamelikeatoaglob,whichisastructureholdingreferencestoallthevariablescalleda,asinFigure1-2.

    Figure1-2.Consultingthesymboltable,take2

  • Asyoucansee,variablelook-upisdoneintwostages:first,findingtheappropriateglobinthesymboltable;second,findingtheappropriatepartoftheglob.Thisgivesusareference,andassigningittoavariableorgettingitsvalueisdonethroughthisreference.

    1.1.1.1Aliasing

    Thisdisconnectbetweenthenamelook-upandthereferencelook-upenablesustoaliastwonamestogether.First,wegetholdoftheirglobsusingthe*namesyntax,andthensimplyassignoneglobtoanother,asinFigure1-3.

    Figure1-3.Aliasingviaglobassignment

  • We'veassignedb'ssymboltableentrytopointtoa'sglob.Nowanytimewelookupavariablelike%b,thefirststagelook-uptakesusfromthesymboltabletoa'sglob,andreturnsusareferenceto%a.

    ThemostcommonapplicationofthisgeneralideaisintheExportermodule.IfIhaveamodulelikeso:

    packageSome::Module;usebase'Exporter';our@EXPORT=qw(useful);

    subuseful{42}

    thenExporterisresponsibleforgettingtheusefulsubroutine

  • fromtheSome::Modulepackagetothecaller'spackage.Wecouldmockourownexporterusingglobassignments,likethis:

    packageSome::Module;subuseful{42}

    subimport{nostrict'refs';*{caller()."::useful"}=*useful;}

    Rememberthatimportiscalledwhenamoduleisused.Wegetthenameofthecallingpackageusingcallerandconstructthenameoftheglobwe'regoingtoreplaceforinstance,main::useful.Weuseasymbolicreferencetoturntheglob'sname,whichisastring,intotheglobitself.Thisisjustthesameasthesymbolicreferenceinthisfamiliarbutunpleasantpieceofcode:

    $answer=42;$variable="answer";

    print${$variable};

    Ifwewereusingtherecommendedstrictpragma,ourprogramwoulddieimmediatelyandwithgoodreason,sincesymbolicreferencesshouldonlybeusedbypeoplewhoknowwhatthey'redoing.Weusenostrict'refs';totellPerlthatwe'replanningondoinggoodmagicwithsymbolicreferences.

    ManyadvancedusesofPerlneedtodosomeofthethingsthatstrictpreventstheuninitiatedfromdoing.AsaninitiatedPerluser,youwilloccasionallyhavetoturnstricturesoff.Thisisn'tsomethingtotakelightly,butdon'tbeafraidofit;strictisausefulservant,butabadmaster,andshouldbetreatedassuch.

  • Nowthatwehavethe*main::usefulglob,wecanassignittopointtothe*usefulglobinthecurrentSome::Modulepackage.Nowallreferencestouseful()inthemainpackagewillresolveto&Some::Module::useful.

    Thatisagoodfirstapproximationofanexporter,butweneedtoknowmore.

    1.1.1.2Accessingpartsofaglob

    Withournaiveimportroutineabove,wealiasedmain::usefulbyassigningoneglobtoanother.However,thishassomeunfortunatesideeffects:

    useSome::Module;our$useful="Somehandystring";

    print$Some::Module::useful;

    Sincewe'vealiasedtwoentireglobstogether,anychangestoanyofthevariablesintheusefulglobwillbereflectedintheotherpackage.IfSome::Modulehasamoresubstantialroutinethatusesitsown$useful,thenallhellwillbreakloose.

    Allwewanttodoistoputasubroutineintothe&usefulelementofthe*main::usefulglob.Ifwewereexportingascalaroranarray,wecouldassignacopyofitsvaluetotheglobbysaying:

    ${caller()."::useful"}=$useful;@{caller()."::useful"}=@useful;

  • However,ifwetrytosay:

    &{caller()."::useful"}=&useful;

    theneverythinggoeswrong.The&usefulontherightcallstheusefulsubroutineandreturnsthevalue42,andtherestofthelinewantstocallacurrentlynon-existantsubroutineandassignitsreturnvaluethenumber42.Thisisn'tgoingtowork.

    Thankfully,Perlprovidesuswithawayaroundthis.Wedon'thavetoassigntheentireglobatonce.Wejustassignareferencetotheglob,andPerlworksoutwhattypeofreferenceitisandstoresitintheappropriatepart,asinFigure1-4.

    Figure1-4.Assigningtoaglob'sarraypart

  • Noticethatthisisnotthesameas@a=@b;itisrealaliasing.Anychangesto@bwillbeseenin@a,andviceversa:

    @b=(1,2,3,4);*a=\@b;

    push@b,5;print@a;#12345

    #However:$a="Bye"$b="Hellothere!";print$a;#Bye

  • Althoughthe@aarrayisaliasedbyhavingitsreferenceconnectedtothereferenceusedtolocatethe@barray,therestofthe*aglobisuntouched;changesin$bdonotaffect$a.

    Youcanwritetoallpartsofaglob,justbyprovidingtheappropriatereferences:

    *a=\"Hello";*a=[1,2,3];*a={red=>"rouge",blue=>"bleu"};

    print$a;#Helloprint$a[1];#2print$a{"red"};#rouge

    Thethreeassignmentsmaylookliketheyarereplacingeachother,buteachwritestoadifferentpartoftheglobdependingontheappropriatereferencetype.Iftheassignedvalueisareferencetoaconstant,thenthevariable'svalueisunchangeable.

    *a=\1234;$a=10;#Modificationofaread-onlyvalueattempted

    Nowwecometoasolutiontoourexporterproblem;wewanttoalias&main::usefuland&Some::Module::useful,butnootherpartsoftheusefulglob.Wedothisbyassigningareferenceto&Some::Module::usefulto*main::useful:

    subuseful{42}subimport{

  • nostrict'refs';*{caller()."::useful"}=\&useful;}

    ThisissimilartohowtheExportermoduleworks;theheartofExporteristhissegmentofcodeinExporter::Heavy::heavy_export:

    foreach$sym(@imports){#shortcutforthecommoncaseofnotypecharacter(*{"${callpkg}::$sym"}=\&{"${pkg}::$sym"},next)unless$sym=~s/^(\W)//;

    $type=$1;*{"${callpkg}::$sym"}=$typeeq'&'?\&{"${pkg}::$sym"}:$typeeq'$'?\${"${pkg}::$sym"}:$typeeq'@'?\@{"${pkg}::$sym"}:$typeeq'%'?\%{"${pkg}::$sym"}:$typeeq'*'?*{"${pkg}::$sym"}:do{requireCarp;Carp::croak("Can'texportsymbol:$type$sym")};}

    Thishasalistofimports,whichhaveeithercomefromtheuseSome::Module'...';declarationorfromSome::Module'[email protected],ortheymaynot;iftheydonot,suchaswhenyousayuseCarp'croak';,thentheyrefertosubroutines.

    Inouroriginalcase,wehadset@EXPORTto("useful").First,Exporterchecksforatypesigilandremovesit:

  • (*{"${callpkg}::$sym"}=\&{"${pkg}::$sym"},next)unless$sym=~s/^(\W)//;

    Because$symis"useful"withnotypesigiltherestofthestatementexecuteswitharesultsimilarto:

    *{"${callpkg}::$sym"}=\&{"${pkg}::$sym"};next;

    Pluggingintheappropriatevalues,thisisverymuchlikeourmockexporter:

    *{$callpkg."::useful"}=\&{"Some::Module::useful"};

    Ontheotherhand,wherethereisatypesigiltheexporterconstructsthereferenceandassignstherelevantpartoftheglob:

    *{"${callpkg}::$sym"}=$typeeq'&'?\&{"${pkg}::$sym"}:$typeeq'$'?\${"${pkg}::$sym"}:$typeeq'@'?\@{"${pkg}::$sym"}:$typeeq'%'?\%{"${pkg}::$sym"}:$typeeq'*'?*{"${pkg}::$sym"}:do{requireCarp;Carp::croak("Can'texportsymbol:$type$sym")};

  • AccessingGlobElements

    The*glob=...syntaxobviouslyonlyworksforassigningreferencestotheappropriatepartoftheglob.Ifyouwanttoaccesstheindividualreferences,youcantreattheglobitselfasaveryrestrictedhash:*a{ARRAY}isthesameas\@a,and*a{SCALAR}isthesameas\$a.TheothermagicnamesyoucanuseareHASH,IO,CODE,FORMAT,andGLOB,forthereferencetotheglobitself.TherearealsothereallytrickyPACKAGEandNAMEelements,whichtellyouwheretheglobcamefrom.

    Thesedays,accessingglobsbyhashkeysisreallyonlyusefulforretrievingtheIOelement.However,we'llseeanexamplelaterofhowitcanbeusedtoworkwithglobreferencesratherthanglobsdirectly.

    1.1.1.3Creatingsubroutineswithglobassignment

    OnecommonuseofthealiasingtechniqueinadvancedPerlistheassignmentofanonymoussubroutinereferences,andespeciallyclosures,toaglob.Forinstance,there'samodulecalledData::BT::PhoneBillthatretrievesdatafromBritishTelecom'sonlinephonebillservice.Themoduletakescomma-separatedlinesofinformationaboutacallandturnsthemintoobjects.Anolderversionofthemodulesplitthelineintoanarrayandblessedthearrayasanobject,providingabunchofread-onlyaccessorsfordataaboutacall:

    packageData::BT::PhoneBill::_Call;subnew{my($class,@data)=@_;bless\@data,$class;}

    subinstallation{shift->[0]}subline{shift->[1]}...

  • Closures

    Aclosureisacodeblockthatcapturestheenvironmentwhereit'sdefinedspecifically,anylexicalvariablestheblockusesthatweredefinedinanouterscope.Thefollowingexampledelimitsalexicalscope,definesalexicalvariable$seqwithinthescope,thendefinesasubroutinesequencethatusesthelexicalvariable.

    {my$seq=3;subsequence{$seq+=3}}

    print$seq;#outofscope

    printsequence;#prints6printsequence;#prints9

    Printing$seqaftertheblockdoesn'twork,becausethelexicalvariableisoutofscope(it'llgiveyouanerrorunderusestrict.However,thesequencesubroutinecanstillaccessthevariabletoincrementandreturnitsvalue,becausetheclosure{$seq+=3}capturedthelexicalvariable$seq.

    Seeperlfaq7andperlrefformoredetailsonclosures.

    Ofcourse,theinevitablehappened:BTaddedanewcolumnatthebeginning,andalloftheaccessorshadtoshiftdown:

    subtype{shift->[0]}subinstallation{shift->[1]}subline{shift->[2]}

    Clearlythiswasn'taseasytomaintainasitshouldbe.Thefirststepwastorewritetheconstructortouseahashinsteadofanarrayasthebasisfortheobject:

  • our@fields=qw(typeinstallationlinechargecard_datetimedestination_number_durationrebate_cost);

    subnew{my($class,@data)=@_;bless{map{$fields[$_]=>$data[$_]}0..$#fields}=>$class;}

    Thiscodemapstypetothefirstelementof@data,installationtothesecond,andsoon.Nowwehavetorewritealltheaccessors:

    subtype{shift->{type}}subinstallation{shift->{installation}}subline{shift->{line}}

    Thisisanimprovement,butifBTaddsanothercolumncalledfriends_and_family_discount,thenIhavetotypefriends_and_family_discountthreetimes:onceinthe@fieldsarray,onceinthenameofthesubroutine,andonceinthenameofthehashelement.

    It'sacardinallawofprogrammingthatyoushouldneverhavetowritethesamethingmorethanonce.Itdoesn'ttakemuchtoautomaticallyconstructalltheaccessorsfromthe@fieldsarray:

    formy$f(@fields){nostrict'refs';*$f=sub{shift->{$f}};}

  • Thiscreatesanewsubroutineintheglobforeachofthefieldsinthearrayequivalentto*type=sub{shift->{type}}.Becausewe'reusingaclosureon$f,eachaccessor"remembers"whichfieldit'stheaccessorfor,eventhoughthe$fvariableisoutofscopeoncetheloopiscomplete.

    CreatinganewsubroutinebyassigningaclosuretoaglobisaparticularlycommontrickinadvancedPerlusage.

    1.1.2.AUTOLOAD

    Thereis,ofcourse,asimplerwaytoachievetheaccessortrick.Insteadofdefiningeachaccessorindividually,wecandefineasingleroutinethatexecutesonanycalltoanundefinedsubroutine.InPerl,thistakestheformoftheAUTOLOADsubroutineanordinarysubroutinewiththemagicnameAUTOLOAD:

    subAUTOLOAD{print"Idon'tknowwhatyouwantmetodo!\n";}

    yow();

    InsteadofdyingwithUndefinedsubroutine&yowcalled,PerltriestheAUTOLOADsubroutineandcallsthatinstead.

    TomakethisusefulintheData::BT::PhoneBillcase,weneedtoknowwhichsubroutinewasactuallycalled.Thankfully,Perlmakesthisinformationavailabletousthroughthe$AUTOLOADvariable:

  • subAUTOLOAD{my$self=shift;if($AUTOLOAD=~/.*::(.*)/){$self->{$1}}

    Themiddlelinehereisacommontrickforturningafullyqualifiedvariablenameintoalocallyqualifiedname.Acallto$call->typewillset$AUTOLOADtoData::BT::PhoneBill::_Call::type.Sincewewanteverythingafterthelast::,weusearegularexpressiontoextracttherelevantpart.Thiscanthenbeusedasthenameofahashelement.

    WemaywanttohelpPerloutalittleandcreatethesubroutineontheflysoitdoesn'tneedtouseAUTOLOADthenexttimetypeiscalled.Wecandothisbyassigningaclosuretoaglobasbefore:

    subAUTOLOAD{if($AUTOLOAD=~/.*::(.*)/){my$element=$1;*$AUTOLOAD=sub{shift->{$element}};goto&$AUTOLOAD;}

    Thistime,wewriteintothesymboltable,constructinganewsubroutinewherePerlexpectedtofindouraccessorinthefirstplace.Byusingaclosureon$element,weensurethateachaccessorpointstotherighthashelement.Finally,oncethenewsubroutineissetup,wecanusegoto&subnametotryagain,callingthenewlycreatedData::BT::PhoneBill::_Call::typemethodwiththesameparametersasbefore.Thenexttimethesamesubroutineiscalled,itwillbefoundinthesymboltablesincewe'vejustcreateditandwewon'tgothroughAUTOLOADagain.

  • gotoLABELandgoto&subnamearetwocompletelydifferentoperations,unfortunatelywiththesamename.Thefirstisgenerallydiscouraged,butthesecondhasnosuchstigmaattachedtoit.Itisidenticaltosubname(@_)butwithoneimportantdifference:thecurrentstackframeisobliteratedandreplacedwiththenewsubroutine.Ifwehadused$AUTOLOAD->(@_)inourexample,andsomeonehadtoldadebuggertosetabreakpointinsideData::BT::PhoneBill::_Call::type,theywouldseethisbacktrace:

    .=Data::BT::PhoneBill::_Call::type....=Data::BT::PhoneBill::_Call::AUTOLOAD....=main::process_call

    Inotherwords,we'veexposedtheplumbing,ifonlyforthefirstcalltotype.Ifweusegoto&$AUTOLOAD,however,theAUTOLOADstackframeisobliteratedandreplaceddirectlybythetypeframe:

    .=Data::BT::PhoneBill::_Call::type....=main::process_call

    It'salsoconcievablethat,becausethereisnothirdstackframeorcall-returnlinkagetohandle,thegototechniqueismarginallymoreefficient.

    TherearetwothingsthateveryuserofAUTOLOADneedstoknow.ThefirstisDESTROY.IfyourAUTOLOADsubroutinedoesanythingmagical,youneedtomakesurethatitcheckstoseeifit'sbeingcalledinplaceofanobject'sDESTROYclean-upmethod.Onecommonidiomtodothisisreturnif$1eq"DESTROY".AnotheristodefineanemptyDESTROYmethodintheclass:subDESTROY{}.

    ThesecondimportantthingaboutAUTOLOADisthatyoucanneitherdeclinenorchainAUTOLOADs.IfanAUTOLOADsubroutinehasbeencalled,thenthemissingsubroutinehasbeendeemedtobedealtwith.Ifyouwanttorethrowtheundefined-subroutineerror,youmustdosomanually.Forinstance,let'slimitourData::BT::PhoneBill::_Call::AUTOLOADmethodtoonlydealwithrealelementsofthehash,andnotany

  • randomrubbishortypothatcomesourway:

    useCarpqw(croak);...subAUTOLOAD{my$self=shift;if($AUTOLOAD=~/.*::(.*)/andexists$self->{$1}){return$self->{$1}}croak"Undefinedsubroutine&$AUTOLOADcalled";}

    1.1.3.COREandCORE::GLOBAL

    TwoofthemostmisunderstoodpiecesofPerlarcanaaretheCOREandCORE::GLOBALpackages.Thesetwopackageshavetodowiththereplacementofbuilt-infunctions.Youcanoverrideabuilt-inbyimportingthenewfunctionintothecaller'snamespace,butitisnotassimpleasdefininganewfunction.

    Forinstance,tooverridetheglobfunctioninthecurrentpackagewithoneusingregularexpressionsyntax,weeitherhavetowriteamoduleorusethesubspragmatodeclarethatwewillbeusingourownversionoftheglobtypeglob:

    usesubsqw(glob);

    subglob{my$pattern=shift;local*DIR;opendirDIR,"."ordie$!;returngrep/$pattern/,readdirDIR;}

  • ThisreplacesPerl'sbuilt-inglobfunctionforthedurationofthepackage:

    print"$_\n"forglob("^c.*\\.xml");

    ch01.xmlch02.xml...

    However,sincethesyntaxforthegloboperatorisinternallyresolvedtoacalltoglob,wecouldjustaswellsay:

    print"$_\n"for;

    Neitherofthesewouldworkwithouttheusesubsline,whichpreparesthePerlparserforseeingaprivateversionoftheglobfunction.

    Ifyou'rewritingamodulethatprovidesthisfunctionality,alliswellandgood.Justputthenameofthebuilt-infunctionin@EXPORT,andtheExporterwilldotherest.

    WheredoCORE::andCORE::GLOBAL::comein,then?First,ifwe'reinapackagethathasanoverridenglobandweneedtogetatPerl'scoreglob,wecanuseCORE::glob()todoso:

    @files=;#Newregexpglob@files=CORE::glob("ch*xml");#Oldshell-styleglob

  • CORE::alwaysreferstothebuilt-infunctions.Isay"refersto"asausefulfictionCORE::merelyqualifiestothePerlparserwhichglobyoumean.Perl'sbuilt-infunctionsdon'treallyliveinthesymboltable;they'renotsubroutines,andyoucan'ttakereferencestothem.TherecanbeapackagecalledCORE,andyoucanhappilysaythingslike$CORE::a=1.ButCORE::followedbyafunctionnameisspecial.

    Becauseofthis,wecanrewriteourregexp-globfunctionlikeso:

    packageRegexp::Glob;usebase'Exporter';our@EXPORT=qw(glob);

    subglob{my$pattern=shift;returngrep/$pattern/,CORE::glob("*");}1;

    There'saslightproblemwiththis.Importingasubroutineintoapackageonlyaffectsthepackageinquestion.Anyotherpackagesintheprogramwillstillcallthebuilt-inglob:

    useRegexp::Glob;@files=glob("ch.*xml");#Newregexpglob

    packageElsewhere;@files=glob("ch.*xml");#Oldshell-styleglob

    Ourothermagicpackage,CORE::GLOBAL::,takescareofthisproblem.Bywritingasubroutinereferenceinto

  • CORE::GLOBAL::glob,wecanreplacetheglobfunctionthroughoutthewholeprogram:

    packageRegexp::Glob;

    *CORE::GLOBAL::glob=sub{my$pattern=shift;local*DIR;opendirDIR,"."ordie$!;returngrep/$pattern/,readdirDIR;};

    1;

    Nowitdoesn'tmatterifwechangepackagesthegloboperatoranditsaliaswillbeourmodifiedversion.

    Sothereyouhaveit:CORE::isapseudo-packageusedonlytounambiguouslyrefertothebuilt-inversionofafunction.CORE::GLOBAL::isarealpackageinwhichyoucanputreplacementsforthebuilt-inversionofafunctionacrossallnamespaces.

    1.1.4.CaseStudy:Hook::LexWrap

    Hook::LexWrapisamodulethatallowsyoutoaddwrappersaroundsubroutinesthatis,toaddcodetoexecutebeforeorafterawrappedroutine.Forinstance,here'saverysimpleuseofLexWrapfordebuggingpurposes:

    wrap'my_routine',pre=>sub{print"Abouttorunmy_routinewitharguments@_"},post=>sub{print"Donewithmy_routine";}

  • ThemainsellingpointofHook::LexWrapissummarizedinthemodule'sdocumentation:

    Unlikeothermodulesthatprovidethiscapacity(e.g.Hook::PreAndPostandHook::WrapSub),Hook::LexWrapimplementswrappersinsuchawaythatthestandard"caller"functionworkscorrectlywithinthewrappedsubroutine.

    It'seasyenoughtofoolcallerifyouonlyhavepre-hooks;youreplacethesubroutineinquestionwithanintermediateroutinethatdoesthemoralequivalentof:

    submy_routine{call_pre_hook();goto&Real::my_routine;}

    Aswesawabove,thegoto&subnameformobliteratesmy_routine'sstackframe,soitlookstotheoutsideworldasthoughmy_routinehasbeencontrolleddirectly.

    Butwithpost-hooksit'sabitmoredifficult;youcan'tusethegoto&trick.Afterthesubroutineiscalled,youwanttogoontodosomethingelse,butyou'veobliteratedthesubroutinethatwasgoingtocallthepost-hook.

    SohowdoesHook::LexWrapensurethatthestandardcallerfunctionworks?Well,itdoesn't;itactuallyprovidesitsown,makingsureyoudon'tusethestandardcallerfunctionatall.

    Hook::LexWrapdoesitsworkintwoparts.Thefirstpartassignsaclosuretothesubroutine'sglob,replacingitwithanimposterthatarrangesforthehookstobecalled,andthesecond

  • providesacustomCORE::GLOBAL::caller.Let'sfirstlookatthecustomcaller:

    *CORE::GLOBAL::caller=sub{my($height)=($_[0]||0);my$i=1;my$name_cache;while(1){my@caller=CORE::caller($i++)orreturn;$caller[3]=$name_cacheif$name_cache;$name_cache=$caller[0]eq'Hook::LexWrap'?$caller[3]:'';nextif$name_cache||$height--!=0;returnwantarray?@_?@caller:@caller[0..2]:$caller[0];}};

    Thebasicideaofthisisthatwewanttoemulatecaller,butifweseeacallintheHook::LexWrapnamespace,thenweignoreitandmoveontothenextstackframe.Sowefirstworkoutthenumberofframestobackupthestack,defaultingtozero.However,sinceCORE::GLOBAL::calleritselfcountsasastackframe,weneedtostartthecountinginternallyfromone.

    Next,wedoaslightbitoftrickery.OurimpostersubroutineiscompiledintheHook::LexWrapnamespace,butithasthenameoftheoriginalsubroutineit'semulating.SoifweseesomethinginHook::LexWrap,westoreitssubroutinenameawayin$name_cacheandthenskipoverit,withoutdecrementing$height.IfthethingweseeisnotinHook::LexWrap,butcomesdirectlyaftersomethingthatis,wereplaceitssubroutinenamewiththeonefromthecache.Finally,once$heightgetsdowntozero,wecanreturntheappropriatebitsofthe@callerarray.

    Bydoingthis,we'vecreatedourownreplacementcaller

  • function,whichhidestheexistenceofstackframesintheHook::LexWrappackage,butinallotherwaysbehavesthesameastheoriginalcaller.Nowlet'sseehowourimpostersubroutineisbuiltup.

    Mostofthewraproutineisactuallyjustaboutargumentchecking,contextpropagation,andreturnvaluehandling;wecanslimitdowntothefollowingforourpurposes:

    subwrap(*@){my($typeglob,%wrapper)=@_;$typeglob=(ref$typeglob||$typeglob=~/::/)?$typeglob:caller()."::$typeglob";my$original=ref$typeglobeq'CODE'?$typeglob:*$typeglob{CODE};$imposter=sub{$wrapper{pre}->(@_)if$wrapper{pre};my@return=&$original;$wrapper{post}->(@_)if$wrapper{post};return@return;};*{$typeglob}=$imposter;}

    Tomakeourimposterwork,weneedtoknowtwothings:thecodewe'regoingtorunandwhereit'sgoingtoliveinthesymboltable.Wemighthavebeeneitherhandedatypeglob(thetrickycase)orthenameofasubroutineasastring.Ifwehaveastring,thecodelookslikethis:

    $typeglob=$typeglob=~/::/?$typeglob:caller()."::$typeglob";my$original=*$typeglob{CODE};

  • Thefirstlineensuresthatthenowbadlynamed$typeglobisfullyqualified;ifnot,it'sprefixedwiththecallingpackage.Thesecondlineturnsthestringintoasubroutinereferenceusingtheglobreferencesyntax.

    Inthecasewherewe'rehandedagloblike*to_wrap,wehavetousesomemagic.Thewrapsubroutinehastheprototype(*$);hereiswhattheperlsubdocumentationhastosayabout*prototypes:

    A"*"allowsthesubroutinetoacceptabareword,constant,scalarexpression,typeglob,orreferencetoatypeglobinthatslot.Thevaluewillbeavailabletothesubroutineeitherasasimplescalaror(inthelattertwocases)asareferencetothetypeglob.

    Soif$typeglobturnsouttobeatypeglob,it'sconvertedintoaglobreference,whichallowsustousethesamesyntaxtowriteintothecodepartoftheglob.

    The$imposterclosureissimpleenoughitcallsthepre-hook,thentheoriginalsubroutine,thenthepost-hook.Weknowwhereitshouldgointhesymboltable,andsoweredefinetheoriginalsubroutinewithournewone.

    Sothisrelativelycomplexmodulereliespurelyontwotricksthatwehavealreadyexamined:first,globallyoverridingabuilt-infunctionusingCORE::GLOBAL::,andsecond,savingawayasubroutinereferenceandthenglobassigninganewsubroutinethatwrapsaroundtheoriginal.

    1.1.5.IntrospectionwithB

    There'sonefinalcategoryofintrospectionasappliedtoPerl

  • programs:inspectingtheunderlyingbytecodeoftheprogramitself.

    Whentheperlinterpreterishandedsomecode,ittranslatesitintoaninternalcode,similartootherbytecode-compiledlanguagessuchasJava.However,inthecaseofPerl,eachoperationisrepresentedasthenodeonatree,andtheargumentstoeachoperationarethatnode'schildren.

    Forinstance,fromtheveryshortsubroutine:

    subsum_input{my$a=;print$a+1;}

    PerlproducesthetreeinFigure1-5.

    Figure1-5.Bytecodetree

  • TheBmoduleprovidesfunctionsthatexposethenodesofthistreeasobjectsinPerlitself.Youcanexamineandinsomecasesmodifytheparsedrepresentationofarunningprogram.

    Thereareseveralobviousapplicationsforthis.Forinstance,ifyoucanserializethedatainthetreetodisk,andfindawaytoloaditupagain,youcanstoreaPerlprogramasbytecode.TheB::BytecodeandByteLoadermodulesdojustthis.

    ThosethinkingthattheycanusethistodistributePerlcodeinanobfuscatedbinaryformatneedtoreadontooursecondapplication:youcanusethetreetoreconstructtheoriginalPerlcode(orsomethingquitelikeit)fromthebytecode,byessentiallyperformingthecompilationstageinreverse.TheB::Deparsemoduledoesthis,anditcantellusalotabouthowPerlunderstandsdifferentcode:

    %perl-MO=Deparse-n-e'/^#/||print'

    LINE:while(defined($_=)){print$_unless/^#/;}

    Thisshowsuswhat'sreallygoingonwhenthe-nflagisused,theinferred$_inprint,andthelogicalequivalenceofX||YandYunlessX.[*](Incidentally,theOmoduleisadriverthatallowsspecifiedB::*modulestodowhattheywanttotheparsedsourcecode.)

    [*]The-MO=DeparseflagisequivalenttouseOqw(Deparse);.

    Tounderstandhowthesemodulesdotheirwork,youneedtoknowalittleaboutthePerlvirtualmachine.LikealmostallVM

  • technologies,Perl5isasoftwareCPUthatexecutesastreamofinstructions.Manyoftheseoperationswillinvolveputtingvaluesonortakingthemoffastack;unlikearealCPU,whichusesregisterstostoreintermediateresults,mostsoftwareCPUsuseastackmodel.

    Perlcodeenterstheperlinterpreter,getstranslatedintothesyntaxtreestructurewesawbefore,andisoptimized.Partoftheoptimizationprocessinvolvesdeterminingaroutethroughthetreebyjoiningtheopstogetherinalinkedlist.InFigure1-6,therouteisshownasadottedline.

    Figure1-6.Optimizedbytecodetree

    Eachnodeonthetreerepresentsanoperationtobedone:weneedtoenteranewlexicalscope(thefile);setupinternaldatastructuresforanewstatement,suchassettingthelinenumberforerrorreporting;findwhere$alivesandputthatonthestack;findwhatfilehandlerefersto;readalinefromthat

  • filehandleandputthatonthestack;assignthetopvalueonthestack(theresult)tothenextvaluedown(thevariablestorage);andsoon.

    Thereareseveraldifferentkindsofoperators,classifiedbyhowtheymanipulatethestack.Forinstance,therearethebinaryoperatorssuchasaddwhichtaketwovaluesoffthestackandreturnanewvalue.readlineisaunaryoperator;ittakesafilehandlefromthestackandputsavaluebackon.Listoperatorslikeprinttakeanumberofvaluesoffthestack,andthenullarypushmarkoperatorisresponsibleforputtingaspecialmarkvalueonthestacktotellprintwheretostop.

    TheBmodulerepresentsallthesedifferentkindsofoperatorsassubclassesoftheB::OPclass,andtheseclassescontainmethodsallowingustogetthenextmoduleintheexecutionorder,thechildrenofanoperator,andsoon.

    SimilarclassesexisttorepresentPerlscalar,array,hash,filehandle,andothervalues.WecanconvertanyreferencetoaB::objectusingthesvref_2objectfunction:

    useB;

    my$subref=sub{my$a=;print$a+1;};

    my$b=B::svref_2object($subref);#B::CVobject

    ThisB::CVobjectrepresentsthesubroutinereferencethatPerlcan,forinstance,storeinthesymboltable.Tolookattheoptreeinsidethisobject,wecalltheSTARTmethodtogetthefirstnodeinthelinkedlistofthetree'sexecutionorder,ortheROOTmethodtofindtherootofthetree.

  • Dependingonwhichopwehave,therearetwowaystonavigatetheoptree.Towalkthetreeinexecutionorder,youcanjustfollowthechainofnextpointers:

    my$op=$b->START;

    do{printB::class($op).":".$op->name."(".$op->desc.")\n";}while$op=$op->nextandnot$op->isa("B::NULL");

    TheclasssubroutinejustconvertsbetweenaPerlclassnamelikeB::COPandtheunderlyingCequivalent,COP;thenamemethodreturnsthehuman-readablenameoftheoperation,anddescgivesitsdescriptionasitwouldappearinanerrormessage.Weneedtocheckthattheopisn'taB::NULL,becausethenextpointerofthefinalopwillbeaCnullpointer,whichBhandilyconvertstoaPerlobjectwithnomethods.Thisgivesusadumpofthesubroutine'soperationslikeso:

    COP:nextstate(nextstatement)OP:padsv(privatevariable)PADOP:gv(globvalue)UNOP:readline()COP:nextstate(nextstatement)OP:pushmark(pushmark)OP:padsv(privatevariable)SVOP:const(constantitem)BINOP:add(addition(+))LISTOP:print(print)UNOP:leavesub(subroutineexit)

    Asyoucansee,thisisthenaturalorderfortheoperationsin

  • thesubroutine.Ifyouwanttoexaminethetreeintop-downorder,somethingthatisusefulforcreatingthingslikeB::DeparseoralteringthegeneratedbytecodetreewithtrickslikeoptimizerandB::Generate,thentheeasiestwayistousetheB::Utilsmodule.Thisprovidesanumberofhandyfunctions,includingwalkoptree_simple.Thisallowsyoutosetacallbackandvisiteveryopinatree:

    useB::Utilsqw(walkoptree_simple);...my$op=$b->ROOT;

    walkoptree_simple($op,sub{$cop=shift;printB::class($cop).":".$cop->name."(".$cop->desc.")\n";});

    NotethatthistimewestartfromtheROOTofthetreeinsteadoftheSTART;traversingtheoptreeinthisordergivesusthefollowinglistofoperations:

    UNOP:leavesub(subroutineexit)LISTOP:lineseq(linesequence)COP:nextstate(nextstatement)UNOP:null(nulloperation)OP:padsv(privatevariable)UNOP:readline()PADOP:gv(globvalue)COP:nextstate(nextstatement)LISTOP:print(print)...

    WorkingwithPerlattheoplevelrequiresagreatdealof

  • practiceandknowledgeofthePerlinternals,butcanleadtoextremelyusefultoolslikeDevel::Cover,anop-levelprofilerandcoverageanalysistool.

  • 1.2.MessingwiththeClassModel

    Perl'sstyleofobjectorientationisoftenmaligned,butitssheersimplicityallowstheadvancedPerlprogrammertoextendPerl'sbehaviorininterestingandsometimesstartlingways.BecauseallthedetailsofPerl'sOOmodelhappenatruntimeandintheopenusinganordinarypackagevariable(@INC)tohandleinheritance,forinstance,orusingthesymboltablesformethoddispatchwecanfiddlewithalmosteveryaspectofit.

    Inthissectionwe'llseesometechniquesspecifictoplayingwiththeclassmodel,butwewillalsoexaminehowtoapplythetechniqueswealreadyknowtodistortPerl'ssenseofOO.

    1.2.1.UNIVERSAL

    Inalmostallclass-basedOOlanguages,allobjectsderivefromacommonclass,sometimescalledObject.Perldoesn'tquitehavethesameconcept,butthereisasinglehard-wiredclasscalledUNIVERSAL,whichactsasalast-resortclassformethodlookups.Bydefault,UNIVERSALprovidesthreemethods:isa,can,andVERSION.

    Wesawisabrieflyinthelastsection;itconsultsaclassorobject's@ISAarrayanddetermineswhetherornotitderivesfromagivenclass:

    packageCoffee;our@ISA=qw(Beverage::Hot);

    subnew{returnbless{temp=>80},shift}

    packageTea;usebase'Beverage::Hot';

  • packageLatte;usebase'Coffee';

    packagemain;my$mug=Latte->new;

    Tea->isa("Beverage::Hot");#1Tea->isa("Coffee");#0

    if($mug->isa("Beverage::Hot")){warn'ContentsMayBeHot';}

    isaisahandymethodyoucanuseinmodulestocheckthatyou'vebeenhandedtherightsortofobject.However,sincenoteverythinginPerlisanobject,youmayfindthatjusttestingascalarwithisaisnotenoughtoensurethatyourcodedoesn'tblowup:ifyousay$thing->isa(...)onanunblessedreference,Perlwilldie.

    Thepreferred"safetyfirst"approachistowritethetestthisway:

    my($self,$thing)=@_;croak"YouneedtogivemeaBeverage::Hotinstance"unlesseval{$thing->isa("Beverage::Hot");};

    Thiswillworkevenif$thingisundeforanon-reference.

    Checkingisarelationshipsisonewaytoensurethatanobjectwillrespondcorrectlytothemethodsthatyouwanttocallonit,butitisnotnecessarilythebestone.Anotheridea,thatofducktyping,statesthatyoushoulddeterminewhetherornottodealwithanobjectbasedonthemethodsitclaimstorespondto,ratherthanitsinheritance.IfourTeaclassdidnotderivefrom

  • Beverage::Hot,butstillhadtemperature,milk,andsugaraccessorsandbrewanddrinkmethods,wecouldtreatitasifitwereaBeverage::Hot.Inshort,ifitwalkslikeaduckanditquackslikeaduck,wecantreatitlikeaduck.[*]

    [*]Ofcourse,oneoftheproblemswithducktypingisthatcheckingthatsomethingcanrespondtoanactiondoesnottellushowitwillrespond.WemightexpectaTReeobjectandaDogtobothhaveabarkmethod,butthatwouldn'tmeanthatwecouldusetheminthesameway.

    TheuniversalcanmethodallowsustocheckPerlobjectsduck-style.It'sparticularlyusefulifyouhaveabunchofrelatedclassesthatdon'tallrespondtothesamemethods.Forinstance,lookingbackatourB::OPclasses,binaryoperators,listoperators,andpatternmatchoperatorshavealastaccessortoretrievetheyoungestchild,butnullary,unary,andlogicaloperatorsdon't.Insteadofcheckingwhetherornotwehaveaninstanceoftheappropriateclasses,wecanwritegenericallyapplicablecodebycheckingwhethertheobjectrespondstothelastmethod:

    $h{firstaddr}=sprintf("%#x",${$op->first})if$op->can("first");$h{lastaddr}=sprintf("%#x",${$op->last})if$op->can("last");

    Anotheradvantageofcanisthatitreturnsthesubroutinereferenceforthemethodonceithasbeenlookedup.We'llseelaterhowtousethistoimplementourownmethoddispatchinthesamewaythatPerlwould.

    Finally,VERSIONreturnsthevalueoftheclass's$VERSION.ThisisusedinternallybyPerlwhenyousay:

    useSome::Module1.2;

  • WhileI'msurethere'ssomethingcleveryoucandobyprovidingyourownVERSIONmethodandhavingitdomagicwhenPerlcallsit,Ican'tthinkwhatitmightbe.

    However,thereisonetrickyoucanplaywithUNIVERSAL:youcanputyourownmethodsinit.Suddenly,everyobjectandeveryclassname(andrememberthatinPerlaclassnameisjustastring)respondstoyournewmethod.

    OneparticularlycreativeuseofthisistheUNIVERSAL::requiremodule.Perl'srequirekeywordallowsyoutoloadupmodulesatruntime;however,oneofitsmoreannoyingfeaturesisthatitactsdifferentlybasedonwhetheryougiveitabareclassnameoraquotedstringorscalar.Thatis:

    requireSome::Module;

    willhappilylookupSome/[email protected],ifyousay:

    my$module="Some::Module";require$module;

    PerlwilllookforafilecalledSome::Moduleinthecurrentdirectoryandprobablyfail.Thismakesitawkwardtorequiremodulesbynameprogramatically.Youhavetoendupdoingsomethinglike:

    eval"require$module";

  • whichhasproblemsofitsown.UNIVERSAL::requireisaneatsolutiontothisitprovidesarequiremethod,whichdoestheloadingforyou.Nowyoucansay:

    $module->require;

    Perlwilltreat$moduleasaclassnameandcalltheclassmethod,whichwillfallthroughtoUNIVERSAL::require,whichloadsupthemodule.

    Similarly,theUNIVERSAL::monikermoduleprovidesahuman-friendlynameforanobject'sclass,bylowercasingthetextafterthefinal:::

    packageUNIVERSAL;

    submoniker{my($self)=@_;my@parts=split/::/,(ref($self)||$self);returnlcpop@parts;}

    Thisallowsyoutosaythingslike:

    formy$class(@classes){print"Listingofall".$class->plural_moniker.":\n";print$_->name."\n"for$class->retrieve_all;print"\n";}

  • SomepeopledisagreewithputtingmethodsintoUNIVERSAL,buttheworstthatcanhappenisthatanobjectnowunexpectedlyrespondstoamethoditwouldnothavebefore.Andifitwouldnotrespondtoamethodbefore,thenanycalltoitwouldhavebeenafatalerror.Atworst,you'vepreventedtheprogramfrombreakingimmediatelybymakingitdosomethingstrange.Balancingthisagainstthekindofhacksyoucanperpetratewithit,I'dsaythataddingthingstoUNIVERSALisausefultechniqueforthearmoryofanyadvancedPerlhacker.

    1.2.2.DynamicMethodResolution

    Ifyou'restillconvincedthatPerl'sOOsystemisnotthesortofthingthatyouwant,thenthetimehascometowriteyourown.DamianConway'sObjectOrientedPerlisfullofwaystoconstructnewformsofobjectsandobjectdispatch.

    We'veseenthefundamentaltechniquesfordoingthis;it'snowjustamatterofcombiningthem.Forinstance,wecancombineAUTOLOADandUNIVERSALtorespondtoanymethodinanyclassatall.Wecouldusethistoturnallunknownmethodsintoaccessorsandmutators:

    subUNIVERSAL::AUTOLOAD{my$self=shift;$UNIVERSAL::AUTOLOAD=~/.*::(.*)/;returnif$1eq"DESTROY";if(@_){$self->{$1}=shift;}$self->{$1};}

    Orwecoulduseittomessaboutwithinheritance,like

  • Class::Dynamic;ormakemethodspartofanobject'spayload,likeClass::ClasslessorClass::Object.We'llseelaterhowtoimplementJava-stylefinalattributestopreventmethodsfrombeingoverridenbyderivedclasses.

    1.2.3.CaseStudy:SingletonMethods

    OntheinfrequentoccasionswhenI'mnotprogramminginPerl,IprograminaninterestinglanguagecalledRuby.RubyisthecreationofJapaneseprogrammerYukihiroMatsumoto,basedonPerlandseveralotherdynamiclanguages.IthasagreatnumberofideasthathaveinfluencedthedesignofPerl6,andsomeofthemhaveevenbeenimplementedinPerl5,aswe'llseehereandlaterinthechapter.

    Oneoftheseideasisthesingletonmethod,amethodthatonlyappliestooneparticularobjectandnottotheentireclass.InPerl,theconceptwouldlooksomethinglikethis:

    my$a=Some::Class->new;my$b=Some::Class->new;

    $a->singleton_method(dump=>sub{my$self=shift;requireData::Dumper;printSTDERRDate::Dumper::Dumper($self)});

    $a->dump;#Printsarepresentationoftheobject.$b->dump;#Can'tlocatemethod"dump"

    $areceivesanewmethod,but$bdoesnot.Nowthatwehaveanideaofwhatwewanttoachieve,halfthebattleisover.It'sobviousthatinordertomakethiswork,we'regoingtoputa

  • singleton_methodmethodintoUNIVERSAL.Andnowsomehowwe'vegottomake$ahaveallthemethodsthatitcurrentlyhas,butalsohaveanadditionalone.

    Ifthismakesyouthinkofsubclassing,you'reontherighttrack.Weneedtosubclass$a(and$aonly)intoanewclassandputthesingletonmethodintothenewclass.Let'stakealookatsomecodetodothis:

    packageUNIVERSAL;

    subsingleton_method{my($object,$method,$subref)=@_;

    my$parent_class=ref$object;my$new_class="_Singletons::".(0+$object);*{$new_class."::".$method}=$subref;

    if($new_classne$parent_class){@{$new_class."::ISA"}=($parent_class);bless$object,$new_class;}}

    First,wefindwhat$a'soriginalclassis.Thisiseasy,sincereftellsusdirectly.Nextwehavetomakeupanewclassanewpackagenameforoursingletonmethodstolivein.Thishastobespecifictotheobject,soweusetheclosestthingtoauniqueidentifierforobjectsthatPerlhas:thenumericrepresentationofitsmemoryaddress.

  • 0+$object

    Wedon'ttalkalotaboutmemorylocationsinPerl,sousingsomethinglike0+$objecttofindamemorylocationmaysurpriseyou.However,itshouldbeafamiliarconcept.Ifyou'veeveraccidentallyprintedoutanobjectwhenyouexpectedanormalscalar,youshouldhaveseensomethinglikeSome::Class=HASH(0x801180).ThisisPerl'swayoftellingyouthattheobjectisaSome::Classobject,it'sbasedonahash,anditlivesatthatparticularlocationinmemory.

    However,justlikethespecialvariable$!,objectshaveastring/integerduality.Ifyoutreatanobjectasanordinarystring,yougettheoutputwehavejustdescribed.However,ifyoutreatitasanumber,youjustgetthe0x8801180.Bysaying0+$object,we'reforcingtheobjecttoreturnitsmemorylocation,andsincenotwoobjectscanbeatthesamelocation,wehaveapieceofdatauniquetotheobject.

    Weinjectthemethodintothenewclasswithglobassignment,andnowweneedtosetupitsinheritancerelationshipon$a'sownclass.SincePerl'sinheritanceishandledbypackagevariables,theseareopenforustofiddlewithdynamically.Finally,wechange$a'sclassbyre-blessingitintothenewclass.

    Thefinaltwististhatifthisisthesecondtimetheobjecthashadasingletonmethodaddedtoit,thenitsclasswillalreadybeintheform_Singleton::8393088.Inthiscase,thenewclassnamewouldbethesameastheold,andwereallydon'twanttoalter@ISA,sincethatwouldsetuparecursiverelationship.Perldoesn'tlikethat.

    Inonly11linesofcodewe'veextendedthewayPerl'sOOsystemworkswithanewconceptborrowedfromanotherlanguage.Perl'smodelmaynotbeterriblyadvanced,butit'sastonishinglyflexible.

  • 1.3.UnexpectedCode

    ThefinalsetofadvancedtechniquesinthischaptercoversanythingwherePerlcoderunsatatimethatmightnotbeobvious:tying,forinstance,runscodewhenavariableisaccessedorassignedto;overloadingrunscodewhenvariousoperationsarecalledonavalue;andtimeshiftingallowsustoruncodeoutoforderordelayeduntiltheendofscope.

    SomeofthemoststrikingeffectsinPerlcanbeobtainedbyarrangingforcodetoberunatunexpectedmoments,butthismustbetemperedwithcare.Thewholepointofunexpectedcodeisthatit'sunexpected,andthatbreaksthewell-knownPrincipleofLeastSurprise:programmingPerlshouldnotbesurprising.

    Ontheotherhand,thesearepowerfultechniques.Let'stakealookathowtomakethebestuseofthem.

    1.3.1.Overloading

    Overloading,inaPerlcontext,isawayofmakinganobjectlooklikeitisn'tanobject.Morespecifically,it'sawayofmakinganobjectrespondtomethodswhenusedinanoperationorothercontextthatdoesn'tlooklikeamethodcall.

    Theproblemwithsuchoverloadingisthatitcanquicklygetwildlyoutofhand.C++overloadstheleftbit-shiftoperator,

  • ontheotherhand,overloadsthesameoperatoronarraystomeanpush.IfwemakeflagrantuseofoverloadinginPerl,weenduphavingtolookatleasttwiceatcodelike:

    $object*=$value;

    Welookoncetoseeitasamultiplication,oncetorealizeit'sactuallyamethodcall,andoncemoretoworkoutwhatclass$objectisinatthispointandhencewhatmethodhasbeencalled.

    Thatsaid,forclassesthatmoreorlessrepresentthesortofthingsyou'reoverloadingnumbers,strings,andsoonthenoverloadingworksfine.Now,howdowedoit?

    1.3.1.1Simpleoperatoroverloading

    Theclassicexampleofoperatoroverloadingisamodulethatrepresentstime.Indeed,Time::Seconds,fromtheTime::Piecedistributiondoesjustthis.Let'smakesomenewTime::Secondsobjects:

    my$min=Time::Seconds->new(60);my$hour=Time::Seconds->new(3600);

    ThepointofTime::Secondsisthat,aswellasmerelyrepresentinganumberofseconds,youcanconvertbetweendifferentunitsofduration:

    my$longtime=Time::Seconds->new(123456);print$longtime->hours;#34.2933..print$longtime->days;#1.42888..

  • Theseobjectsdefinitelyrepresentanumberanumberofseconds.Normally,we'dhavetoaddthemtogetherwithsomeuglyhacklikethis:

    my$new=$min->add($hour);

    Andeventhenit'snotclearwhetherornotthatalterstheoriginal$min.Soonenaturaluseofoperatoroverloadingwouldbetoenableustosay$min+$hour,andgetbackanobjectrepresenting3,660seconds.Andthatispreciselywhathappens:

    my$new=$min+$hour;print$new->seconds;#3660

    ThisisdonebythefollowingbitofcodeintheTime::Secondsmodule:

    useoverload'+'=>\&add;#...subadd{my($lhs,$rhs)=_get_ovlvals(@_);returnTime::Seconds->new($lhs+$rhs);}

    sub_get_ovlvals{my($lhs,$rhs,$reverse)=@_;$lhs=$lhs->seconds;

    if(UNIVERSAL::isa($rhs,'Time::Seconds')){$rhs=$rhs->seconds;}elsif(ref($rhs)){

  • die"Can'tusenonSecondsobjectinoperatoroverload";}

    if($reverse){return$rhs,$lhs;}return$lhs,$rhs;}

    Theoverloadpragmaisthekeytoitall.IttellsPerltolookmorecarefullyatoperationsinvolvingobjectsofthatclass,anditregistersmethodsforthegivenoperatorsinalook-uptable.Whenanobjectisinvolvedinanoverloadedoperation,theoperationislookedupinthetableandtheresultingmethodcalled.Inthiscase,$obj+$otherwillcall$obj->add($other,0).

    ThereasonPerlpassesthreeparameterstothemethodisthatinthecaseof$other+$obj,where$otherisnotanobjectthatoverloads+,westillexpecttheaddmethodtobecalledon$obj.Inthiscase,however,Perlwillcall$obj->add($other,1),tosignifythattheargumentshavebeenreversed.

    The_get_ovlvalssubroutinelooksatthetwoargumentstoanoperatorandtriestocoercethemintonumbersotherTime::Secondsobjectsareturnedintonumbersbyhavingthesecondsmethodcalledonthem,ordinarynumbersarepassedthrough,andanyotherkindofobjectcausesafatalerror.Thentheargumentsarereorderedtotheoriginalorder.

    Oncewehavetwoordinarynumbers,wecanaddthemtogetherandreturnanewTime::Secondsobjectbasedonthesum.

    Theotheroperatorsarebasedonthisprinciple,suchas,whichimplementsallofthecomparisonoperators:

    useoverload''=>\&compare;

  • subcompare{my($lhs,$rhs)=_get_ovlvals(@_);return$lhs$rhs;}

    Time::Secondsalsooverloadsassignmentoperators+=and-=:

    useoverload'-='=>\&subtract_from;subsubtract_from{my$lhs=shift;my$rhs=shift;$rhs=$rhs->secondsifUNIVERSAL::isa($rhs,'Time::Seconds');$$lhs-=$rhs;return$lhs;}

    Thisallowsyoutosay$new+=60toaddanotherminutetothenewduration.

    Finally,toavoidhavingtowritesuchsubroutinesforeverykindofoperator,Time::Secondsusesafeatureofoverloadcalledfallback.ThisinstructsPerltoattempttoautomaticallygeneratereasonablemethodsfromtheonesspecified:forinstance,the$x++operatorwillbeimplementedintermsof$x+=1,andsoon.Time::Secondssetsfallbacktoundef,whichmeansthatPerlwilltrytouseanautogeneratedmethodbutwilldieifitcannotfindone.

    useoverload'fallback'=>'undef';

    Alternatevaluesforfallbackincludesometruevalue,whichis

  • themostgeneralfallback:ifitcannotfindanautogeneratedmethod,itwilldowhatitcan,assumingifnecessarythatoverloadingdoesnotexist.Inotherwords,itwillalwaysproducesomevalue,somehow.

    Ifyou'reusingoverloadingjusttoaddashortcutoperatorortwoontoanotherwiseobject-basedclassforexample,ifyouwantedtoemulateC++'s(ratherdodgy)useofthe

  • youwouldn'tnormallythinkofasoperators.ThetwomostusefulofthesewehavejustseenwithTime::Secondstheabilitytodictatehowanobjectisconvertedtoastringorintegerwhenusedassuch.

    Thisisdonebyassigningmethodstotwospecialoperatornamesthe""operatorforstringificationandthe0+operatorfornumification:

    useoverload'0+'=>\&seconds,'""'=>\&seconds;

    NowanytimetheTime::Secondsobjectisusedasastringoranumber,thesecondsmethodgetscalled,returningthenumberofsecondsthattheobjectcontains:

    print"Onehourplusoneminuteis$newseconds\n";#Onehourplusoneminuteis3660seconds.

    Thesearethemostcommonmethodstomakeanoverloadedobjectlookandbehavelikethethingit'smeanttorepresent.Thereareafewothermethodsyoucanplaywithformoreobscureeffects.

    Forinstance,youcanoverloadthewaythatanobjectisdereferencedinvariousways,allowingascalarreferencetopretendthatit'salistreferenceorviceversa.TherearefewsensiblereasonstodothisthecuriousObject::MultiTypeoverloadsthe@{},%{},&{},and*{}operatorstoallowasingleobjecttopretendtobeanarray,hash,subroutine,orglob,dependingonhowit'sused.

  • 1.3.1.3Non-operatoroverloading

    Onelittle-knownextensionoftheoverloadmechanismishiddenawayinthedocumentationforoverload:

    ForsomeapplicationPerlparser[sic]manglesconstantstoomuch.Itispossibletohookintothisprocessviaoverload::constant()andoverload::remove_constant()functions.

    Thesefunctionstakeahashasanargument.Therecognizedkeysofthishashare

    integer

    tooverloadintegerconstants,

    float

    tooverloadfloatingpointconstants,

    binary

    tooverloadoctalandhexadecimalconstants,

    q

    tooverload"q"-quotedstrings,constantpiecesof"qq"-and"qx"-quotedstringsandhere-documents,

  • qr

    tooverloadconstantpiecesofregularexpressions.

    Thatistosay,youcancausethePerlparsertorunasubroutineofyourchoiceeverytimeitcomesacrosssomekindofconstant.Naturally,thisisagainsomethingthatshouldbeusedwithcarebutcanbeusedtosurprisingeffect.

    Thesubroutinessuppliedtooverload::constantpassthreeparameters:thefirstistherawformastheparsersawit,thesecondisthedefaultinterpretation,andthethirdisamnemonicforthecontextinwhichtheconstantoccurs.Forinstance,given"camel\nalpaca\npanther",thefirstparameterwouldbecamel\nalpaca\npanther,whereasthesecondwouldbe:

    camelalpacapanther

    Asthisisadouble-quoted(qq)string,thethirdparameterwouldbeqq.

    Forinstance,thehigh-precisionmathlibrariesMath::BigIntandMath::BigFloatprovidetheabilitytoautomaticallycreatehigh-precisionnumbers,byoverloadingtheconstantoperation.

    %perl-MMath::BigFloat=:constant-le'printref(123456789012345678901234567890\>1234567890)'Math::BigFloat

  • Thisallowsthelibrariestogetatallthenumbersinaprogram,providinghigh-precisionmathwithouttheexplicitcreationofoverloadedMath::BigFloatobjects.Thecodethatdoesitisstunninglysimple:

    subimport{my$self=shift;#...overload::constantfloat=>sub{$self->new(shift);};}

    Whentheparserseesafloatingpointnumber(onetoolargetobestoredasaninteger)itpassestherawstringasthefirstparameterofthesubroutinereference.Thisisequivalenttocalling:

    Math::BigFloat->new("1234567890123456789012345678901234567890")

    atcompiletime.

    TheMath::Big*librariescangetawaywiththisbecausetheyarerelativelywellbehaved;thatis,aPerlprogramshouldnotnoticeanydifferenceifallthenumbersaresuddenlyoverloadedMath::BigIntobjects.

    Ontheotherhand,here'saslightlymorecrazyuseofoverloading...

    I'vealreadymentionedRubyasbeinganotherfavoritelanguageofmine.OneofthedrawsaboutRubyisthatabsolutelyeverythingisanobject:

  • %irbirb(main):001:0>2=>2irb(main):002:0>2.class=>Fixnumirb(main):003:0>2.class.class=>Classirb(main):004:0>2.class.class.class=>Classirb(main):005:0>2.methods=>["=","divmod","+","floor","to_int","to_i","chr","truncate","round","ceil","integer?","prec_f","prec_i","prec","coerce","nonzero?","+@","remainder","eql?","=  =  =","clone","between?","is_a?","equal?","singleton_methods","freeze","instance_of?","send","methods","tainted?","id","instance_variables","extend","dup","protected_methods","=~","frozen?","kind_of?","respond_to?","class","nil?","instance_eval","public_methods","_ _send_ _","untaint","_ _id_ _","inspect","display","taint","method","private_methods","hash",

  • "to_a"]

    Ilikethatyoucancallmethodsona2.Ilikethatyoucandefineyourownmethodstocallona2.Ofcourse,youcan'tdothatinPerl;2isnotanobject.

    Butwecanfakeit.Ruby.pmwasaproof-of-conceptmoduleIstartedworkontodemonstratethatyoucandothissortofthinginPerl.Here'swhatitlookslike:

    useRuby;print2->class;#"FixInt"print"HelloWorld"->class->class#"Class"print2->class->to_s->class#"String"print2->class->to_s->length#"6"print((2+2)->class)#"FixInt"

    #Oreven:print2.class.to_s.class#"String"

    Howcanthispossiblywork?Obviously,theonlythingthatwecancallmethodsonareobjects,soconstantslike2andHelloWorldneedtoreturnobjects.Thistellsusweneedtobeoverloadingtheseconstantstoreturnobjects.Wecandothateasilyenough:

    packageRuby;subimport{overload::constant(integer=>sub{returnFixnum->new(shift)},q=>sub{returnString->new(shift)},qq=>sub{returnString->new(shift)});

  • }

    Wecanmaketheseobjectsblessedscalarreferences:

    packageFixnum;subnew{returnbless\$_[1],$_[0]}

    packageString;subnew{returnbless\$_[1],$_[0]}

    Thisallowsustofilltheclassesupwithmethodsthatcanbecalledontheconstants.That'sagoodstart.Theproblemisthatourconstantsnowbehavelikeobjects,insteadoflikethestringsandnumberstheyrepresent.Wewant"HelloWorld"tolooklikeandactlike"HelloWorld"insteadoflike"String=SCALAR(0x80ba0c)".

    Togetaroundthis,weneedtooverloadagainwe'veoverloadedtheconstantstobecomeobjects,andnowweneedtooverloadthoseobjectstolooklikeconstantsagain.Let'slookatthestringclassfirst.Thefirstthingweneedtooverloadisobviouslystringification;whentheobjectisusedasastring,itneedstodisplayitsstringvaluetoPerl,whichwedobydereferencingthereference.

    useoverload'""'=>sub{${$_[0]}};

    Thiswillgetusmostofthewaythere;wecannowprintoutourStringsandusethemanywherethatanormalPerlstringwouldbeexpected.Next,wetakenoteofthefactthatinRuby,Stringscan'tbecoercedintonumbers.Youcan'tsimplysay2+"10",becausethisisanoperationbetweentwodisparatetypes.

  • TomakethishappeninourStringclass,wehavetooverloadnumification,too:

    useCarp;useoverload"0+"=>sub{croak"Stringcan'tbecoercedintoFixnum"};

    YoumightlikethefactthatPerlconvertsbetweentypesmagically,butthereasonwhyRubycan'tdoitisbecauseitusesthe+operatorforbothnumericadditionandstringconcatenation,justlikeJavaandPython.Let'soverload+togiveusstringconcatenation:

    useoverload"+"=>sub{String->new(${$_[0]}."$_[1]")};

    Therearetwothingstonoteaboutthis.ThefirstisthatwehavetobesurethatanyoperationsthatmanipulatestringswillthemselvesreturnStringobjects,orotherwisewewillendupwithordinarystringsthatwecannolongercallmethodson.ThisisnecessaryintheFixnumanaloguetoensurethat(2+2)->classstillworks.Theotherthingisthatwemustexplicitlyforcestringificationontheright-handoperand,forreasonssoontobecomeapparent.

    Turningtemporarilytothenumericclass,wecanfillintwooftheoverloadmethodsinthesamesortofway:

    useoverload'""'=>sub{croak"failedtoconvertFixnumintoString"},"0+"=>sub{${$_[0]}},

  • However,methodslike+havetobetreatedcarefully.Wemightfirsttrydoingsomethinglikethis:

    useoverload'+'=>sub{${$_[0]}+$_[1]};

    However,ifwethentry2+"12"thenwegetthebizarreresult122,andfurtherproddingfindsthatthisisaString.Why?

    WhathappensisthatPerlfirstseesFixnum+Stringandcallstheoverloadedmethodwe'vejustcreated.Insidethismethod,itconvertstheFixnumobjecttoitsintegervalueandnowhasinteger+String.

    Theintegerisnotoverloaded,buttheStringobjectis.IfPerlcanseeanoverloadedoperation,itwilltryandcallit,reorderingtheoperationasString+integer.SinceStringhasanoverloaded+method,too,thatgetscalled,creatinganewstring,whichcatenatestheStringandtheinteger.Oops.

    Ideally,wewouldfindawayofconvertingtheright-handsideofthe+operationonaFixnumtoanhonest-to-goodnessnumber.Unfortunately,whilePerlhasanexplicitstringificationoperator,"",whichweusedtoavoidthisproblemintheStringcase,thereisn'tanexplicitnumificationoperator;overloaduses0+asaconvenientmnemonicfornumification,butthisismerelydescribingtheoperationintermsofthe+operator,whichcanbeoverloaded.Sotofixupour+method,wehavetogetalittletechnical:

    useoverload'+'=>\∑

    subsum{my($left,$right)=@_;my$rval;if(my$numify=overload::Method($right,"0+")){

  • $rval=$right->$numify;}else{$rval=$right;}Fixnum->new($$left+$rval);}

    Toexplicitlynumifytheright-handside,weaskoverloadifthatvaluehasanoverloadednumification.Ifitdoes,Methodwillreturnthemethod,andwecancallitandexplicitlynumifythevalueinto$rval.Oncewe'vegottwoplainoldnumbers,weaddthemtogetherandreturnanewnumberoutofthetwo.

    Next,weaddoverloadfallback=>1;toeachclass,toprovidedo-what-I-mean(DWIM)methodsfortheoperatorsthatwedon'tdefine.Thisiswhatyouwanttodoforanycasewhereyouwantanobjecttocompletelyemulateastandardbuilt-intype,ratherthanjustaddoneortwooverloadedmethodsontosomethingthat'sessentiallyanobject.

    Finally,asalittleflourish,wewanttomakethelastlineofourexamplework:

    print2.class.to_s.class#"String"

    OneofthereasonsRuby'sconcatenationoperatoris+istofreeup.forthepreferreduseinmostOOlanguages:methodcalls.Thisisn'tveryeasytodoinPerl,butwecanfakeitenoughforariggeddemo.Obviouslywe'regoingtoneedtooverloadtheconcatenationoperator.ThekeytoworkingouthowtomakeitworkistorealizewhatthosethingslikeclassareinaPerlcontext:they'rebarewords,orjustordinarystrings.HenceifweseeaconcatenationbetweenoneofourRubyobjectsandanordinarystring,weshouldcallthemethodwhosenameisin

  • thestring:

    useoverload"."=>sub{my($obj,$meth)=@_;$obj->$meth};

    Andpresto,wehaveRuby-likeobjectsandRuby-likemethodcalls.Themethodcallmagicisn'tperfectwe'llseelaterhowitcanbeimprovedbuttheRuby-likeobjectscannowrespondtoanymethodswewanttoputintotheirclasses.It'snothardtobuildupafullclasshierarchyjustlikeRuby'sown.

  • Limitations

    Ofcourse,ouroverloadingshenanigansdonotmanagetodealwith,forinstance,turningarraysintoobjects.AlthoughPerlisprettyflexible,thatreallycan'tbedonewithoutchangingthewaythemethodcalloperatorworks.

    Thatdoesn'tnecessarilystoppeople;thehackerknownonlyas"chocolateboy"hascreatedamodulecalledautobox,whichrequiresapatchtothePerlcore,butwhichallowsyoutotreatanybuilt-inPerldatatypeasanobject.

    1.3.2.TimeShifting

    ThefinalfundamentaladvancedtechniquewewanttolookatisthatofpostponingorreorderingtheexecutionofPerlcode.Forinstance,wemightwanttowaituntilallmoduleshavebeenloadedbeforemanipulatingthesymboltable,wemightwanttoconstructsomecodeandrunitimmediatelywitheval,orwemightwanttoruncodeattheendofascope.

    TherearePerlkeywordsforalloftheseconcepts,andjudicioususeofthemcanbeeffectiveinachievingawidevarietyofeffects.

    1.3.2.1Doingthingsnowwitheval/BEGIN

    Thebasicinterfacetotime-shiftingisthroughaseriesofnamedblocks.ThesearelikespecialsubroutinesthatPerlstoresinaqueueandrunsatstrategicpointsduringthelifetimeofaprogram.

    ABEGINblockisexecutedassoonasPerlcompilesthecode:

  • print"Icomesecond!\n";BEGIN{print"Icomefirst!\n";}

    ThesecondlineappearsfirstbecausePerldoesnotordinarilyruncodeasitseesit;itwaitsuntilithascompiledaprogramandallofitsdependenciesintothesortofoptreewesawinoursectiononB,andthenrunsitall.However,BEGINforcesPerltorunthecodeassoonastheindividualblockhasbeencompiledbeforetheofficialruntime.

    Infact,theusedirectivetoloadamodulecanbethoughtofas:

    BEGIN{requireModule::Name;Module::Name->import(@stuff);}

    becauseitcausesthemodule'scodetobeloadedupanditsimportmethodtoberunimmediately.

    OneuseoftheimmediateexecutionnatureoftheBEGINblockisintheAnyDBM_Filemodule.ThismoduletriestofindanappropriateDBMmoduletoinheritfrom,meaningthatsolongasoneofthefivesupportedDBMmodulesisavailable,anycodeusingDBMsoughttowork.

    Unfortunately,someDBMimplementationsaremorereliablethanothers,oroptimizedfordifferenttypesofapplication,soyoumightwanttospecifyapreferredsearchorderthatisdifferentfromthedefault.Butwhen?AsAnyDBM_Fileloads,itsetsupits@ISAarrayandrequirestheDBMmodules.

    ThetrickistouseBEGIN;ifAnyDBM_Fileseesthatsomeoneelsehasputan@ISAarrayintoitsnamespace,itwon'toverwriteitwithitsdefaultone.Sowesay:

  • BEGIN{@AnyDBM_File::ISA=qw(DB_FileGDBM_FileNDBM_File);}useAnyDBM::File;

    Thiswouldn'tworkwithouttheBEGIN,sincethestatementwouldthenonlybeexecutedatruntime;wayaftertheusehadsetupAnyDBM_File.

    AswellasaBEGIN,there'salsoanENDblock,whichstoresupcodetorunrightattheendoftheprogram,and,infact,thereareaseriesofotherspecialblocksaswell,asshowninFigure1-7.

    Figure1-7.Namedblocks

    TheCHECKblocksandtheINITblocksareprettymuchindistinguishable,runningjustbeforeandjustafterexecutionbegins.Theonlydifferenceisthatexecutingperlwiththe-cswitch(compilationchecks)willrunCHECKblocksbutnotINITblocks.(Thisalsomeansthatifyouloadamoduleatruntime,itsCHECKandINITblockswon'tberun,becausethetransition

  • betweentheglobalcompilationphaseandtheglobalruntimeexecutionhasalreadypassed.)Let'stakealookatwhatwecandowithaCHECKblock.

    1.3.2.2DoingthingslaterwithCHECK

    Earlier,wetalkedaboutmessingwithinheritancerelationshipsandstealingideasfromotherlanguages.Let'snowimplementanewmodule,whichgivesustheJavaconceptoffinalmethods.Afinalmethodisonethatcannotbeoverridenbyinheritance:

    packageBeverage::Hot;subserve:final{#Ihaveexclusiverightstodefiningthismethod!my($self,$who)=@_;if($who->waitress){$who->waitress->serve($self,$who);}else{$who->take($self);}}

    packageTea;usebase'Beverage::Hot';

    subserve{#Compile-timeerror.}

    We'lldothisbyallowingausertospecifya:finalattributeonamethod.Thisattributewillmarkamethodforlaterchecking.Oncecompiletimehasfinished,we'llcheckoutalltheclassesthatderivefromthemarkedclass,anddiewithanerrorifthederivedclassimplementsthefinalmethod.

  • Attributes

    TheideaofattributescameinPerl5.005,withtheattrsmodule.Thiswaspartofthreadingsupportandallowedyoutomarkasubroutineasbeingamethodorbeinglockedforthreadingthatis,itonlyallowsonethreadtoaccessthesubroutineorthemethod'sinvocantatonce.In5.6.0,thesyntaxwaschangedtothenow-familiarsubname:attr,anditalsoalloweduser-definedattributes.

    PerhapstheeasiestwaytogetintoattributeprogrammingforanythingtrickyistouseDamianConway'sAttribute::Handlersmodule:thisallowsyoutodefinesubroutinestobecalledwhenanattributeisseen.

    Thefirstthingwewanttodoistakeanoteofthoseclassesandmethodsmarkedfinal.WeneedtoswitchtotheUNIVERSALclass,sothatourattributeisvisibleeverywhere.We'llalsouseahash,%marked,togroupthemarkedmethodsbypackage:

    packageUNIVERSAL;useAttribute::Handlers;subfinal:ATTR{my($pack,$ref)=@_;push@{$marked{$pack}},*{$ref}{NAME};}

    TheAttribute::Handlerspackagearrangesforourhandlertobecalledwithvariousparameters,ofwhichweareonlyinterestedinthefirsttwothepackagethathasthemarkedsubroutineinitandtheglobreferenceforthesubroutineitselfbecausewecangetthesubroutine'snamefromthat.(NAMEisoneofthemagicnameswecanusetoaccessaglob'sslotitreturnsthenameofthesymboltableentry.*{Tea::serve}{NAME}wouldreturnserve.)

    Nowwe'vegotourlistofmarkedmethods.Weneedtofinda

  • waytointerruptPerljustbeforeitrunsthescriptbutafterallthemodulesthatweplantousehavebeencompiledandalltheinheritencerelationshipssetup,sothatwecanchecknobodyhasbeennaughtyandoverridenafinalizedmethod.

    TheCHECKkeywordgivesusawaytodothis.Itregistersablockofcodetobecalledaftercompilationhasbeenfinishedbutbeforeexecutionbegins.[*]

    [*]Incidentally,theOcompilermodulewementionedearlierworksbymeansofCHECKblocksafterallthecodehasbeencompiled,Ohastheselectedcompilerbackendvisittheopcodetreeandspitoutwhateveritwantstodo,thenexitsbeforethecodeisrun.

    Toenableustotestthemodule,itturnsoutwewanttohaveourCHECKblockcallanotherfunction.Thisisbecausewecanthenrunthecheckertwice,oncewithoutanoffendingmethodandoncewith:

    CHECK{Attribute::Final->check}

    Whatwillourcheckingmethoddo,though?Itneedstovisitalltheclassesthatderivefromthoseclasseswehaveinour%markedhash,andtodothat,ithastoknowallthepackagesinthesystem.Sofirstwe'llwritealittlefunctiontorecursivelywalkoverthesymboltable,collectingnamesofpackagesitsees.

    Thesymboltableisjustahash,andwecanfindglobnamesbylookingatthekeysofthehash.Tomakematterseveneasier,packagenamesarejusthashkeysthatendin::.Soourcollectorfunctionlookslikethis:

    subfill_packages{nostrict'refs';my$root=shift;my@subs=greps/::$//,keys%{$root."::"};push@all_packages,$root;

  • for(@subs){nextif$rooteq"main"and$_eq"main";#Loopfill_packages($root."::".$_);}}

    Thenextlineavoidsthepotentialtrapofloopingforever,becausethemain::packagecontainsanentrytoitself.Nowwecanstartlookingatthecheckfunction.Itonlyhastodealwiththosepackagesthathavesomekindofinheritancerelationship,soifapackagedoesnothavean@ISA,thenwecandiscardit:

    subcheck{nostrict'refs';fill_packages("main")unless@all_packages;formy$derived_pack(@all_packages){nextunless@{$derived_pack."::ISA"};...}}

    Next,wehavealistofmarkedpackagesthatcontainfinalmethods.Wewanttolookspecificallyatcircumstanceswhereaderivedpackagederivesfromamarkedpackage:

    formy$derived_pack(@all_packages){nextunless@{$derived_pack."::ISA"};formy$marked_pack(keys%marked){nextunless$derived_pack->isa($marked_pack);...

  • Atthispoint,weknowwehaveasuspectpackage.Ithastherightkindofinheritancerelationship,butdoesitoverridethefinalizedmethod?

    formy$meth(@{$marked{$marked_pack}}){my$glob_ref=\*{$derived_pack."::".$meth};if(*{$glob_ref}{CODE}){

    Ifthecodeslotispopulated,thenwehaveindeedfoundanaughtymethod.Atthispoint,allthat'slefttodoisreportwhereitcamefrom.WecandothatwiththeBtechnique:byturningtheglobintoaB::GVobject,wegainaccesstotheotherwiseunreachableFILEandLINEmethods,whichtelluswheretheglobentrywasconstructed.

    my$name=$marked_pack."::".$meth;my$b=B::svref_2object($glob_ref);die"Cannotoverridefinalmethod$nameat".$b->FILE.",line".$b->LINE."\n";

    AndthatistheessenceofworkingwithCHECKblocks:theyallowustodothingswiththesymboltableonceeverythingisinplace,onceallthemoduleshavebeenloaded,andoncetheinheritancerelationshipsandotherfactorshavebeensetup.Ifyoueverfeelyouneedtodosomethinginamodulebutyoudon'twanttodoitquiteyet,puttingitinaCHECKblockmightjustbetherighttechnique.

  • 1.3.2.3DoingthingsattheendwithDESTROY

    We'vereferredtothespecialDESTROYmethod,whichiscalledwhenanobjectgoesoutofscope.Generallythisisusedforwritingoutstatetodisk,breakingcircularreferences,andotherfinalizationtasks.However,youcanuseDESTROYtoarrangeforthingstobedoneattheendofascope:

    subdo_later(&){blessshift,"Do::Later"}subDo::Later::DESTROY{$_[0]->()};

    {my$later=do_later{print"Endofblock!\n";};...}

    Solongas$latersticksaround,thecodedoesn'tgetcalled.Whenitgoesoutofscope,getsundefined,orthefinalreferencetoitgoesaway,thenthecodeblockiscalled.Hook::LexWrap,oneofthemoduleswelookedatearlierinthechapter,actuallyusesasimilartricktoturnoffthewrappingofasubroutineattheendofalexicalscope:

    my$unwrap;$imposter=sub{if($unwrap){goto&$original}...}...returnblesssub{$unwrap=1},'Hook::LexWrap::Cleanup';

  • Whileyoukeepholdofthereturnvaluefromwrap,theimpostercallsthewrappingcode.However,oncethatvaluegoesoutofscope,theclosuresets$unwraptoatruevalue,andfromthenontheimpostersimplyjumpstotheoriginalroutine.

    1.3.2.4Casestudy:Acme::Dot

    Oneexamplethatputsitalltogethermessingaboutwiththesymboltable,shiftingthetimingofcodeexecution,andoverloadingismyownAcme::Dotmodule.

    Ifyou'renotfamiliarwithCPAN'sAcme::*hierarchy,we'llcoveritinmoredetailinChapter10,butfornowyoushouldknowit'sformodulesthatarenotentirelyserious.Acme::Dotisfarfromserious,butitdemonstratesalotofseriousadvancedtechniques.

    TheideaofAcme::Dotwastoabstractthe$variable.methodoverloaded.operatorfromRuby.pmandallowthird-partymodulestouseit.Italsogoesalittlefurther,allowing$variable.method(@arguments)towork.And,ofcourse,itdoessowithoutusingsourcefiltersoranyothernon-Perlhackery;thatwouldbecheatingoratleastinelegant.

    So,howdowemakethiswork?Weknowthemaintrick,fromRuby.pm,ofoverloadingconcatentationonanobject.However,therearetwoniggles.Thefirstisthatpreviously,where$foo.classwasavariable"concatenated"withaliteralstring,$foo.method(@args)isgoingtobeparsedasasubroutinecall.That'sfine,forthetimebeing;we'llassumethatthereisn'tgoingtobeasubroutinecalledmethodkickingaroundanywherefornow,andlaterwe'llfixupthecasewherethereisone.WewantPerltocalltheundefinedsubroutinemethod,becauseifanundefinedsubroutinegetscalled,wecancatchitwithAUTOLOADandsubvertit.

  • Inwhatwaydoweneedtosubvertit?IntheRuby.pmcase,wesimplyturnedtheright-handsideoftheconcatenation(classin$var.class)andusedthatasamethodname.Inthiscase,weneedtonotonlyknowthemethodname,butthemethod'sparameters,aswell.So,ourAUTOLOADroutinehastoreturnadatastructurethatholdsthemethodnameandtheparameter.Ahashisanaturalwayofdoingthis,althoughanarraywoulddojustaswell:

    subAUTOLOAD{$AUTOLOAD=~/.*::(.*)/;returnif$1eq"DESTROY";return{data=>\@_,name=>$1}}

    Asusual,wetakecaretoavoidclobberingDESTROY.Nowthatwehavetheargumentsandthename,wecanwriteouroverloadsubroutinetofirethecorrectmethodcallonconcatenation.Ontheleftwillbetheobject,andontherightwillbetheresultofourAUTOLOADroutinethedatastructurethattellsuswhichmethodtofireandwithwhatparameters.

    useoverload"."=>sub{my($obj,$stuff)=@_;@_=($obj,@{$stuff->{data}});goto&{$obj->can($stuff->{name})};},fallback=>1;

    JustasinRuby,weusethegototricktoavoidupsettinganythingthatreliesoncaller.[*]Nowwehavetheeasypartdone.

    [*]Although,tobehonest,Idon'tbelievetherereallyis(oroughttobe)anythingthatreliesonthebehaviorofcalleratleast,nothingthatisn'tdoingadvancedthingsitself.

  • Isaythisistheeasypartbecauseweknowhowtodothisforonepackage.Sofarwe'veglossedoverthefactthatthemethodsandtheoverloadroutinearegoingtoliveinoneclass,andtheAUTOLOADsubroutinehastobepresentwhereverthe$var.methodmethodcallsaregoingtobemade.Tomakemattersworse,ourAcme::Dotmoduleisgoingtobeneitherofthesepackages.We'regoingtoseesomethinglikethis:

    packageMy::Class;useAcme::Dot;usebase'Class::Accessor';__PACKAGE__->mk_accessors(qw/nameage/);

    packageEnd::User;useMy::Class;

    my$x=newMy::Class;$x.name("Winnie-the-Pooh");

    It'stheOOclassthatneedstouseAcme::Dotdirectly,anditwillhavetheoverloadroutine.WecantakecareofthiseasilybymakingAcme::Dot'simportmethodsetuptheoverloadinginitscaller:

    my($call_pack);

    subimport{nostrict'refs';$call_pack=(caller())[0];eval{data}});goto\&{\$obj->can(\$stuff->{name})};

  • },fallback=>1;

    EOT;}

    However,there'sthethirdpackage,theEnd::Userpackage,whichactuallyneverseesAcme::Dotatall.ItjustusesMy::Classandexpectstogetthedot-operatorfunctionalityaspartofthatclass.Meanwhile,ourpoorAcme::DotclasshastosomehowfindoutwhichclassistheenduserandinstallanAUTOLOADroutineintoit.

    Thankfully,weknowthattheend-userclasswillcallMy::Class->import,sowecanuseglobassignmenttomakeMy::Class::importconveysomeinformationbacktoAcme::Dot.WecanmodifyAcme::Dot'simportroutinealittle:

    my($call_pack,$end_user);

    subimport{nostrict'refs';$call_pack=(caller())[0];*{$call_pack."::import"}=sub{$end_user=(caller())[0];};eval{data}});goto\&{\$obj->can(\$stuff->{name})};},fallback=>1;

    EOT;

  • }

    Asyoucansee,we'venowglobassignedMy::Class'simportroutineandmadeitsaveawaythenameofthepackagethatusedit:theend-userclass.

    Andnow,sinceeverythingissetup,weareatthepointwherewecaninjecttheAUTOLOADintotheenduser'sclass.WeuseaCHECKblocktotime-shiftthistotheendofcompilation:

    CHECK{#Atthispoint,everythingisready,and$end_usercontains#thecallingpackage'scallingpackage.nostrict;if($end_user){*{$end_user."::AUTOLOAD"}=sub{$AUTOLOAD=~/.*::(.*)/;returnif$1eq"DESTROY";return{data=>\@_,name=>$1}}}}

    AndthatisessentiallyhowAcme::Dotoperates.Itisn'tperfect;ifthere'sasubroutineintheend-userpackagewiththesamenameasamethodontheobject,AUTOLOADwon'tbecalled,andwewillrunintoproblems.It'spossibletoworkaroundthat,bymovingallthesubroutinestoanotherpackage,dispatchingeverythingviaAUTOLOADandusingBtoworkoutwhetherwe'reinthecontextofaconcatenationoperator,but...hey,it'sonlyanAcme::*module.AndIhopeit'smadeitspointalready.

  • 1.4.Conclusion

    We'venowlookedatmanyoftheadvancedtechniquesusedinpurePerlmodules,mostoftheminvolvinghowtomanipulatethewayPerloperates.We'vedividedthoseroughlyintosectionsonmessingwiththesymboltable,messingwiththeclassmodel,andmakingcoderunwherecodemightnotbeexpected.

    Inasense,everythingelseinthisbookwillbebuiltonthetechniquesthatwe'veseenhere.However,Perlisapragmaticlanguage,andinsteadoflookingintheabstractattechniquesthatmightbeuseful,we'regoingtoseehowthesetricksarealreadybeingusedinreal-lifecodeinCPANmodulesandhowtheycanmakeyourprogramminglifeeasier.

  • Chapter2.ParsingTechniquesOnethingPerlisparticularlygoodatisthrowingdataaround.Therearetwotypesofdataintheworld:regular,structureddataandeverythingelse.Thegoodnewsisthatregulardatacolondelimited,tabdelimited,andfixed-widthfilesisreallyeasytoparsewithPerl.Wewon'tdealwiththathere.Thebadnewsisthatregular,structureddataistheminority.

    Ifthedataisn'tregular,thenweneedmoreadvancedtechniquestoparseit.Therearetwomajortypesofparserforthiskindoflesspredictabledata.Thefirstisabottom-upparser.Let'ssaywehaveanHTMLpage.Wecansplitthedataupintomeaningfulchunksortokenstagsandthedatabetweentags,forinstanceandthenreconstructwhateachtokenmeans.SeeFigure2-1.Thisapproachiscalledbottom-upparsingbecauseitstartswiththedataandworkstowardaparse.

    Figure2-1.Bottom-upparsingofHTML

    Theothermajortypeofparserisatop-downparser.ThisstartswithsomeideasofwhatanHTMLfileoughttolooklike:ithasantagatthestartandanattheend,withsomestuffinthemiddle.Theparsercanfindthatpatterninthe

  • documentandthenlooktoseewhatthestuffinthemiddleislikelytobe.SeeFigure2-2.Thisiscalledatop-downparsebecauseitstartswithallthepossibleparsesandworksdownuntilitmatchestheactualcontentsofthedocument.

    Figure2-2.Top-downparsingofHTML

  • 2.1.Parse::RecDescentGrammars

    DamianConway'sParse::RecDescentmoduleisthemostwidelyusedparsergeneratorforPerl.Whilemosttraditionalparsergenerators,suchasyacc,producebottom-upparsers,Parse::RecDescentcreatestop-downparsers.Indeed,asitsnameimplies,itproducesarecursivedescentparser.Oneofthebenefitsoftop-downparsingisthatyoudon'tusuallyhavetosplitthedataintotokensbeforeparsing,whichmakesiteasierandmoreintuitivetouse.

    2.1.1.SimpleParsingwithParse::RecDescent

    I'macompulsiveplayeroftheJapanesegameofGo.[*]WegenerallyuseafileformatcalledSmartGameFormat(http://www.red-bean.com/sgf/)forexchanginginformationaboutGogames.Here'sanexampleofanSGFfile:

    [*]TheAmericanGoAssociationprovidesanintroductiontoGobyKarlBakercalledTheWaytoGo(http://www.usgo.org/usa/waytogo/W2Go8x11.pdf).

    (;GM[1]FF[4]CA[UTF-8]AP[CGoban:2]ST[2]RU[Japanese]SZ[19]HA[5]KM[5.50]TM[]PW[SimonCozens]PB[KeikoAihara]AB[dd][pd][jj][dp][pp];W[df];B[fd];W[cn](;B[dl])(;B[fp]CR[fp]C[Thisistheusualresponse.])(;B[co]CR[co]C[Thiswayisstrongerstill.];W[dn];B[fp]))

    http://www.red-bean.com/sgf/http://www.usgo.org/usa/waytogo/W2Go8x11.pdf

  • Thislittlegameconsistsofthreemoves,followedbythreedifferentvariationsforwhathappensnext,asshowninFigure2-3.Thefiledescribesatreestructureofvariations,withparenthesisedsectionsbeingvariationsandsubvariations.

    Figure2-3.Treeofmoves

    Eachvariationcontainsseveralnodesseparatedbysemicolons,andeachnodehasseveralparameters.Thissortofdescriptionoftheformatisidealforconstructingatop-downparser.

    Thefirstthingwe'lldoiscreatesomethingthatmerelyworksoutwhethersometextisavalidSGFfilebycheckingwhetheritparses.Let'slookatthestructurecarefullyagainfromthetopand,aswego,translateitintoagrammarsuitableforParse::RecDescent.

    Let'scallthewholethingagametree,sinceaswe'veseen,itturnsouttobeatree-likestructure.Agametreeconsistsofanopenparenthesis,andasequenceofnodes.Wecanthenhavezero,one,ormanyvariationsthesearealsostoredasgametreesandfinallythere'sacloseparenthesis:

    GameTree:"("SequenceGameTree(s?)")"

  • Readthisas"YoucanmakeaGameTreeifyousee(,aSe