Buona procedura o design di funzioni

3

Questo è in riferimento a la domanda pubblicata qui . Come lo giudicherei, la domanda dovrebbe essere chiusa semplicemente perché sembra chiedere perché gli sviluppatori Borland abbiano reso una cosa una funzione e un'altra una procedura (funzione che restituisce un risultato nullo).

Ora l'esempio è stato fornito con alcune funzioni di manipolazione delle stringhe che esistono in Borland Pascal o Delphi:

S2 := Copy(S1,3,2);

Copies into S2 from S1 the 2 characters starting from the 3rd position.

Delete(S,3,2);

Deletes from S the 2 characters starting from the 3rd position.

Ora pensavo che potesse essere una buona discussione su quali sarebbero state le buone decisioni di progettazione riguardo alla creazione di queste cose. Ho individuato alcune regole di buon design su come dovrebbe apparire un prototipo di funzione oltre l'ovvio (il nome riflette la funzione, il risultato della funzione dovrebbe essere atomico, nessuna variabile estranea), ma ci sono altri che dovrebbero governare una situazione come questa o altri? Non ho davvero visto un buon caso nel libro di codice di Atwood in cui è stato discusso.

Ad ogni modo, ci sono delle buone regole su come le funzioni dovrebbero essere progettate per funzionare? Escludendo la denominazione speciosa, sarebbe meglio avere

S2 := Delete(S1,3,2);

al contrario di

Delete(S,3,2);

? Ci sono altre considerazioni o esempi utili per discutere del design di funzioni buone e cattive?

    
posta Glenn1234 21.09.2013 - 04:58
fonte

3 risposte

11

Mi sembra che entrambi gli stili abbiano un posto perché non fanno la stessa cosa dal punto di vista della semantica:

S2 := Delete(S1,3,2);

L'assegnazione implica che ci sia una subroutine che restituisce qualcosa che può essere assegnato a una variabile.

Delete(S,3,2);

Implica una mutazione sul posto della subroutine senza alcun tipo di valore di ritorno, rendendola così una procedura, poiché le procedure non hanno valori di ritorno.

In generale, le funzioni devono essere progettate in modo che possano essere completamente al curry e in modo che siano concepibilmente puri. Dal momento che il secondo stile di design "funzione" si basa interamente su un effetto collaterale per generare il suo effetto, direi che dovresti usare sempre il primo stile.

    
risposta data 21.09.2013 - 05:23
fonte
4

Finché restano in vigore alcune regole linguistiche di base, entrambe le notazioni possono essere tradotte in altro.

S2 := Delete(S1,3,2);

può essere riscritto come

Delete(S2,S1,3,2);

se S2 è dichiarato come riferimento pass-by.

E

Delete(S,3,2);

può essere riscritto come

S := Delete(S,3,2);

Nella maggior parte delle lingue a cui riesco a pensare, questo è il caso. Se non è il caso, l'argomento per la notazione è chiaro: usa quello che funziona.

Ma supponendo che si possa usare entrambi, hai chiesto delle considerazioni utili. Per me, i due guidanti dovrebbero essere chiarezza e efficienza .

Sulla chiarezza , prendi il primo esempio sopra. Personalmente, da una funzione, mi aspetto uno dei due comportamenti. O restituisce tutto il lavoro che fa in S2 (senza alcun argomento pass-by-reference) o restituisce tutto il suo lavoro in argomenti pass-by-reference e restituisce solo un codice che indica il successo o l'insuccesso. Fare altrimenti - manipolare alcuni argomenti come prodotto del lavoro e poi restituire un altro prodotto di lavoro - rende il codice impossibile da capire. Ora, se non ci sono dubbi sul successo o l'insuccesso della funzione, e se il pass-by-reference è più appropriato per il lavoro svolto, allora la sintassi procedurale va bene. Ma nella mia esperienza, 90 +% delle volte, desidero un'indicazione di successo / fallimento, o non voglio passare per riferimento, o entrambi.

In efficienza , prendi il secondo esempio. Ovviamente se S o le operazioni su di esso sono grandi e complesse, il pass-by-reference può essere più efficiente di lavorare su una copia di dati e ritornare solo per assegnare alla stessa variabile originale. E come sopra, se il pass-by-reference è appropriato, e se non ci sono domande circa la funzione / la procedura che ha esito positivo o negativo, non è necessario alcun ritorno.

    
risposta data 28.09.2013 - 04:09
fonte
0

Non sono sicuro di altri linguaggi, ma in Ruby l'approccio che adottano consiste nell'implementare solitamente entrambi i tipi di metodo, in modo che l'utente possa scegliere quale sia il migliore per la situazione, ma il tipo che modifica i dati ( piuttosto che lasciare i dati originali invariati e restituire la versione modificata) è sempre suffisso con un '!', quindi è chiaro che la funzione esegue un'operazione distruttiva.

    
risposta data 02.10.2013 - 23:03
fonte

Leggi altre domande sui tag