Ho il seguente codice in molti posti in una grande applicazione:
if (datastruct.data_ok &&
cur_time > datastruct.start_time && cur_time < datastruct.end_time)
{
do_something();
}
Ora volevo eliminare il codice ripetuto definendo una funzione time_ok (...) che semplificherebbe il codice ripetuto a:
if (time_ok(&datastruct, cur_time))
{
do_something();
}
A mio parere, si tratta di un refactoring ben fatto e dovrebbe quindi essere fatto. Se la definizione della condizione cambia in futuro, la manutenzione del codice diventa più semplice poiché è necessario modificare solo una posizione.
Tuttavia, diversi membri del team hanno notato che è possibile abusare della funzione assegnando un argomento NULL, che arresta il programma. Si sono anche lamentati del fatto che il valore restituito è un booleano e non un codice di errore e tutte le funzioni dovrebbero restituire un codice di errore.
Quindi, il refactoring sarebbe secondo loro essere fatto nel modo seguente:
bool time_ok_condition;
int err;
err = time_ok(&datastruct, &time_ok_condition, cur_time);
if (err != 0)
{
fprintf(stderr, "Error %d at file %s line %d", err, __FILE__, __LINE__);
exit(1);
}
if (time_ok_condition)
{
do_something();
}
Tuttavia, a mio parere, ciò si traduce in un codice eccessivamente lungo e se io davvero devo fare tutto questo, preferirei avere il codice originale non refactored.
Ho inventato un modo per aggirare questa regola usando una macro:
if (TIME_OK(datastruct, cur_time))
{
do_something();
}
... che non può mai mandare in crash il programma su argomenti NULL dato che la macro assume il nome della struttura e non un puntatore alla struttura come argomento. Tuttavia, non mi piace particolarmente questo approccio all'utilizzo di una macro perché la macro valuta i suoi argomenti più volte.
Ho notato che sebbene C sia stato sviluppato per le chiamate di sistema Unix e Unix tradizionalmente restituiscono i codici di errore, le funzioni standard della libreria C come strstr, strchr, strspn non restituiscono un codice di errore e quindi gestiscono argomenti NULL arrestando il programma.
Ora, è una domanda completamente diversa se il programma debba arrestarsi in modo anomalo con Coredump o stampare un messaggio di errore significativo per l'errore teorico che non si verifica mai in questo programma (vedere la domanda Come dovrebbe" questo non può mai accadere "lo stile degli errori in C viene gestito? on Overflow dello stack).
Tuttavia, questa domanda riguarda la possibilità di restituire qualcosa di diverso da un codice di errore. In questo caso molto specifico, una risposta positiva richiederebbe l'uso della strategia "crash with coredump" poiché l'intervallo di un ritorno booleano non può rappresentare errori, ma non significa necessariamente che una strategia di "crash con coredump" sia ottimale in tutti i casi .
Chi è corretto? Le funzioni C dovrebbero sempre restituire un codice di errore come le chiamate di sistema Unix, o dovrebbe essere consentito scrivere funzioni che restituiscono qualcos'altro se c'è una ragione giustificata come la semplicità del codice?