-+  Associazione
-+  Documenti
-+  Eventi
-+  Community
-+  Blog
-+  Link

Ottobre 2013

Dom Lun Mar Mer Gio Ven Sab
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Cerca






 

« habemus perlfunc | Home | Mongers @ Webbit 2004 »

Omelia XII
22.04.04

Carissimi,

ho finito la lettura dell'Apocalisse 12 e, sobillato anche da larsen, ho deciso di tramutare ciò che inizialmente avevo pensato come un semplice "impressioni a caldo" in qualcosa di più corposo e articolato. Qualcosa che vuol essere una specie di riassunto di ciò che ho capito o mi ha colpito, e un modo anche per esercitarmi nella scrittura di pseudo-code in Perl6 :-)

Prevedo quindi di integrare questo post iniziale con ulteriori commenti, man mano che vado avanti nella digestione del corposissimo corpus Walliano.

Premessa

Come già Larry con "apocalisse", non intendo utilizzare la parola "omelia" nella sua accezione comune, di matrice ecclesiastica, di "sermone, spiegazione delle Sacre Scritture ai fedeli" (lungi da me l'idea di salire su un qualsivoglia pulpito!), ma nell'accezione più vicina all'etimo greco "homilìa", che sta per conversazione.

Mi piacerebbe che la conversazione non rimanesse monologo, quindi vi invito a partecipare correggendomi dove sbaglio, o aggiungendo dove tralascio, o riportando le vostre impressioni. Avete a disposizione la possibilità di commentare, quindi abusatene pure.

Gli oggetti nel quotidiano

Per quanto riguarda l'utilizzo "comune" di classi ed oggetti (i casi più semplici che rappresentano poi una buona percentuale dei casi totali, il quotidiano appunto), molto è stato fatto per rendere il più esplicito possibile ciò che dev'essere esplicito e il più implicito possibile ciò che dev'essere implicito.

La differenza principale sta nel fatto che un oggetto non è più esplicitamente, nel codice, una reference (quasi sempre, una reference ad un hash) sottoposta a bless, ma un qualcosa di "opaco" allo sguardo occasionale.

Per spiegarci meglio, vediamo come può essere implementata una semplice classe in Perl6:

    class Persona {
        has $.nome;
        has $.cognome;
        has $.soprannome = $.nome;

        method saluta {
            say $.soprannome ~ ": ciao";
        }
    }

    my $dada = Persona.new( nome => "Aldo", cognome => "Calpini");
    $dada.soprannome = "dada";
    $dada.saluta();
    my $nominativo = $dada.nome ~ " " ~ $dada.cognome;

Qui vediamo all'opera le sostanziali differenze:

  • attributi espliciti (non più chiavi di hash ma variabili introdotte da "has")
  • metodi espliciti (non più "sub" ma "method")
  • costruttore implicito ("new" non dev'essere definito)
  • metodi accessori (lettura/scrittura degli attributi) impliciti

Ovviamente, è sempre possibile implementare il tutto in maniera diversa (anche implementarlo con un hash, come ai bei vecchi tempi del Perl5). E' possibile scrivere un metodo "new", o "overloadare" le funzioni per accedere agli attributi che Perl6 crea per noi.

Ciò che mi piace particolarmente, di tutta questa implementazione, è l'innata ortogonalità delle operazioni: il fatto di fornire un "new" di default, ad esempio, non deriva da qualche magia nera, ma semplicemente dal fatto che ogni classe eredita, volente o nolente, dalla classe Object, la quale implementa appunto il metodo new in questione.

Privacy

Si possono (finalmente, sospirerà qualcuno) creare attributi, e perfino metodi, davvero "privati", nel senso che sono interni alla classe e nessuno, neanche con i salti mortali (immagino), può utilizzarli dall'esterno.

L'identificatore che segnala la nostra richiesta di riservatezza sono i due punti:

    class Personalita {
        has @.:inconscio;

        method :rimozione( $self: $indesiderato ) {
            push(@self.:inconscio, $indesiderato);
        }
    }

Nessuno potrà vedere ciò che c'è nel nostro inconscio, né tantomeno interferire con i nostri meccanismi di rimozione :-)

Ereditarietà

Non molto da dire, se non che non si usa più @ISA, ma si danno esplicitamente dei "tratti" alla classe:

    class Utente is Persona {
        has $.login = $.nome;
        has $.password;
        has $.home = "/home/$.login";
    }

    class Luser is Utente is Incompetente is Seccatura; # :-)

Classi e Ruoli

Una novità (a mio avviso meravigliosa) che porterà il Perl6 per sfruttare al meglio le potenzialità della programmazione OO è quella dei ruoli. I ruoli non sono "propriamente" classi, o meglio sono classi, ma dalle quali non è possibile costruire direttamente oggetti.

Quello che permettono di fare i ruoli, fondamentalmente, è di costruire classi complesse, o gerarchie di classi, non solo tramite il meccanismo dell'ereditarietà ma tramite quello della "composizione".

    role Programmatore is {
        has @.linguaggi_conosciuti = <<nessuno>>;
        method scrivi_codice($linguaggio, $righe) {
            die unless @.linguaggi_conosciuti ~~ $linguaggio;
            sleep($righe*10);
        }
    }

    class Dipendente is Utente {
        has $.matricola;
        does Programmatore;
    }

Non solo: è possibile associare dei ruoli ad oggetti già creati! Questo permette di creare dei "mixin", una sorta di oggetti ibridi, creati secondo una classe, ma che assumono in seguito (in qualunque momento decidiamo noi) tratti di un'altra classe:

    my $dada = Persona.new();
    $dada does Programmatore;
    push($dada.linguaggi_conosciuti, 'Perl');

Ovviamente, l'implementazione dell'operatore di match, quando applicato ad oggetti, utilizza quindi il metodo .does (invece di .isa) che ritorna un valore vero sia per la classe propria dell'oggetto, che per classi ereditate, che per ruoli in qualunque modo "assegnati" ad esso:

    if($dada ~~ Programmatore) {
        $dada.scrivi_codice(linguaggio => 'Perl', righe => 1000);
    }

Delegare, delegare, delegare

Un ulteriore meccanismo a disposizione del disegnatore di classi è quello della "delegation", ossia il demandare ad altre classi la gestione di alcuni metodi. L'implementazione prevede sempre e comunque un attributo che contenga il riferimento ad un oggetto della classe alla quale si intende delegare.

    class Dipendente is Persona {
        has Qualifica $.ruolo handles 'lavora';
    }

in questa maniera

    $dada.lavora(); # è in realtà $dada.ruolo.lavora();

La cosa particolarmente carina è che si possono usare anche espressioni regolari per decidere quali metodi delegare:

    class Persona {
        has Schiavo $.schiavo handles (/[lava | pulisci | stira]/);
    }

E abbiamo così delegato al nostro "Schiavo" tutti i lavori di casa :-)

Altro

L'Apocalisse contiene molto, molto di più, incluse modifiche al linguaggio decise da Larry e team nel tempo trascorso dalla pubblicazione dell'ultimo documento e che poco o nulla hanno a che fare con l'OOP. Degli argomenti principali, quelli che mi risultano meno chiari sono:

  • submetodi
  • "alias" privati di classi
  • in generale, tutto il meccanismo di dispatch :-)
  • AUTOLOAD e i suoi nuovi amici AUTOMETH, AUTOMETHDEF, etc.
  • definizione dei tipi

Mi riprometto di studiarmeli meglio per la prossima volta :-)

cheers,
Aldo

Inviato da dada il 22.04.04 19:08
Ti è piaciuto questo articolo? Iscriviti al feed!

Inviato da Cosimo il 27.04.04 00:22

Ciao,

il tuo intervento e' molto interessante. L'ho letto con entusiasmo. Mi suggerisce una riflessione sui ruoli, che mi sembrano una caratteristica veramente "potente", anche se non credo di coglierne tutti gli aspetti. Possono essere considerati l'approccio di perl 6 all'aspect programming? (o almeno al suo distillato pratico, tolta tutta la fumosa teoria?)

Inviato da dada il 27.04.04 14:33

ciao Cosimo.

in realtà so molto poco, se non nulla, dell'aspect programming. ho trovato questi 2 articoli che mi accingo a leggere:


http://www.theserverside.com/articles/article.tss?l=AspectOrientedRefactoringPart1 e http://www.theserverside.com/articles/article.tss?l=AspectOrientedRefactoringPart2.

se hai qualche testo introduttivo sull'argomento da consigliarmi (o ne puoi postare tu una versione molto sintetica qui sul blog :-) fammelo sapere.

cheers,

Aldo

Inviato da larsen il 27.04.04 17:41

Cosimo, aggiungo che se vuoi scrivere nuove entry nel blog (e non semplicemente risposte ad entry di altri) puoi mandare una mail a me.

Inviato da dada il 28.04.04 15:02

Cosimo,

ho letto qualcosa sull'AOP, e anche se non ho ancora ben chiara la tua distinzione fra "distillato pratico" e "fumosa teoria", mi sento già di poterti dare qualche risposta.

mi sembra di capire che l'AOP sarà pienamente supportata in Perl6, ma non (o non necessariamente) tramite i ruoli; nella sesta Apocalisse Larry Wall introduce il metodo .wrap per le subroutine (ma generalmente, per qualunque oggetto di tipo codice).

questo dovrebbe essere lo strumento base per l'implementazione dell'AOP (ne parla lo stesso Larry), anche se di per sé non implementa gli Aspect come unità modulari. mi viene in mente un possibile (ovviamente, è codice non testato :-) esempio di come aggiungere azioni prima e dopo ogni chiamata di metodo di una classe:

    foreach ($class.meta.getmethods()) -> $method {
        $method.wrap( {
            log($somewhere, "calling $(class).$(method)");
            call;
            log($somewhere, "called $(class).$(method)");
        } );
    }

ovviamente, all'interno del ciclo è possibile inserire direttive per restringere il "pointcut" dell'aspetto in questione.

per un'implementazione più "astratta" dell'AOP immagino sia possibile utilizzare in qualche modo i ruoli, accedendo ai metadati della classe alla quale il metodo viene applicato. dato che la definizione di una classe è semplicemente un blocco (o closure) che viene eseguito dal runtime in qualche fase BEGIN o giù di lì, immagino sia possibile interferire in ogni modo e maniera con l'applicazione stessa di un ruolo ad una classe.

di per loro, i ruoli non sono altro che unità di composizione delle classi. come spiega anche Larry, possono "degenerare" in semplici interfacce (a la Java, tanto per capirsi) se contengono solo metodi "virtuali" (ossia pure dichiarazioni senza definizione), ma possono anche contenere intere definizioni di classe, compresi attributi, che vengono semplicemente "pacchettizzate" all'esterno e possono quindi essere applicate a N classi.

infine, i ruoli forniscono il supporto per i mixin objects, che sono a mio avviso molto, molto potenti. e tra l'altro, mi sembra che proprio una peculiarità di AspectJ sia quella di fornire la possibilità di creare mixin in Java.

spero di aver contribuito a chiarirti un po' le idee (sicuramente tu hai contribuito a chiarire un po' le mie :-). se hai qualche esempio concreto di cosa intendi per AOP e di come lo utilizzeresti, rispondimi pure che vedrò di spremermi un altro po' le meningi :-)

cheers,

Aldo

Inviato da Cosimo il 28.04.04 15:06

Ho dato un'occhiata molto veloce agli articoli che hai riportato, e devo dire che sono quanto di meglio mi sia capitato di leggere finora sull' AOP. Altri articoli, che dovrebbero essere introduttivi, mi sono sembrati (quasi) tutto fumo e (quasi) niente arrosto. Ne riporto un paio:

http://www.ccs.neu.edu/home/lieber/AOP.html

http://openmap.bbn.com/~kanderso/aop/AOP-thoughts.html

L'altro che volevo segnalare l'ho visto anche nella "bibliografia" di quelli citati da te, ed e':

http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect.html

In ogni caso, credo che questi articoli evidenzino un'impostazione "java", piuttosto che presentare i concetti in maniera "neutra".


Perdonatemi l'attegiamento eretico e poco accademico, ma se ho capito la faccenda (e in una certa misura ne dubito) tutto il concetto dell'aspect programming si ridurrebbe ad un preprocessore java un po' piu' intelligente del normale.


In ambienti a noi piu' consoni (perl), e' chiaro che questo "inserimento dinamico di codice" sarebbe completamente eseguito a run-time, senza estensioni + o - interessanti del linguaggio.

Inviato da Cosimo il 04.05.04 20:59

Ciao Aldo,
grazie del tuo messaggio, anche tu hai contribuito parecchio a chiarirmi le idee, anche direi in generale su qualche aspetto di perl6.

Per quanto concerne l'AOP, mi sto documentando soltanto da qualche settimana e molto sporadicamente, non ho neanche un esempio valido per poter fissare le idee.

Probabilmente usando Perl, le esigenze che hanno motivato l'AOP si sentono un po' meno...

Inviato da dada il 21.05.04 18:28

proseguo con la prossima puntata della mia Omelia. innanzitutto...

Errata Corrige

Riguardando il codice da me scritto, ho notato diversi errori (cose che capitano quando scrivi codice senza testarlo, eh :-). Siccome mi ritengo, nel bene e nel male, un individuo pressappoco nella media, penso siano errori nei quali sia piuttosto facile cadere, quindi ritengo che valga la pena di commentarli un po' e di capire anche perché ho commesso tali errori.
  • Nel primo paragrafo, "Gli oggetti nel quotidiano", questa riga non funziona come io intendevo funzionasse:

        has $.soprannome = $.nome;
    

    Ossia, non assegna $obj.soprannome uguale a $obj.nome, nel caso un soprannome non venga fornito, quando $obj viene creato. Gli assegna, invece, un bel undef.

    Questo perché l'assegnazione di un valore di default ad attributi è in realtà l'assegnazione di un "tratto", che altro non è se non una closure che verrà eseguita al momento della creazione dell'oggetto.

        has $.risposta = 42;
        # equivale a ...
        has $.risposta is build(42);
    

    Quindi, passando semplicemente $.nome, ho preso un riferimento all'attributo di classe, non dell'istanza. In pratica, ciò che $.nome contiene al momento della costruzione stessa della classe, ossia appunto undef. Per valutare $.nome come "la proprietà assegnata all'oggetto che sto instanziando", dovrei costruire appunto una closure in modo da "ritardarne" la valutazione al momento opportuno:

        has $.soprannome = { $.nome };
    
        # tanto per chiarire il concetto,
        # in perl5 sarebbe espresso come: 
        # has $.soprannome = sub { return $.nome };
        
        # che equivale a:
        has $.soprannome is build( { $.nome } );
        # oppure
        has $.soprannome will build { $.nome };
    

    Lo stesso dovrebbe valere anche per la classe Utente presentata nel paragrafo "Ereditarietà", che quindi va intesa come:

        class Utente is Persona {
            has $.login = { $.nome };
            has $.password;
            has $.home = { "/home/$(.login)" };
        }
    
  • Sempre nel primo paragrafo, ho dimenticato anche un'altra cosa: per default, gli attributi sono readonly. Se voglio che il metodo accessorio possa anche scrivere nell'attributo devo esplicitamente dargli un tratto rw:

        has $.nome is rw;
    

    Nel mio caso, poiché voglio che tutti gli attributi definiti siano read-write, posso dare il tratto alla classe, in modo che tutti gli attributi lo "ereditino" da lì:

        class Persona is rw {
            has $.nome;
            has $.cognome;
            # ...
        }
    
  • Per finire, nel paragrafo "Classi e Ruoli" c'è un lapsus che deriva forse dalla "troppa" somiglianza del Perl6 col linguaggio naturale :-)

        role Programmatore is { ... }
        # dovrebbe essere
        role Programmatore { ... }
    

E ora possiamo tornare al resto della nostra trattazione...

Metodi, Submetodi, Multimetodi

Tutti sappiamo, più o meno, cos'è un metodo. Abbiamo visto che possono esserci metodi pubblici (dichiarati con method) e metodi privati (il cui nome inizia con :). La cosa interessante è che, se all'interno della mia classe definisco delle sub, queste non definiscono in nessun modo dei metodi:

    class Utente is Persona {
        has $.password;
        
        sub verifica_password($password) {
            return false if $password.chars &lt; 8;
            # ...
            return true;
        }
        
        method autentica($self: ) {
        	if( verifica_password($self.password) ) {
        		# ...
        	} else {
        		return 0;
        	}
        }
    }

In questo caso, verifica_password è una funzione (non un metodo), richiamabile dai metodi della mia classe ma solo come sub. In pratica, è slegata da ogni istanza.

Immagino, ma non mi sembra sia detto esplicitamente nell'Apocalisse, che sia possibile richiamare tale funzione anche dall'esterno della classe:

    if( Utente::verifica_password( "blahblah" )) {
        say "la password è ok";
    }

La stessa cosa dovrebbe essere vera anche per i metodi normali:

    if( Utente.autentica() ) {
        say "benvenuto";
    }

Occhio però che in questo caso $self è la classe stessa, non un'istanza di utente (il che implica probabilmente che l'autenticazione non avrà mai successo :-). Se si vuole invece esplicitamente negare un simile utilizzo, occorre definire il tipo dell'invocante:

    method autentica(Utente $self: ) { ... }

In questo caso la chiamata effettata sopra non sarebbe permessa, perché "Utente" è un oggetto di tipo "Class", non di tipo "Utente".

E fin qui, nulla di particolarmente nuovo (perlomeno rispetto a come venivano utilizzati i metodi in Perl5). Oltre alla forma "normale" dei metodi, abbiamo però due varianti: la prima, il submetodo, è semplicemente un modo per raffinare un po' il meccanismo dell'ereditarietà.

Un submetodo (chiamato submethod) è un metodo a tutti gli effetti, solo che non viene ereditato dalle subclassi. Un esempio:

    class A {
        method foo { say "A::foo" };
    }
    
    class B is A {
        submethod foo { say "B::foo" };
    }
    
    class C is B { ... }
    
    my $obj = C.new();
    $obj->foo();

In questo caso viene stampato "A::foo", poiché $obj (che è di classe C) eredita dalla classe A, e non dalla B, il metodo foo.

L'utilizzo dei submethod dovrebbe essere utile, ad esempio, per i costruttori e i distruttori, che generalmente sono specifici di una classe; chi subclassa da noi può scegliere se implementare il proprio costruttore, oppure ereditare quello di default (di Object), piuttosto che ereditare il nostro. Sinceramente non mi è del tutto chiara, in realtà, la reale utilità dei submetodi. Se a voi viene in mente qualcosa in merito, sono tutto orecchie :-)

Veniamo dunque ai multimetodi, che sono invece delle bestie totalmente differenti. Con i multimetodi, in pratica, è possibile implementare il polimorfismo, ossia diverse funzioni con lo stesso nome che vengono distinte in base al tipo (o numero) dei loro parametri.

Un multimetodo viene preceduto dalla parola chiave "multi" e dovrebbe funzionare pressappoco così:

    class Point {
        has $.x is rw;
        has $.y is rw;
        
        multi method add(Point $self, $x, $y) {
        	$self.x += $x;
        	$self.y += $y;
        }
        
        multi method add(Point $self, $offset) {
            $self.x += $offset;
            $self.y += $offset;
        }
    }

I multimetodi in realtà possono essere anche multisub (quindi fuori da classi), cosa che ritorna particolarmente utile per implementare l'overloading degli operatori:

    multi sub infix:+ (Point $a, Point $b) {
    	$a.x += $b.x;
    	$a.y += $b.y;
    }
    
    multi sub infix:+ (Point $a, Num $offset) {
    	$a.x += $offset;
    	$a.y += $offset;    
    }

Tratti d'artista

C'è una cosa che mi ha davvero colpito. Letteralmente colpito, nel senso che leggendola non avevo affatto realizzato cosa volesse dire. Ripensandoci, qualche giorno fa, ho improvvisamente apprezzato tutte (credo) le implicazioni della questione.

Sto parlando dell'implementazione, o meglio della re-implementazione alla luce di ciò che rivela l'Apocalisse 12, dei tratti. Già dalla seconda Apocalisse erano stati introdotti i seguenti costrutti:

    my $pi is constant = 3.14;
    sub name is rw { ... }
    return 0 but true;

So far, so good. Ma quello che è sconvolgente è questo: i tratti non sono nient'altro che dei mini-ruoli. Una variabile a cui viene associato un tratto non è altro che un mini-mixin object.

Seguitemi nella dimostrazione, perché mi rendo conto che non è facile capirlo così su 2 piedi:

    role answer {
    	has Int $.answer = 42;
        method trait_auxiliary:is(answer $trait: Any $container: ?$arg) {
            $container does answer;
            if defined($arg) {
                die "wrong answer" unless $arg == 42;
                $container.answer = $arg;
            }    		
        }
    }

    my $x is answer(43);

Chiaro? "answer" è un tratto, che può essere associato ad una variabile qualunque (e abbiamo anche la possibilità di "intercettare" tale associazione tramite il metodo is), e prende automaticamente l'attributo che ha lo stesso nome del tratto come valore del tratto in sé. Ne consegue che l'ultima riga è, in realtà, solo "syntactic sugar" per:

    my $x does answer;
    $x.answer = 43;

Vi chiederete, allora, che senso ha trattarli come tratti invece che come ruoli? Innanzitutto la sintassi, che è decisamente più dolce, e secondariamente il fatto che non necessariamente un tratto deve specificare "$container does foo" (anche se sarebbe meglio). Questo permette di implementare i tratti in maniera praticamente "invisibile" (pensate all'encapsulation) e spiega il gioco di parole di Larry fra "trait" e "traitor".

Quello che viene fatto, in ogni caso, è molto semplice: viene costruita una nuova classe anonima per l'oggetto container ($x, nel nostro caso) che "eredita" (o meglio, viene composta da) l'eventuale classe di $x più il ruolo/tratto/traditore che gli viene assegnato.

La cosa appare più evidente, a mio avviso, nelle proprietà (variante a runtime dei tratti, introdotti dalla parola chiave "but") che, oltre a creare una classe anonima, creano anche una copia del container:

    $x but answer(42);
    
    # vuol dire:
    
    $temp = $x;
    $temp does answer;
    $temp.answer = 42;

C'è infine un ultimo zuccherino riguardante la dichiarazione delle proprietà:

    my property answer;
    
    # vuol dire:
    
    role answer {
    	has $.answer is rw = 1;
    }

Il che, semplicemente "ereditando" il builtin globale multi sub *trait_auxiliary:is {...}, è del tutto equivalente all'esempio fatto sopra (in questo caso accettiamo che la proprietà possa avere qualunque valore: se vogliamo più controllo, basta definire esplicitamente il ruolo come piace a noi).

Versioning e introspezione

Una delle novità del Perl6 sarà la possibilità, tramite il versioning delle classi, di conservare in @INC più versioni di uno stesso modulo. Come questo sarà implementato a livello di filesystem è ancora da definire, ma a livello di linguaggio sarà possibile, ad esempio, definire:

    class Foo-1.00-ACALPINI { ... }

Per indicare che questa è la versione 1.00 della classe Foo, ed è mia (utilizzando l'ID del CPAN, ad esempio). Similarmente, sarà possibile da uno script dire:

    use Foo-1.00-ACALPINI;

Mentre l'indicazione "classica" a cui siamo abituati:

    use Foo;
    
    # equivale a...
    
    use Foo-(Any)-(Any);

Che dovrebbe autonomamente ricercare la versione più recente installata del modulo Foo. Da notare che specificare un numero di versione vuoldire esattamente quel numero di versione, quindi per indicare "la 1.00 o successive" bisogna specificare un range:

    use Foo-(1.00..);

I "metadati" associati ad una classe saranno accessibili tramite l'oggetto "meta", che identifica l'istanza della MetaClass derivante dal parsing della classe stessa nel codice:

    $obj.meta.class;   # Foo
    $obj.meta.version; # 1.00
    $obj.meta.author;  # ACALPINI

L'oggetto meta è anche l'oggetto che si occupa di fornire l'introspezione. Sono definiti, per ora, i seguenti metodi:

   $obj.meta.isa(class);
   $obj.meta.does(class|role);
   $obj.meta.can(method);
   $obj.meta.getmethods();
   $obj.meta.getattributes();

Il primo e il terzo sono (più o meno) già disponibili in Perl5. Del secondo abbiamo già parlato riguardo ai ruoli. Gli ultimi due, infine, permettono di ispezionare una classe fin nel suo più intimo.

Da notare che, se l'oggetto meta ha un metodo (ad esempio "isa") e la classe stessa invece non lo ha, chiamando il metodo direttamente sull'oggetto, la classe Object (dalla quale tutti gli oggetti ereditano) passa la chiamata all'oggetto meta. Ergo, non è generalmente necessario scrivere $obj.meta.isa ma basta scrivere $obj.isa (a meno che la classe di $obj non implementi un metodo isa, cosa che non dovrebbe comunque fare :-).

E per stavolta è tutto. Rimanete sintonizzati per la terza puntata :-)

cheers,

Aldo

Inviato da dakkar il 11.06.04 16:46

Mi sembra che la differenza tra 'traits' e 'roles' sia, sostanzialmente, che 'roles' sono più "puliti": si comportano bene con la struttura delle classi; invece i 'traits' possono fare un bel po' di porcate... almeno, è quello che ho capito dall'Apocalisse. Aspetto l'Esegesi, Damian è uno dei pochi che capisce bene quello che pensa Larry...










Devo ricordare i dati personali?






D:
Sull'autore...
D:
La ML di Perl.it
Iscriviti! mongers@lists.perl.it è la lista ufficiale di Perl Mongers Italia per porre quesiti di tipo tecnico, per rimanere aggiornato su meeting, incontri, manifestazioni e novità su Perl.it.
D:
Annunci Google