Funzioni anonime

Mi è stato chiesto quale sia il vantaggio, o svantaggio, nell’uso delle funzioni anonime o inline (o onfly), utilizzate moltissimo in Javascript e, oramai con la 5.3, anche in PHP.
Una funzione inline, o anonima perché non ha – appunto – un nome, è un modo veloce per scrivere alcune procedure, indentando ad albero sequenze di callback ad esempio. Quasi tutti i linguaggi supportano la scrittura di funzioni di questo, ognuno al limite con le sue peculiarità e restrizioni. Possono anche avere nomi diversi e sintassi particolari, come i cosiddetti blocks in Objective-C.
Tuttavia, restringendo i casi al Javascript e al PHP, il loro aspetto è pressoché identico:

1
2
3
4
/* Con jQuery */
$('div#button').click( function() {
    alert( 'Clicked' );
});
1
2
3
4
/* In WordPress ad esempio */
add_filter( 'wp_head', function() {
   echo 'Test';
});

Gli esempi di sopra potevano essere scritti anche in questo modo:

1
2
3
4
5
/* Con jQuery */
function onClick() {
    alert( 'Clicked' );
}
$('div#button').click( onCLick );
1
2
3
4
5
/* In WordPress ad esempio */
function my_wp_head() {
   echo 'Test';
}
add_filter( 'wp_head', 'my_wp_head' );

Come risulta evidente, l’implementazione delle funzioni, anonime o non, rimane sempre la stessa e il guadagno sulla quantità di codice scritto è oggettivamente di poco conto, soprattutto su grande progetti (in definitiva si elimina il nome della funzione).

Se dovessimo giudicare i due esempi di sopra, senza porci ulteriori domande, il confronto si giocherebbe su un piano soggettivo e stilistico; c’è chi preferisce evitare le funzioni anonime perché spesso rendono il codice poco leggibile o chi le preferisce perché ama il codice compatto e con poche chiamate a funzioni.

Tuttavia ci sono delle considerazioni, alcune specifiche per determinate circostanze, che – almeno a me personalmente – tendono a farmi evitare, o quantomeno a limitare, l’uso delle funzioni anonime.

1. Leggibilità
Per esperienza diretta, soprattutto in Javascript, l’uso di funzioni anonime, dove a buon bisogno una richiama un’altra e un’altra, rende il codice poco chiaro, rischiando di commettere errori banali perché si è persa di vista una chiusura di una graffa o non si ha la percezione di trovarsi all’interno di una diversa funzione rispetto a quella di sopra, etc…, etc….

Inoltre le IDE di sviluppo, ovviamente, hanno difficoltà a visualizzare correttamente l’elenco delle funzioni di un codice che usa massicciamente funzioni anonime: non hanno un nome da mettere in elenco…

2. Riusabilità
Una funzione anonima, ovvero il codice che essa implementa, non può essere utilizzato più di una volta! Sembra ovvio, ma ciò ovviamente non è un bene. Riflettendoci è curioso che una funzione, che per definizione ha la caratteristica di poter essere utilizzata n volte, perda questa sua importante proprietà nell’uso di funzione anonima; ma dopotutto è in parte voluto.

Riprendendo l’esempio PHP di sopra, ma il concetto è valido anche per Javascript, ecco cosa accadrebbe nei due casi:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Primo filtro */
add_filter( 'wp_head', function() {
  // ...
  // Stessa implementazione
  // ...
});

/* Altro filtro */
add_filter( 'wp_footer', function() {
  // ...
  // Stessa implementazione
  // ...
});

/* Altro filtro ... */
add_filter( 'wp_sub_footer', function() {
  // ...
  // Stessa implementazione
  // ...
});

Ovviamente se si trova un difetto, o si migliora il codice in una delle funzioni anonime, bisogna duplicare questi cambiamenti in tutti gli altri casi. Diversa sarebbe la situazione con un codice standard:

1
2
3
4
5
6
7
/* Comune */
function my_wp_head() {
   echo 'Test';
}
add_filter( 'wp_head', 'my_wp_head' );
add_filter( 'wp_footer', 'my_wp_head' );
add_filter( 'wp_sub_footer', 'my_wp_head' );

In questo caso, paradossalmente, abbiamo risparmiato un bel po di codice scritto.

NOTA BENE: risulta penso ovvio che nessun sviluppatore lascerebbe tre o più blocchi di codice uguali. Appena ci si accorge che una porzione di codice è ripetuta più di una volta, a chiunque viene spontaneo trasformala – appunto – in funzione, con nome e cognome, in modo da essere richiamata quante volta vogliamo.

3. Identificazione
Per definizione, essendo anonime, possono essere usate onfly ma non richiamate o identificate, come detto nel punto precedente. Questo può essere di intralcio in casi particolari come:

1
2
3
4
5
6
7
8
/* Comune */
function my_wp_head() {
   echo 'Test';
}
add_filter( 'wp_head', 'my_wp_head' );
...
...
remove_filter( 'wp_head', 'my_wp_head' );

Qui, ad esempio, abbiamo una funzione `remove_filter()` che pretende, per completare il suo compito, il codice del filtro (`wp_head`) ma anche il nome della funzione! Questo, con le funzione anonime, sarebbe impossibile.

Questo ultimo esempio è forse il più illuminante in quanto, nel caso di PHP e WordPress, ci sono effettivamente moltissimi filtri che si impostano “al volo” una volta sola e che quindi ben si conformano all’uso delle funzioni anonime. Io, ad esempio, è proprio in questi casi che spesso ne abuso. Comunque, come mi è accaduto, nelle successive stesure del codice può capitare – spesso – di dover trasformare l’anonima funzione in una chiamata per nome.

In conclusione, dunque, le funzione anonime sono un ottimo strumento di sviluppo, fornendo spesso – durante la prima stesura del codice – una velocità sicuramente maggiore rispetto all’approccio ‘tutto in funzioni’. Come spesso accade, abusarne non è certo vantaggioso, sia in termini di funzionalità che di leggibilità del codice. Inoltre, in alcuni contesti il loro uso più che essere sconsigliato diventa non praticabile.

Non ci sono commenti per questo Post

Lascia un commento

TAG XHTML PERMESSI: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> INSERIMENTO CODICE:
<pre></pre> // blocco generico
                   <code></code> // blocco generico
                   [cc_actionscript][/cc_actionscript] // Actionscript
                   [cc_actionscript3][/cc_actionscript3] // Actionscript 3
                   [cc_css][/cc_css] // CSS Style Sheet
                   [cc_html][/cc_html] // HTML
                   [cc_js][/cc_js] // Javascript
                   [cc_objc][/cc_objc] // Objective-C
                   [cc_php][/cc_objc] // PHP
                   [cc_sql][/cc_sql] // SQL