Scala e gestione delle eccezioni [chiuso]

3

Sono curioso del perché la gestione delle eccezioni sia un argomento spesso ignorato in Scala. L'obiettivo della lingua (o dello stile) è quello di non fare affidamento sulla gestione delle eccezioni, ad eccezione dell'input / codice esterno?

Speravo che la guida allo stile avesse qualche discussione sul controllo / gestione delle eccezioni. C'è un buon riferimento che potrei consultare per capire se ci sono delle differenze nella gestione delle eccezioni in Scala rispetto alle lingue a cui sono più abituato (C ++ / C # / Java / Ruby / etc)?

Qualcuno con qualche anno alla Scala sarebbe disposto a scrivere delle linee guida per la gestione delle eccezioni specifiche di Scala? o la risposta è semplicemente "fai come faresti in Java"? Cos'è "il modo funzionale"?

    
posta Will I Am 25.12.2014 - 20:10
fonte

2 risposte

8

Il buon stile funzionale non ha bisogno della codifica difensiva quasi quanto lo stile imperativo. prova e catch non è l'unica struttura di controllo che viene trascurata in Scala (e in altri linguaggi funzionali); per e mentre i loop sono specie a rischio di estinzione e anche if ... else è usato in modo più selettivo (anche se molto più efficacemente, poiché restituisce un valore ).

Nel mondo funzionale, abbini il tuo codice alla forma dei dati. O scegli una forma che dia al tuo codice la struttura che desideri. Questo è vero non solo con Opzione e O ma Elenco e Set e Mappa e altro ancora. Tutti sono abbinati a potenti funzioni di ordine superiore: mappa , piega , filtro ecc.

Per fare un esempio banale, se un codificatore Java o C ++ vuole recuperare il primo (o tutti) degli elementi in un elenco e manipolarlo, devono prima controllare che l'elenco non sia vuoto o avvolgerlo in prova / cattura per gestire l'errore. Se devono gestire una serie di elenchi, è più probabile che quest'ultima opzione sia scelta (e ancor meno probabile che corrisponda al contesto che potrebbe generare un errore).

In Scala puoi semplicemente farlo nell'elenco di Ints chiamato xs :

  xs.headOption map (_ * 2)
  // Returns twice the first item - if there is one - as an Option

o

  xs map (_ * 2)
  // Doubles everything in the list.  Returns a list.

Se non c'è nulla nell'elenco, non accadrà nulla. Se vuoi che succeda qualcosa, puoi rilevare l'errore e reagire.

  xs.headOption map (_ * 2) orElse Some(0)
  // Returns Some(twice the head item) if there is one or Some(0)
  xs.headOption map (_ * 2) getOrElse 0
  // Returns twice the head item or 0 if there is none

Ancora meglio, se hai a che fare con un elenco di elenchi, ognuno dei quali potrebbe essere vuoto, la mappatura su ciascuno di essi produrrà risultati per ogni elenco popolato e nessun problema con nessun vuoto. È molto potente quando si tratta di grandi raccolte di dati imprevedibili.

Quali di questi tipi funzionali (Opzione e Entrambi e Lista e Mappa e tutti gli altri - mi dispiace usare la brutta parola - monadi) offrono anche, molto importante, la separazione delle preoccupazioni. Nota come ho usato mappa in tutti gli esempi precedenti. In due esempi è Option.map , mentre nell'altro è List.map . In tutti i casi, map sta facendo la stessa cosa: ¨ Applica la mia funzione ai dati contenuti nel contenitore, preservando il contesto. Se si tratta di un contesto di lista, si ottiene un elenco di dati trasformati. Se è un contesto "può o non può esistere", puoi ottenere il tuo oggetto trasformato. Se si tratta di un contesto che potrebbe davvero andare male in modo sbagliato, puoi ottenere il tuo oggetto o la possibilità di lamentarti. E così via.

In questo modo si ottiene una separazione delle preoccupazioni tra l'azione che si desidera eseguire e il contesto in cui viene applicata. Il grande vantaggio è che se decidi di cambiare il contesto (ad es. Set di oggetti unici anziché arbitrario Elenco di oggetti), il resto del codice non ha bisogno di cambiare affatto. mappa farà ancora la cosa giusta (così come filtro , fold e il resto).

Parole chiave imperative incorporate come try..catch o if ... else ... if ... else non hanno questo potere. Per cominciare, non hanno alcun significato reale e devono essere messi insieme (distorcendo il codice intricato all'interno di essi) e non offrono alcuna garanzia. Immagina di averli usati per gestire un elenco arbitrario di oggetti e poi decidere di voler garantire unicità . Quanto di quel codice imperativo dovresti cambiare? Come puoi essere sicuro che funzionerà?

Lasciare le eccezioni per gestire l'inaspettato e irrisolvibile. I tipi funzionali possono essere sicuri delle loro garanzie, per aiutarti a evitare errori comuni e prevedibili.

    
risposta data 21.01.2015 - 20:03
fonte
5

Scala incoraggia l'uso di costrutti come opzioni e futures per la gestione degli errori. Prima di tutto, la valutazione lazy rende problematiche le eccezioni, perché c'è uno stack diverso quando viene eseguita una funzione rispetto a quando è in coda per l'esecuzione. Scala non è pigro per impostazione predefinita, ma può essere pigro quando si sceglie.

Inoltre, opzioni e futures sono molto più potenti delle eccezioni. Puoi concatenare le operazioni su di esse e non si limitano a propagare direttamente nello stack come fanno le eccezioni. È possibile archiviarli in raccolte e ridurre la duplicazione nel codice del gestore.

Praticamente l'unica volta che usi le eccezioni in Scala è per errori che non puoi gestire, ma ucciderà comunque il tuo programma.

    
risposta data 25.12.2014 - 21:08
fonte

Leggi altre domande sui tag