Funzioni annidate; consentire o no? [chiuso]

0

Avendo programmato un intero lotto in python, l'uso di funzioni annidate è un buon modo per non ingombrare lo spazio dei nomi con piccole funzioni di supporto che vengono utilizzate una sola volta.

Ora sto programmando in go, e dopo aver scritto un codice che ho immediatamente voluto refactoring in una funzione interna, ho scoperto che go non consente dichiarazioni di funzioni annidate. Ho immediatamente cambiato la funzione in una funzione anonima e l'ho salvata in una variabile, e l'ho chiamata come una funzione normale. Tuttavia, questo sembra andare contro la progettazione del linguaggio poiché la sintassi della dichiarazione di funzione normale non può essere utilizzata all'interno di un'altra funzione.

C'è una buona ragione per non consentire o per impedire l'uso di dichiarazioni di funzioni annidate?

    
posta Filip Haglund 13.07.2015 - 16:19
fonte

2 risposte

6

L'obiettivo principale di Go è di essere semplice da imparare e semplice da usare anche per programmatori sub-mediocri, quindi se vuoi scrivere in modo idiatico Vai l'anti-pattern che dovresti evitare di più è l'anti-pattern "Clever Code" .

Per una buona ragione per non consentire le funzioni annidate anche se si consentono le funzioni anonime - una delle differenze tra Python e Go è che Python non ha bisogno di una funzione main . Puoi semplicemente scrivere:

def foo():
    print('hi')

foo()

e l'interprete Python inizierebbe a leggere dall'alto verso il basso. Quando raggiunge def foo(): creerà una funzione e quando raggiungerà foo() eseguirà quella funzione. L'interprete è sempre nella stessa modalità (che è, almeno, l'astrazione) - la modalità di lettura e valutazione. Funziona allo stesso modo sia all'interno che all'esterno di una funzione, quindi è facile per esso supportare la copia di tutto quel codice all'interno di una funzione: aggiungerà semplicemente un'altra cornice al suo callstack e a parte questo farà esattamente la stessa cosa.

Go è una storia diversa. Quando scrivi

func foo() {
    fmt.Println("hi")
}

func main() {
    foo()
}

Il compilatore legge il livello più alto in modalità dichiarativo e crea le funzioni, ma il corpo delle funzioni che legge nella modalità imperativo . Nella modalità dichiarativa può creare funzioni e in modalità imperativo può eseguire istruzioni. Per abilitare le funzioni annidate sarà necessario aggiungere funzionalità di dichiarazione delle funzioni alla modalità imperativo .

Quindi, si potrebbe chiedere, non aggiungere questa funzionalità alla modalità imperativo ? Il motivo principale è la gestione delle chiusure:

func main() {
    txt := "hi"
    func foo() {
        fmt.Println(txt)
    }
    foo()
}

Scrivere qualcosa del genere significa che foo non è una funzione regolare - ha bisogno di accedere a txt , che risiede nello stack frame di main , quindi ha bisogno di un puntatore di contesto quello indicherà quel telaio. Se main viene richiamato, verrà creato un altro foo con un puntatore di contesto diverso.

Questo rende le funzioni annidate essenzialmente diverse dalle funzioni regolari, il che è un motivo per non avere funzioni annidate. Python non ha questo problema, perché tutte le sue funzioni sono le chiusure - sono tutte "annidate".

    
risposta data 13.07.2015 - 16:58
fonte
0

Il comportamento e la semantica delle funzioni nidificate sono molto più vicini alle funzioni anonime che alle funzioni non annidate. Molto probabilmente, volevano semplicemente che la sintassi riflettesse quella differenza.

Tuttavia, non mi sorprenderebbe vedere le funzioni annidate in un aggiornamento futuro, perché credo che le ragioni siano più culturali che tecniche. Go era inteso come un successore dei linguaggi della famiglia C per la programmazione dei sistemi. I precedenti linguaggi dominanti a tale scopo non supportavano funzioni annidate, e quindi i programmatori che lavorano in quelle aree non hanno incorporato funzioni nidificate nei loro linguaggi di progettazione.

Per molti programmatori, questo tipo di incapsulamento a livello di funzione non "sembra" corretto. Per loro, l'incapsulamento delle funzioni di supporto è il lavoro di una classe, fine della storia. Questo è un atteggiamento profondamente radicato e riflessivo tra molti programmatori orientati agli oggetti. Vedrai questo se lavori mai da qualche parte che fa principalmente programmazione in C ++ con alcune utility python sul lato.

Penso che questo atteggiamento stia lentamente cambiando quando le funzionalità di stile funzionale vengono aggiunte ai linguaggi "aziendali", ma potrebbero volerci un paio di generazioni.

    
risposta data 13.07.2015 - 19:33
fonte

Leggi altre domande sui tag