Přednáška #6: Moduly a objekty (perlmod, perlmodlib, perlootut, perlobj) ############################## Balíčky (packages) ================== package Bear::Burrow; <-- platí do konce bloku/souboru $abc <-- hledá se v aktuálním balíčku $Bear::Burrow::bears <-- jméno s balíčkem (není relativní!) $::bears $main::bears <-- odkaz na "hlavní" balíček STDIN, STDOUT a spol. <-- výjimky, které se hledají v mainu CORE::print <-- pokud jste si print zastínili lokálním jménem %Bear::Burrow <-- tabulka symbolů (read-only) *Bear::Burrow::x{CODE} <-- položka v tabulce symbolů (read-write) Phasery ======= BEGIN { ... } <-- kód vyhodnocovaný v době kompilace END { ... } <-- po ukončení programu (včetně die) INIT { ... } <-- těsně před spuštěním programu Moduly ====== require $file; <-- načte modul a vykoná všechen jeho kód, pozor na návratovou hodnotu (pokud už je modul načten, neudělá nic) require Bear::Burrow; <-- najde modul podle balíčku (pozor, modul může definovat jiné balíčky) use Bear::Burrow; <-- BEGIN { require + import symbolů (viz níže) } Exportování symbolů =================== use parent 'Exporter'; our @EXPORT = qw(func $var); <-- exportuje se automaticky our @EXPORT_OK = qw(xyz); <-- exportuje se jen na požádání use Pkg; <-- importuje vše z @EXPORT use Pkg (); <-- neimportuje nic use Pkg qw(a b c); <-- importuje vyjmenované symboly no Pkg qw(a); <-- odstraní importovaný symbol Co se děje uvnitř: - use se vykoná v čase kompilace - pomocí require se nahraje modul - zavolá se jeho metoda import zděděná z Exporteru (viz níže) - import kopíruje symboly mezi tabulkami - "no ..." volá metodu unimport Pragmatické moduly (perlmodlib, perlpragma) ================== [implementace: definují funkci import, která provede danou akci] use strict; use warnings; use utf8; use bignum; <-- aritmetika s velkými čísly use feature 'what'; <-- povoluje nové featury jazyka use integer; <-- aritmetika je celočíselná use lib 'cesta'; <-- nastaví cestu k modulům use less 'cpu'; <-- :-) Objekty ======= bless $ref; <-- nastaví, že k odkazované datové struktuře patří aktuální balíček (balíčky se chovají jako třídy) $ref->method($a); <-- zavolá method($ref, $a) v příslušném balíčku (metoda objektu) Pkg->method($a); <-- zavolá method('Pkg', $a) v balíčku Pkg (metoda třídy) ref $a; <-- pro referenci na blessnutý objekt vrací 'Pkg' Příklad ======= package Dog; sub new { my ($class) = @_; return bless {}, $class; <-- $class bude třeba kvůli dědičnosti } sub wag_tail { my ($self) = @_; ... } 42; my $dog = Dog->new; <-- takto se třída používá $dog->wag_tail; my $dog = new Dog; <-- také možno, ale pozor na funkce v aktuálním balíčku wag_tail $dog; Atributy ======== Jazyk nic takového nedefinuje. Zvyk: položky v blessnutém hashi. Accessory: $obj->attr, $obj->attr($value) Dědičnost ========= Není zabudovaná, třídy se musí shodnout na implementaci. Podpora v jazyce: @ISA <-- třída může určit seznam tříd, ze kterých dědí use parent qw(...); <-- načte moduly a přidá je do @ISA; detekuje cykly use base qw(...); <-- používalo se dříve (podobné chování) UNIVERSAL <-- je automaticky předkem všech tříd $obj->isa('Pkg') <-- otestuje, zda je objekt daného typu (i nepřímo) Class->isa('Pkg') <-- otestuje, zda je třída potomkem jiné (i nepřímo) $obj->class('m') <-- otestuje, zda má objekt metodu daného jména Konstruktor volá konstruktor předka, předáváme $class. $obj->method; <-- nejprve třída, pak její předek (předkové) $obj->SUPER::method; <-- metoda předka (vzhledem k aktuálnímu balíčku!) Vícenásobná dědičnost ===================== Komplikace s konstruktory Hledání správné metody: default je DFS + cache use mro 'c3'; <-- přepne na jiný algoritmus (zaručuje, že třída se prohledá až po potomcích) Speciální metody ================ sub AUTOLOAD { ... } <-- volá se na neznámé metody, v $AUTOLOAD najde, jaká metoda byla zavolaná sub DESTROY { ... } <-- destruktor, volá se před uvolněním objektu a také na samém konci běhu programu (pozor na pořadí!) ${^GLOBAL_PHASE} <-- "DESTRUCT" při závěrečném destruování objektů Objektové systémy ================= use Class::Tiny qw(attrs...); <-- dodá accessory a konstruktor use Class::Accessor; <-- vylepšená verze use Moose; <-- těžkotonážní, ale velmi mocné