Newsgroup: it.comp.programmare
Titolo: Funzioni nidificate: ma servono?

Qualcuno qui ha mai definito funzioni dentro altre funzioni, come si può 
fare in C/C++? Ma è una cosa utile oppure non capita praticamente mai di 
doverlo fare o di servirsene?
 
A ee sembra una complicazione inutile... se serve una funzione in più la 
si può sempre definire a parte, no?

 si puň sempre definire a parte, no?
 
No. Non necessariamente puoi: non potresti avere una closure. L'idea e'
che tipicamente la funzione interna ha accesso al contesto della
funzione esterna.
 
E' un meccanismo potentissimo. Arrivo a dire che cerco di non
programmare in linguaggi che non lo consentono.
 
-- 
-riko
http://www.enrico-franchi.org/
 
http://rik0-techtemple.blogspot.com/
 

 funzione esterna.
 
Dici che ci sono casi in cui una "nested function" non e' sostituibile? 
  Mi faresti un esempio? Ciao.

 programmare in linguaggi che non lo consentono.
 
Pascal e Delphi lo consentono, per cui immagino che li userai spesso :)
 


L'UNICO vantaggio delle nested function e' che hanno accesso a tutte le 
variabili della funzione che le contiene. Quindi quando le chiami non 
devi passargli tutte le variabili che gli servono.
Le puoi sempre sostituire con una funzione esterna, con il solo 
svantaggio che, nel caso accedessero a molte variabili, gliele devi 
ovviamente passare tutte come argomenti.
 
Puoi leggerne di piu' qui:
http://en.wikipedia.org/wiki/Nested_function
 
e in questa discussione:
http://stackoverflow.com/questions/2929281/are-nested-functions-a-bad-thing-in-gcc
 
 
Ciao.

   Mi faresti un esempio? Ciao.
 
Ah, solito discorso. Se ci fermiamo ad un discorso di "calcolabilita'"
non e' una feature che aumenta (ovviamente) la potenza del modello.
Tuttavia ne aumenta l'espressivita'.
 
Quindi.. sostituibile? Certo. 
 
  Come dicevo una anonymous class fa (grosso modo) lo stesso mestiere.
Quindi se ho le anonymous classes posso, banalmente, usare quelle. Anche
se pago un bel po' di sintassi in piu'. Non e' un caso che ci sia una
comunita' piuttosto vitale per averle in Java, proprio per rendere piu'
snello il codice. Ma, come dicevo, in questo caso l'overhead e' solo
sintattico. Tutto sommato pagabile. E non a caso in Java sono molti i
contesti in cui si possono usare.
 
In generale una closure e' sempre sostituibile con un oggetto (e
viceversa). Il problema e' che non sempre una delle due costruzioni e'
quella ottimale.
 
In particolare Massimo suggeriva di definire la funzione altrove. E
questo non e' un costrutto equivalente: una closure la usi perche' ha
accesso a stato locale alla funzione dove e' definita. Se definisci la
funzione fuori questo non e' piu' vero: hai bisogno di un meccanismo che
le permetta di portarsi in giro lo stato che le serve. Meccanismo che
puo' essere un oggetto, appunto. 
 
O al limite una zozzeria con le globali, se voglio usare la funzione
esterna. Ma non direi che e' "equivalente": diciamo che uno dei due
costrutti e' robusto e sicuro. L'altro no.


 Pascal e Delphi lo consentono, per cui immagino che li userai spesso :)
 
Stai girando un'implicazione. Io cerco di non programmare in linguaggi
che non le hanno. Ovvero cerco di programmare in linguaggi che le hanno.
Non necessariamente in *tutti*. Sono un po' troppi anche per me, tutti.
 
Inoltre, nel caso di Pascal, non mi e' chiaro cosa diavolo succede
quando lo fai. La mia idea e' che sotto non hai una vera closure. 
Sembra anche essere abbastanza essere l'impressione dominante:
 
<
http://community.freepascal.org:10000/bboards/message?message_id=340950
 
&forum_id=24102>
 
Come vedi, al di la di truccacci non ce la fai. Oltretutto non sento un
gran bisogno di scrivere codice in FreePascal. A Pascal ho sempre
preferito C, sinceramente. E se ho sotto mano C semplicemente ne faccio
a meno (come faccio a meno di tutti i pacchi di cose che C non ha
rispetto ad altri linguaggi). In C++ invece mi sposto in altre
direzioni. Ma ribadisco, la funzione di per se e' comoda. 
 
In C++ ci sono state diverse proposte per aggiungere la funzionalita'.
Se uno proprio ne ha bisogno la emula al solito con un oggetto
chiamabile. La differenza e' che ho ancora piu' sintassi fra le scatole,
ma si sopravvive.
 
Tra l'altro nel frattempo mi sono andato a vedere C++11 e li si, ci sono
quelle vere. Al solito sono implementate in modo che se non ci stai
attento ti spari nei piedi, ma in generale e' un grosso passo avanti
rispetto a prima. 


 ovviamente passare tutte come argomenti.
 
Il problema e' che questa soluzione e' piu' verbosa e meno espressiva. 
Chiaramente, come tutti i costrutti non fondamentali (scegli un set di
primitive a scelta... che so, if, goto, ...) sono ottenibili in altro
modo. Quello che paghi e' pero' in termini di espressivita', chiarezza e
manutensibilita' del codice.
 
In aggiunta ci possono essere questioni aggiuntive relative al
typesystem, tipo che la callback ha una certa signature e se tu vuoi
passargli la tua funzione che prende le variabili interne non puoi.
Certo, puoi girare intorno anche a questo. Per esempio definendo che la
callback prende un numero qualunque e un tipo qulunque di parametri. Etc
etc etc. Pero' davvero, stai pagando un sacco in termini di facilita' di
lettura. 


 costrutti e' robusto e sicuro. L'altro no.
 
Io tutta questa maggiora espressivita', robustezza, ecc.. non ce la 
vedo. Gia' le nested classes mi capita raramente di utilizzarle, se non 
per alleggerire il codice per un esempio/demo o in parti marginali del 
programma.
 
Mi piacerebbe comunque che postassi un esempio (facciamo in C o Java) 
che per te e' un modello di migliore espressivita', cosi' ci penso su.
 
Se poi mi postassi un link al codice di qualche software "diffuso" che 
utilizza queste nested function mi guardo anche quello.
 
Ciao.

 utilizza queste nested function mi guardo anche quello.
 
Qualunque pezzo di codice in Ruby usa i blocchi (che fanno
essenzialmente la stessa cosa). Qui davvero, e' talmente built-in nel
linguaggio che praticamente ogni cosa operi su una collezione prima o
poi lo fa (quindi qualunque cosa venga dopo l'hello world). Praticamente
ogni software scritto in un linguaggio funzionale o con tendenze
funzionali lo fa. Non c'e' nemmeno da cercare.
 
In Python ci sono esempi a partire dalla libreria standard, ma in
generale molte delle cose scritte con i decoratori definiscono una
nested function. Stiamo quindi parlando di roba pesantemente usata in
Django, Jinja, etc.


 rispetto a prima.
 
E ti pareva.
 
Sai mica dirmi che trappole hanno preparato stavolta... cosě magari ci 
metto un pň di meno a uscirne, quando le incontro?
 
PS
quando mai ho scelto di imparare il C++... errore, errore. Me lo dice 
sempre anche il compilatore.

 metto un pň di meno a uscirne, quando le incontro?
 
Il problema e' essenzialmente legato al tempo di vita delle variabili
automatiche. In una lambda puoi (se lo richiedi) riferirti a tutte le
variabili del corpo della funzione in cui la lambda e' definita.
 
Quale e' il problema? Potenzialmente la lambda ha un tempo di vita
*superiore* a quello della funzione dove la dichiari. L'esempio piu'
estremo e' quello in cui *ritorni* la lambda. Ora, l'esempio e'
particolarmente inutile, ma tant'e':
 
F adder(int a) {
  return [&](int b) { return a + b; }
}
 
F Inc = adder(1);
 
Bene... definita cosi' scoppia il mondo, perche' la lambda ha un
*riferimento* di a. Quindi quando la chiamiamo, a e' gia' morto e
l'universo e' ad un passo dal collasso.
 
Se voglio avere una *copia* di a devo fare:
 
 
F adder(int a) {
  return [=](int b) { return a + b; }
}
 
A questo punto io mi posso riferire ad a *per copia*. Ovvero a viene
copiato, con tutto quello che ne consegue, e fine della storia.
 
Ovviamente fra le quadre posso specificare esplicitamente chi catturare
e come catturarlo.
 
[]      Capture nothing (or, a scorched earth strategy?)
[&]     Capture any referenced variable by reference
[=]     Capture any referenced variable by making a copy
[=, &foo]       Capture any referenced variable by making a copy, but
capture variable foo by reference
[bar]   Capture bar by making a copy; don't copy anything else
[this]  Capture the this pointer of the enclosing class
 
 
Essenzialmente il baco che prevedo sara' che la gente fara' la cattura
per riferimento e poi, in qualche momento successivo della vita del
programma, le lambda cominceranno a vivere piu' della funzione che le ha
create. E tanti saluti.


 bel macello con le variabili automatiche).
 
Andava bene un esempio che non compilava, giusto per capire.
 
 > Qualunque pezzo di codice in Ruby usa i blocchi (che fanno
essenzialmente la stessa cosa).
 > In Python ci sono esempi a partire dalla libreria standard
 > Stiamo quindi parlando di roba pesantemente usata in
Django, Jinja,
 
Posta, posta pure il link, python preferibilmente, sono curioso, basta 
solo che sia software di una certa rilevanza.
 
(PS. sto guardando ora i sorgenti di django e non ho ancora trovata 1 di 
funzione nested... magari c'e' eh, certo che molto usata non credo...)

 funzione nested... magari c'e' eh, certo che molto usata non credo...)
 
Dei 1002 files di Django ho trovato nested functions in questi files:
https://code.djangoproject.com/browser/django/trunk/django/template/base.py
 
https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py
 
https://code.djangoproject.com/browser/django/trunk/django/utils/functional.py
 
https://code.djangoproject.com/browser/django/trunk/django/utils/simplejson/encoder.py
 
https://code.djangoproject.com/browser/django/trunk/django/core/serializers/python.py
 
 
Ho usato grep, me ne saro' persi qualcuno sicuramente, chiedo venia, se 
ci fosse un qualche tool (ho provato pylint) per cercarle sarebbe bello.
 
Nelle libreria standard sono certo usati molto di piu', ma non 
mischierei le due cose. La libreria standard non guarda certo alla 
programmabilita' o espressivita', guarda all'ottimizzazione.
 
Il mio intento era solo quello di attenuare il tuo punto di vista, 
secondo me esageratamente a favore.
 
Ciao

.


 secondo me esageratamente a favore.
 
Possibile. Il tool che ho scritto dice:
 
% python digger.py /Library/Frameworks/EPD64.framework/Versions/7.2 
Analyzed 15467 modules.
Found 32174 classes, that collectively have 131098 methods.
Found 37812 non-method functions.
Found 11074 nested functions.
Found 5696 lambda expressions, of which 4504 where nested (already
counted).
 
Il set di roba su cui lo ho lanciato e' enthought python, ovvero
libreria standard piu' un dozzilione di altre librerie, incluso jinja2,
networkx, tornado, twisted.
 
Come vedi, il numero di nested functions definite e' circa 1/3 del
numero di classi definite e circa 1/4 delle funzioni (intese come
"funzioni", non come "metodi"). Essendo nello stesso ordine di grandezza
delle classi e delle funzioni, direi che e' difficile dire che e' una
feature usata di rado. 
 
Ora, sono sicuro che ci siano dei bachi nel mio tool qua e la. E' una
cosa scritta alla brutto cane per curiosita' personale. Ma non credo che
sia cosi' pesantemente sbagliato. Nota, ci sono anche errori per
difetto: potenzialmente quando usi decorator (il modulo), stai
"nascondendo" un uso di funzione nestate. Idem se costruisci la funzione
in qualche modo diverso da def o lambda.
 
Poi anche functools ha diverse cose che essenzialmente definiscono
funzioni nested e *non* vengono rilevate dal tool (e.g., partial, molto
comodo). 
 
P.S. Nel caso di Django l'uso e' effettivamente un po' sotto media:
 
Analyzed 1872 modules.
Found 4594 classes, that collectively have 10770 methods.
Found 1708 non-method functions.
Found 664 nested functions.
Found 446 lambda expressions, of which 349 where nested (already
counted).
 
viceversa e' sopra-media l'uso delle classi. Probabilmente lo stile del
progetto e' semplicemente usare *meno* la parte piu' funzionale di
Python. 



Personalmente le aborro: trovo che i loro vantaggi siano marginali
e di contro aumentano un forte accopiamento tra dati e di fatto
rendono di fatto 'globali' tutte le variabili.
Dal mio punto di vista preferisco una maggiore segregazione
di dati e potere passare solo i parametri che interessano.
Se c'e davvero necessita' di molti parametri comuni, meglio
piazzarli in una struttura globale.
Ovviamente, e' solo la mia opinione :-)
cc.
 

 piazzarli in una struttura globale.
 
Hei, ma accusavi le nested functions di rendere le cose globali... qua
parli di struttura globale! :)
 
E comunque la necessita' delle nested functions non e', essenzialmente
quella di risolvere il problema dei molti parametri comuni (vedi
IntroduceParameterObject pattern per quello -- sono cose separate).
