| |||
| © Perl Mongers Italia. Tutti i diritti riservati. | |||
Capita ogni tanto che, sul canale IRC #perl.it, qualcuno o qualcosa venga ad accendere una scintilla d'interesse in una altrimenti grigia e noiosa giornata lavorativa. Cos'è un canale IRC, chiedete? Quello che comunemente passa sotto il nome di chat, e nella fattispecie la chat sulla quale si possono trovare molti degli autori di Perl.it (praticamente tutti). Se qualcuno di voi sta pensando che la chat sia una cosa da scellerati perdigiorno o adolescentelli brufolosi che non hanno una vera vita, si dovrà ora ricredere. Perlomeno per quanto riguarda i brufoli, che personalmente avevo una quindicina d'anni fa :-) La scintilla, dicevamo, si è accesa qualche giorno fa (era giovedì 23 novembre 2006), quando gaspa ci ha "sfidato" parlando d'introspezione. Più che un articolo, di fatto questo è un racconto: direttamente dalla "viva voce" di #perl.it (i commenti, ovviamente, sono miei e quindi di parte :-). Premetto che l'argomento "tecnico" potrebbe risultare ostico a chi si è avvicinato da poco al Perl. Chi, al contrario, ama cimentarsi in questioni di lana caprina e intricati sofismi, è ovviamente invitato a proseguire la discussione utilizzando i commenti. Buona lettura... Presentiamo innanzitutto rapidamente i personaggi di questa storia: dada, che sono io; dree e dakkar, due delle "colonne" di #perl.it; e infine gaspa, giovane e promettente perlista. La scena inizia, dunque, proprio con l'ingresso in canale di gaspa. Ahi ahi. Ha tirato fuori Ma cos'è precisamente una symbol table? Come dice il nome, è la tabella di tutti i simboli definiti in un determinato package. Provate questo semplice script sul vostro Perl:
use Data::Dumper;
print Dumper \%main::;
Uscirà fuori, probabilmente, un sacco di robaccia. Ma se guardate più attentamente, noterete che alcuna di quella "robaccia" sembra avere un senso... Ad esempio, ci troviamo chiavi tipo
use Data::Dumper;
$x = 42;
print Dumper \%main::;
Se confrontate l'output con quello dello script precedente, vedrete una riga in più:
'x' => *::x,
Cosa vuol dire? Che stavolta nel package Torniamo al canale, dove gaspa aveva buttato là un improbabile Ma gaspa non demorde, e rilancia. Ecco il punto. Quello che si chiama introspezione, nel gergo del programmatore, indica la possibilità di un linguaggio di ispezionare, appunto, le proprie strutture dati; ossia, le variabili definite, le funzioni, classi, metodi, etc. In sostanza, il programma stesso che il linguaggio sta in quel momento eseguendo. Nobile intento davvero. Ma rimane il problema di come accedere alle chiavi di Col senno di poi, bisogna dire che dree aveva (quasi) ragione. Ma lì per lì non sono stato molto a ragionarci e, come mio solito, ostentando sicumera le ho sparate grosse :-) La buona volontà di gaspa è encomiabile, ma la sintassi Finché non si rende conto da solo di non essere sulla buona strada. Chissà che cosa stava provando a fare... durante la mia assenza, un'altra "stoccata" di dree. Ad essere sincero, mi sono accorto di questo suggerimento di dree solo riguardando i log. Sta di fatto che esiste un modulo, chiamato Devel::SymDump, che non abbiamo menzionato ma che fa esattamente il lavoro che gaspa stava cercando, in qualche modo, di riprodurre. Un punto per dree++. Io, nel frattempo, mi ero messo a cercare uno script che ricordavo di aver scritto svariati anni prima, per la precisione questo. Nella sub Ho tirato in ballo un sacco di concetti (col segreto intento, ovviamente, di seminare il panico :-). Un typeglob è una bestia strana, in Perl. Ed è appunto quello che viene puntato, nella symbol table, dal nome che gli corrisponde. Se riprendete l'esempio precedente, quando abbiamo scritto In due parole, un typeglob rappresenta tutte le variabili, a prescindere dal "sigillo", di un certo nome (il sigillo sarebbe il
*x # typeglob
*x{SCALAR} # slot scalare (ossia $x)
*x{ARRAY} # slot array (ossia @x)
*x{HASH} # slot hash (ossia %x)
*x{CODE} # slot codice (ossia sub x)
*x{IO} # slot filehandle (ossia open x, ...)
E a cosa serve una cosa del genere, chiedete? Beh, storicamente i typeglob sono gli antenati delle reference (c'erano già ai tempi del Perl 4); inoltre, fino a qualche versione di Perl fa, erano l'unico modo per passare un filehandle come argomento ad una subroutine, quindi potreste aver visto codice del tipo:
open(FILE, ">output");
print_report(*FILE);
Oggi, però, si preferisce a quest'idioma il più moderno:
open(my $file, ">output");
print_report($file);
Infine, come abbiamo già detto, i typeglob sono appunto quello che viene "puntato" dalle chiavi presenti nella symbol table. Intanto, sul canale, non sapendo ancora cosa m'aspetta proseguo spavaldo nella mia esposizione. Ora, per chi non lo conoscesse, dakkar è il castigamatti di #perl.it. Non importa di cosa si stia parlando, se Perl o teoria degli automi a stati finiti o biologia macromolecolare o omelette al prosciutto, se qualcuno in canale si lascia sfuggire anche una lieve imprecisione, dakkar arriva con puntualità svizzera e spiega, con dovizia di particolari, dove e perché stai sbagliando. dakkar, per definizione, sa. Mi metto, quindi, tranquillamente in attesa della bastonata... Che è poi fondamentalmente quello che tentavo di dire io. Il fatto di utilizzare il typeglob in assegnazione non mi era in effetti venuto in mente, ma si stava parlando di utilizzarlo in lettura... Un po' titubante, cerco di vedere se ho capito bene. Heh. Ovviamente non avevo capito come mi sembrava. Per fortuna, non sono il solo :-) La cosa si fa divertente: sembrava tutto chiaro, e ora siamo in 3 ad avere dubbi. Ci deve essere qualcosa che ci sfugge... Da parte mia, tento di chiuderla lì con una boutade. gaspa sembra quasi convinto. Ma c'è quel quasi che non gli torna, e mi spinge ad espormi con qualche riga di codice dal succitato programmino... cosa che ovviamente suscita le ire del dakkar! Eh si, dakkar ha ragione. Non sto usando il typeglob, né tantomeno sto accedendo alla symbol table del package. Sto componendo il nome tramite una stringa, come si fa ad esempio in:
$pippo = "ciao";
$pluto = "pippo";
print ${$pluto}; # stampa "ciao"
Tale pratica, solitamente, viene punita seduta stante col bacchettamento delle dita. Innanzitutto non funziona con le variabili Hah! L'infame, ci lascia così. Beh, del resto era piuttosto tardi. La sintassi però l'ha trovata, ed è la stessa che dree aveva proposto circa 15 minuti prima. Un altro punto per dree++. Rimane però da capire cosa fare con questi benedetti typeglob. Ovviamente, la prima cosa che faccio è digitare Ancora qualche minuto di lettura, un po' di "distrazione" lavorativa, ed ecco che mi sembra di aver trovato il bandolo della matassa. La cosa suscita immediatamente la sardonica ammirazione di dree. Spiritosi... intanto però funziona. Ma gaspa ancora non si arrende. Del resto, io l'avevo detto. L'aveva detto pure dakkar. E' nella natura dei typeglob non dare, tout court, informazioni sul "tipo" che giustifica la loro presenza nella symbol table. Inaspettatamente però, gaspa mi smonta l'adorabile abuso di graffe, semplificando il tutto con la sintassi che stavamo cercando fin dall'inizio (!!!). Lui l'ha capita, finalmente. Io ancora no :-) Mi sento mancare un po' la terra sotto i piedi, quindi tento ostinatamente di salire in cattedra. Il che mi sembra una spiegazione pertinente del perché da un typeglob non posso sapere il "tipo". È che, tutto preso dal capire come "dereferenziare" un typeglob, avevo perso un po' di vista l'obiettivo dell'introspezione. In realtà, il codice di gaspa avrebbe dovuto essere scritto Sono alle corde... Non mi resta che contrattaccare :-) La "singolar tenzone" volge al termine senza vincitori né vinti, come nelle migliori guerre. Alla fine, è proprio gaspa a darci la morale di questa storia. Tutto è bene quel che finisce bene :-) | |||