Le eccezioni sono un concetto OOP?


37

Avendo letto un post ieri, mi sono reso conto che non sapevo molto sull'origine delle eccezioni. È solo un concetto correlato alla OOP? Tendo a pensarlo, ma ci sono ancora delle eccezioni al database.


Una volta ho letto che un "Mr Goodenuf" (o simile) ha inventato delle eccezioni in risposta a "non importa, è Goodenuf, eh!" bullismo di stile. Non riesco a trovare un riferimento ora - forse qualcun altro può farlo. Sarebbe interessante sapere a quale lingua sono stati aggiunti per primi.
Steve314,

7
Haskell ha delle eccezioni e non è affatto OOP
Daniel Gratzer l'

1
Sebbene le eccezioni stesse non siano strettamente orientate agli oggetti, la pratica comune di definire eccezioni come oggetti e lanciare e catturare istanze di questi oggetti chiaramente è molto OOP.
Dougvj,

Qual è la differenza tra un'eccezione e un GOTO sarebbe una domanda interessante.
Austin Henley,

2
@Austin - che ne dici "anche se i tiri d'eccezione violano il principio del punto di uscita unico secondo cui alcuni dei più severi discepoli della programmazione strutturata sostengono come assoluti, non consentono il flusso incontrollato di controllo degli spaghetti nel modo che gotofa. In particolare, l'obiettivo di il lancio è determinato dal contesto, basato sull'annidamento di strutture a blocchi. Pertanto, le eccezioni dipendono anche da una forma leggermente meno rigorosa di programmazione strutturata in cui il principio dell'uscita singola è considerato una linea guida, ma non un assoluto ".
Steve314,

Risposte:


5

Le eccezioni non sono un concetto OOP.

Ma non sono completamente estranei in un piccolo punto.

Come hanno dimostrato altre risposte: il concetto di eccezioni lo ha reso disponibile in diversi linguaggi non OOP. Niente in questo concetto richiede qualcosa da OOP.

Ma tutti i linguaggi OOP, se non tutti, che prendono sul serio OOP richiedono eccezioni perché gli altri metodi di gestione degli errori falliscono in un punto specifico: il costruttore.

Uno dei punti di OOP è che un oggetto deve incapsulare e gestire il suo stato interno in modo completo e coerente. Ciò significa anche che in OOP puro è necessario un concetto per creare un nuovo oggetto con uno stato coerente "atomicamente": tutto, dall'allocazione della memoria (se necessario) all'inizializzazione a uno stato significativo (cioè l'azzeramento semplice della memoria non è sufficiente) deve essere fatto in una sola espressione. Quindi è necessario un costruttore :

Foo myFoo = Foo("foo", "bar", 42);

Ma questo significa che il costruttore può anche fallire a causa di un errore. Come propagare le informazioni di errore dal costruttore senza eccezioni?

  • Valore di ritorno? In caso contrario, poiché in alcune lingue newpotrebbero restituire solo nullinformazioni significative. In altre lingue (es. C ++) myFoonon è un puntatore. Non è possibile verificarlo null. Inoltre, non è possibile chiedere myFooinformazioni sull'errore: non è inizializzato e pertanto "non esiste" nel pensiero OOP.

  • Flag di errore globale? Tanto sull'incapsulamento dello stato e poi su qualche variabile globale? Vai a h ... ;-)

  • Una mistura? In nessun modo migliore.

  • ?

Quindi le eccezioni sono un concetto più fondamentale di OOP ma OOP si basa su di esse in modo naturale.


3
per quanto ne so, l'unica parola in questa "risposta" che affronta la vera domanda è "non". Il resto sembra riguardare le eccezioni in OOP - con tutto il rispetto per me, questo legge da qualche parte tra vagamente imparentato e totalmente irrilevante - di nuovo, nel contesto della domanda posta
moscerino

@gnat: il TO dice anche che non conosce l'origine delle eccezioni. Di qui un piccolo esempio del perché le eccezioni sono ovunque nella terra di OO e sembra essere OK per me. YMMV
AH,

1
@AH Devo essere d'accordo con moscerino, a parte la linea di apertura, in realtà non affronta la domanda. La tua risposta a Gnat è stata "dice che non conosce l'origine delle eccezioni", ma in realtà non hai dato origine a eccezioni, ma solo un uso casuale di eccezioni durante l'istanza dell'oggetto.

Ragazzi, sul serio? -1? La maggior parte delle altre risposte non è nemmeno al 100%. +1 da parte mia per compensare. Questa risposta fornisce buoni consigli di base in un mondo di progetti di classe non funzionanti. (Emendamento: si dovrebbero evitare i costruttori a più fasi di menzione)
Jo So,

44

È solo correlato a OOP?

No. Eccezioni e OOP non sono correlate.

La gestione delle eccezioni è un meccanismo per gestire gli errori. Un'eccezione viene gestita salvando lo stato corrente di esecuzione in una posizione predefinita e passando l'esecuzione a una subroutine specifica nota come gestore delle eccezioni.

Confrontando C ( non proprio il linguaggio OOP , possibile in qualche modo emulare eccezioni in C ) e C ++ (OOP, supporta le eccezioni), nulla impedisce al comitato standard di C di aggiungere la gestione delle eccezioni a C, non renderà ancora C un linguaggio OOP.


2
Si potrebbe anche sostenere che ci sono già una sorta di eccezioni supportate nel solito sistema operativo. Lascia che il programma si blocchi (la "eccezione" non rilevata) e con un dump principale e un debugger, ottieni persino una traccia dello stack.
bhaak

12
Anche MS BASIC dei primi anni '80 aveva una gestione delle eccezioni:ON ERROR GOTO xxxx
jwernerny

1
@bhaak Potrebbe anche parlare di dump della memoria in Windows
JohnL

11
@jwernerny Errore nella gestione? Sicuro. Ma nessuno avrebbe definito tale gestione delle eccezioni. In effetti, era regolarmente contrastato con la gestione (strutturata) delle eccezioni.
Konrad Rudolph,

1
@jwernerny non sono sicuro di seguire; gestione delle eccezioni, come ho capito, è un modo molto specifico per gestire gli errori. Quando sento l'eccezione penso sempre al try catchcostrutto.
Andy,

12

Un'eccezione è, in poche parole, una situazione eccezionale che richiede attenzione e spesso un cambiamento nel flusso dell'esecuzione di un programma. In base a tale definizione, le eccezioni e la gestione delle eccezioni non si limitano all'orientamento agli oggetti e semplici errori di programma possono essere considerati una forma di eccezione.

I linguaggi orientati agli oggetti in genere hanno una classe di eccezione nativa e, a seconda del contesto, la parola "eccezione" potrebbe effettivamente riferirsi a quella classe nativa anziché al concetto generale. La gestione delle eccezioni orientata agli oggetti è, come la maggior parte dell'orientamento agli oggetti, zucchero sintattico e può essere facilmente emulata in linguaggi decisamente non orientati agli oggetti. Ecco un esempio C, dal wiki di programmazione C :

#include <stdio.h>
#include <setjmp.h>

jmp_buf test1;

void tryjump()
{
    longjmp(test1, 3);
}

int main (void)
{
    if (setjmp(test1)==0) {
        printf ("setjmp() returned 0.");
        tryjump();
    } else {
        printf ("setjmp returned from a longjmp function call.");
    }
}

6
Non è solo zucchero sintattico. Ricreare uno stack completo svolgendo e gestori di cattura basati sul tipo è difficile con setjmp. Inoltre, la compilazione speciale di eccezioni comporta vantaggi che non possono essere imitati da setjmp.
edA-qa mort-ora-y

3
Odio la descrizione eccezioni sono situazioni eccezionali. Preferirei dire che dovrebbero essere generate (generate) eccezioni quando una situazione di errore non può essere risolta con il contesto corrente perché non ci sono abbastanza informazioni nel contesto corrente per correggere correttamente l'errore.
Martin York,


9

La risposta è un semplice NO.

Un buon esempio per un linguaggio non OO con eccezioni è ADA.


4
Hm, perché ADA non è una lingua OO? Certo, ADA83 mancava di polimorfismo ma poteva ancora essere considerato basato su oggetti. Anche da ADA95 il linguaggio è completamente orientato agli oggetti.
yannis,

Per quanto ne so, la gestione delle eccezioni è più vecchia di ADA83, pertanto ADA è di per sé una non-OO con gestione delle eccezioni.
Uwe Plonus l'

2
@YannisRizos: Ada83 ha pacchetti e pacchetti generici ma non oggetti. Sono stati introdotti con Ada95.
mouviciel,

2
@Yannis - Gli oggetti senza polimorfismo è come una programmazione strutturata senza blocchi nidificati. Il polimorfismo è uno dei tratti distintivi di OOP. Anche in Ada95, i tipi che supportano l'associazione runtime sono chiamati "tipi con tag" anziché "classi", anche se ovviamente si tratta solo di ortografia. Ada 83 aveva record di varianti e vari altri tipi, ma nessuno di questi tipi offre funzionalità specifiche di OOP. Ada 83 era modulare e strutturato, ma non era orientato agli oggetti.
Steve314

3
@Yannis - fondamentalmente, alcune persone nella comunità di Ada (come alcuni sostenitori della maggior parte delle lingue) non possono accettare che una funzione possa essere buona, ma non implementata nella loro lingua preferita, e inventeranno ogni sorta di scuse per credere diversamente. Eppure non è nemmeno come se un buon linguaggio abbia bisogno di tutte le possibili buone caratteristiche del linguaggio (anche se è facile credere che i designer di Ada lo pensassero). Non credo davvero all'approccio minimalista alla progettazione del linguaggio, ma neanche i linguaggi massimalisti sono perfetti.
Steve314

7

Alcune ottime risposte qui già. Altri esempi per linguaggi di programmazione non OOP con eccezioni:

  • Oracle PL / SQL

  • Visual Basic classico (V6 e precedenti, "On Error Goto" è IMHO una forma di gestione delle eccezioni)

(A dire il vero: trovi alcuni elementi OO in entrambe le lingue, ma la meccanica di gestione delle eccezioni non ne fa uso, immagino perché il concetto è stato introdotto anni prima che gli elementi OO fossero aggiunti a quelle lingue).


Almeno le versioni successive di QuickBASIC su DOS (che precedevano Visual Basic; QB 4.5 era il 1988 secondo Wikipedia, VB 1.0 1991) avevano la gestione degli errori usando la ON ERROR GOTOsintassi. Anche QuickBASIC aveva alcuni concetti simili a OO (penso che QB 4.5 supportasse persino classi di qualche tipo) ma sarebbe difficile trovare un BASIC prevalentemente tradizionale un linguaggio orientato agli oggetti. [Wikipedia ]
un CVn

5

L'idea alla base delle eccezioni è quella di ripulire il flusso del programma in modo che un programmatore possa seguire più facilmente il percorso di esecuzione "normale". Si consideri un semplice caso di apertura di un file in C. Immediatamente dopo aver tentato di aprire il file, il programmatore deve esaminare la risposta dalla chiamata fopen () e decidere se la chiamata è riuscita. Se la chiamata non è riuscita, il programmatore deve rispondere in modo appropriato. La chiamata successiva nel percorso di esecuzione "normale", forse una chiamata a fread () o fwrite (), apparirà dopo che le condizioni di errore o fallimento sono state gestite. Potrebbe essere nella schermata successiva.

Con una lingua che fornisce eccezioni, la chiamata equivalente fopen () può essere seguita immediatamente da fread () o fwrite (). Non vi è alcun errore nella gestione che nasconde il "passaggio successivo" del percorso di esecuzione "normale". Il programmatore può vedere più del normale percorso su una singola schermata e quindi può seguire l'esecuzione più facilmente. La gestione degli errori viene spostata in un'altra parte del programma.

Le eccezioni stesse non sono un concetto OOP, ma sono spesso implementate usando concetti OOP che le rendono più convenienti e potenti. Ad esempio, le eccezioni possono essere definite con una gerarchia di ereditarietà. Utilizzando il nostro esempio nozionale di apertura e lettura o scrittura di un file, ciascuna di queste chiamate può generare una serie di eccezioni: FileClosedException, DeviceFullException, NoSuchFileException, InsufficientFilePermissionsException, ecc. Ognuno di questi può ereditare da FileException, che può ereditare da IOException, che può ereditare da GenericException.

Se il programmatore sta eseguendo un'implementazione rapida e sporca per testare un concetto, potrebbe principalmente ignorare la gestione delle eccezioni e implementare un solo gestore per GenericException. Tale gestore gestirà un GenericException e qualsiasi eccezione ereditata da GenericException. Se desidera trattare qualsiasi eccezione relativa ai file allo stesso modo, può scrivere un gestore per FileException. Verranno chiamati FileExceptions e tutte le eccezioni ereditate da FileException. Se desidera scrivere un programma che risponderà in modo diverso a una varietà di condizioni di errore, può scrivere un gestore specifico per ogni specifica eccezione.


3

Altri hanno giustamente risposto "No" con esempi di lingue. Ho pensato di poter estendere aggiungendo un esempio su come aggiungere eccezioni a una lingua senza mai coinvolgere OOP.

Lo farò nel caso del DSKL (Declarative Sequential Kernel Language) di OZ , un linguaggio adatto per cose accademiche come questa. Il DSKL (o DKL) può essere visualizzato qui (risultato della ricerca casuale), la parte Dichiarazioni e valori. La definizione esatta non è importante, a parte il fatto che si tratta di un linguaggio molto semplice senza variabili modificabili (vengono dichiarate e successivamente associate) e non è incorporato OOP.

OOP non può nemmeno essere aggiunto come astrazione linguistica a questo linguaggio del kernel. Aggiungendo nomi univoci al linguaggio del kernel (NewName) e usando l'ambito locale, è possibile ottenere l'incapsulamento. Oppure aggiungendo uno stato mutabile al linguaggio del kernel (NewCell) e usando l'ambito locale OOP corretto con incapsulamento può essere raggiunto. Ma non può essere raggiunto solo con il linguaggio kernel specificato.

Se poi aggiungiamo eccezioni al linguaggio del kernel avremo una lingua senza supporto OOP ma avremo eccezioni. Lascia che ti mostri come:

Definendo una macchina astratta con uno stack e una memoria, possiamo definire cosa dovrebbe fare ogni istruzione nella nostra lingua (la semantica dell'istruzione). Ad esempio skipnella pila non dovrebbe fare nulla, A = 3nella pila dovrebbe legare (/ unificare) A a (/ con) 3.

Iniziamo aggiungendo la sintassi di come dovrebbero essere definite le nostre eccezioni. Facciamo questo aggiungendo altre due clausole al <statement>nel DKL.

<statement>  ::== ... (old stuff)
                 | try <statement> catch <id> then <statement> end
                 | raise <id> end

Ecco il noto tentativo / cattura e un modo per sollevare / lanciare eccezioni.

Definiamo la loro semantica da come dovrebbero funzionare sulla macchina astratta:

Prova
La dichiarazione semantica è: (try <statement1> catch <id> then <statement2> end)
Do:

  1. Spingere in pila l'istruzione semantica (catch <id> then <statement2> end)
  2. Spingere in pila l'istruzione semantica (<statement1>)

Nota che l'istruzione 1 sarà in cima allo stack e tentata per prima.

Solleva
La dichiarazione semantica è: (raise <id> end)
Do:

  1. Se non c'è più nulla in pila, fermati e segnala un'eccezione non rilevata.
  2. Altrimenti, estrarre la prima istruzione semantica dallo stack. Se non è un'istruzione catch, vai al passaggio 1.
  3. Abbiamo ottenuto un problema, sul modulo (catch <id> then <statement> end)
    Push (<statement>)sulla pila.

Cattura
Se vediamo una dichiarazione di cattura durante la normale esecuzione, ciò significa che qualsiasi cosa all'interno è stata eseguita senza aumentare le eccezioni fino a questo livello. Quindi facciamo semplicemente pop catchdello stack e non facciamo nulla.

QED, abbiamo una lingua con eccezioni e nessuna possibilità di OOP.

Ho rimosso la parte dell'ambiente dalla macchina astratta per renderla più semplice.


1

No.

IIRC, apparvero delle eccezioni prima delle prime lingue OO. AFAIK, le eccezioni sono state inizialmente supportate dalle prime implementazioni LISP. Le prime lingue strutturate (ad es. ALGOL) e le prime lingue OO (ad es. SIMULA) non supportavano le eccezioni.


ALGON 68, ovviamente, aveva delle eccezioni ("eventi"), ma aveva anche tutto il resto. PL / Ho avuto anche loro ("condizioni ON"), e c'è una letteratura del 1969 che ne descrive l'uso.
Ross Patterson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.