L'essenziale se la domanda sembra essere "Come posso restituire due informazioni non correlate da un metodo che restituisce un singolo int? Non voglio mai controllare i miei valori di ritorno, e i valori null sono cattivi, non usarli".
Diamo un'occhiata a ciò che vuoi passare. Stai passando un int o una logica non int per il motivo per cui non puoi dare l'int. La domanda afferma che ci saranno solo due ragioni, ma chiunque abbia mai fatto un enum sa che ogni elenco crescerà. La portata di specificare altri razionali ha semplicemente senso.
Inizialmente, quindi, sembra che potrebbe essere un buon caso per lanciare un'eccezione.
Quando vuoi dire al chiamante qualcosa di speciale che non è nel tipo restituito, le eccezioni sono spesso il sistema appropriato: le eccezioni non sono solo per gli stati di errore e ti consentono di restituire un sacco di contesto e logica per spiegare perché puoi semplicemente oggi int.
E questo è l'UNICO sistema che consente di restituire ints validi garantiti e garantire che ogni operatore e metodo int che accetta ints possa accettare il valore di ritorno di questo metodo senza mai dover verificare valori non validi come null o valori magici.
Ma le eccezioni sono davvero solo una soluzione valida se, come suggerisce il nome, questo è un caso eccezionale , non il normale corso degli affari.
E un try / catch and handler è lo stesso boilerplate di un controllo null, che era ciò a cui si era opposto in primo luogo.
E se il chiamante non contiene il tentativo / cattura, allora il chiamante deve e così via.
Un secondo passaggio ingenuo è dire "È una misurazione. È improbabile che si verifichino misurazioni di distanza negative". Quindi per alcune misurazioni Y, puoi avere solo costi per
- -1 = sconosciuto,
- -2 = impossibile da misurare,
- -3 = rifiutato di rispondere,
- -4 = noto ma riservato,
- -5 = varia a seconda della fase lunare, vedi tabella 5a,
- -6 = quadridimensionale, misure fornite nel titolo,
- -7 = errore di lettura del file system,
- -8 = riservato per uso futuro,
- -9 = quadrato / cubico, quindi Y è uguale a X,
- -10 = è uno schermo monitor quindi non usa le misurazioni X, Y: usa X come diagonale dello schermo,
- -11 = ha scritto le misure sul retro di una ricevuta ed è stata riciclata nell'illegabilità ma penso che fosse 5 o 17,
- -12 = ... hai avuto l'idea.
Questo è il modo in cui viene fatto in molti vecchi sistemi C, e persino nei sistemi moderni in cui esiste un vero vincolo per int, e non è possibile racchiuderlo in una struttura o monade di qualche tipo.
Se le misurazioni possono essere negative, allora devi solo ingrandire il tuo tipo di dati (ad esempio long int) e avere i valori magici più alti dell'intervallo dell'int, e idealmente iniziare con un valore che verrà mostrato chiaramente in un debugger.
Ci sono buoni motivi per averli come variabili separate, invece di avere solo numeri magici. Ad esempio, tipizzazione rigorosa, manutenibilità e conformità alle aspettative.
Nel nostro terzo tentativo, quindi, esaminiamo i casi in cui è normale che il business abbia valori non int. Ad esempio, se una raccolta di questi valori può contenere più voci non intere. Ciò significa che un gestore di eccezioni potrebbe essere l'approccio sbagliato.
In tal caso, sembra un buon caso per una struttura che passa l'int e la logica. Ancora una volta, questa logica può essere solo una const come la precedente, ma invece di tenerle entrambe nello stesso int, le memorizzi come parti distinte di una struttura. Inizialmente, abbiamo la regola che se viene impostata la logica, l'int non verrà impostato. Ma non siamo più legati a questa regola; possiamo fornire razionali anche per numeri validi, se necessario.
Ad ogni modo, ogni volta che lo chiami, hai ancora bisogno di una piastra di cottura, per testare la logica per vedere se l'int è valido, quindi estrai e usa la parte int se la logica ci consente.
È qui che devi indagare sul tuo ragionamento alla base di "non usare null".
Come per le eccezioni, null significa uno stato eccezionale.
Se un chiamante sta chiamando questo metodo e ignora completamente la parte "logica" della struttura, aspettandosi un numero senza alcuna gestione degli errori e ottiene uno zero, allora gestirà lo zero come un numero e si sbaglierà. Se ottiene un numero magico, lo tratterà come un numero e si sbaglia. Ma se diventa nullo, cadrà , come dannatamente bene dovrebbe fare.
Quindi ogni volta che chiami questo metodo devi mettere un segno di spunta per il suo valore di ritorno, tuttavia gestisci i valori non validi, sia nella banda che fuori banda, try / catch, controllando la struttura per un componente "razionale", controllando l'int per un numero magico, o controllando un int per un null ...
L'alternativa, per gestire la moltiplicazione di un output che potrebbe contenere un int non valido e una logica come "Il mio cane ha mangiato questa misura", è quella di sovraccaricare l'operatore di moltiplicazione per quella struttura.
... E quindi sovraccaricare tutti gli altri operatori dell'applicazione che potrebbero essere applicati a questi dati.
... E quindi sovraccaricare tutti i metodi che potrebbero richiedere ints.
... E tutti questi sovraccarichi dovranno contenere ancora controlli per gli inte non validi, solo per poter trattare il tipo di ritorno di questo metodo come se fosse sempre un int valido nel momento in cui lo chiami.
Quindi la premessa originale è falsa in vari modi:
- Se hai valori non validi, non puoi evitare di cercare quei valori non validi in qualsiasi punto del codice in cui gestisci i valori.
- Se stai restituendo qualcosa di diverso da un int, non stai restituendo un int, quindi non puoi trattarlo come un int. Il sovraccarico dell'operatore ti consente di fingere , ma è solo finta.
- Un int con numeri magici (inclusi NULL, NAN, Inf ...) non è più un vero int, è una struttura da povero.
- Evitare i null non renderà il codice più robusto, nasconderà solo i problemi con gli ints o li sposterà in una complessa struttura di gestione delle eccezioni.