A essência se a pergunta parece ser "Como eu retorno duas informações não relacionadas de um método que retorna um único int? Eu nunca quero verificar meus valores de retorno, e os nulos são ruins, não os use".
Vejamos o que você deseja passar. Você está passando um raciocínio int ou não-int por que não pode dar o int. A pergunta afirma que haverá apenas duas razões, mas quem já fez um enum sabe que qualquer lista aumentará. O escopo de especificar outras justificativas apenas faz sentido.
Inicialmente, portanto, parece que pode ser um bom argumento para lançar uma exceção.
Quando você deseja dizer ao chamador algo especial que não está no tipo de retorno, as exceções geralmente são o sistema apropriado: as exceções não são apenas para estados de erro e permitem que você retorne muito contexto e lógica para explicar por que você pode hoje não.
E este é o sistema ONLY que permite retornar ints com garantia garantida e garantir que todo operador int e método que recebe ints possam aceitar o valor de retorno desse método sem precisar verificar valores inválidos, como valores nulos ou mágicos.
Mas as exceções são realmente apenas uma solução válida se, como o nome indica, esse for um caso excepcional , não o curso normal dos negócios.
E um try / catch and handler é tão clichê quanto uma verificação nula, que foi o que foi contestado em primeiro lugar.
E se o chamador não contiver a tentativa / captura, o chamador precisará, e assim por diante.
Um segundo passe ingênuo é dizer "É uma medida. Medições negativas de distância são improváveis". Portanto, para algumas medições Y, você pode apenas ter consts para
- -1 = desconhecido,
- -2 = impossível de medir,
- -3 = recusou-se a responder,
- -4 = conhecido mas confidencial,
- -5 = varia dependendo da fase da lua, consulte a tabela 5a,
- -6 = quadridimensional, medidas indicadas no título,
- -7 = erro de leitura do sistema de arquivos,
- -8 = reservado para uso futuro,
- -9 = quadrado / cúbico, então Y é igual a X,
- -10 = é uma tela do monitor, portanto, não usa as medidas X, Y: use X como a diagonal da tela,
- -11 = anotou as medidas no verso de um recibo e foi lavado em ilegibilidade, mas acho que eram 5 ou 17,
- -12 = ... você entendeu a ideia.
É assim que é feito em muitos sistemas C antigos, e mesmo em sistemas modernos, onde há uma restrição genuína ao int, e você não pode envolvê-lo em uma estrutura ou mônada de algum tipo.
Se as medições puderem ser negativas, você apenas aumentará seu tipo de dados (por exemplo, int longo) e fará com que os valores mágicos sejam maiores que o intervalo da int e, idealmente, comece com algum valor que aparecerá claramente em um depurador.
Existem boas razões para tê-los como uma variável separada, em vez de apenas ter números mágicos. Por exemplo, digitação estrita, manutenção e conformidade com as expectativas.
Em nossa terceira tentativa, analisamos os casos em que é normal o negócio ter valores não int. Por exemplo, se uma coleção desses valores puder conter várias entradas não inteiras. Isso significa que um manipulador de exceções pode ser a abordagem errada.
Nesse caso, parece um bom argumento para uma estrutura que passa pelo int e pela lógica. Novamente, esse raciocínio pode ser apenas uma constante como o descrito acima, mas em vez de manter os dois no mesmo int, você os armazena como partes distintas de uma estrutura. Inicialmente, temos a regra de que, se a lógica for definida, o int não será definido. Mas não estamos mais vinculados a essa regra; também podemos fornecer justificativas para números válidos, se necessário.
De qualquer maneira, toda vez que você o chama, você ainda precisa de um clichê, para testar a justificativa para ver se o int é válido e, em seguida, retire e use a parte int se a justificativa permitir.
É aqui que você precisa investigar seu raciocínio por trás de "não usar nulo".
Como exceções, nulo significa um estado excepcional.
Se um chamador está chamando esse método e ignorando completamente a parte "lógica" da estrutura, esperando um número sem nenhum tratamento de erro e obtém um zero, ele manipulará o zero como um número e estará errado. Se obtiver um número mágico, tratará isso como um número e estará errado. Mas se obtiver um valor nulo, ele cairá , como deve acontecer.
Portanto, toda vez que você chama esse método, deve verificar o valor de retorno; no entanto, lida com os valores inválidos, dentro ou fora da banda, try / catch, verificando a estrutura para um componente "racional", verificando o int para um número mágico ou verificando um int para um nulo ...
A alternativa, lidar com a multiplicação de uma saída que pode conter um int inválido e uma lógica como "Meu cachorro comeu essa medida", é sobrecarregar o operador de multiplicação para essa estrutura.
... E sobrecarregue todos os outros operadores em seu aplicativo que possam ser aplicados a esses dados.
... E, em seguida, sobrecarregue todos os métodos que podem receber ints.
... E todas essas sobrecargas ainda precisam conter verificações de entradas inválidas, apenas para que você possa tratar o tipo de retorno desse método como se ele fosse sempre um int válido no momento em que você está chamando.
Portanto, a premissa original é falsa de várias maneiras:
- Se você tiver valores inválidos, não poderá evitar a verificação desses valores em nenhum momento do código em que está lidando com os valores.
- Se você está retornando algo diferente de um int, não está retornando um int, portanto não pode tratá-lo como um int. A sobrecarga do operador permite fingir , mas isso é apenas fingir.
- Um int com números mágicos (incluindo NULL, NAN, Inf ...) não é mais realmente um int, é uma estrutura de pobre.
- Evitar nulos não tornará o código mais robusto, apenas ocultará os problemas com ints ou os moverá para uma estrutura complexa de tratamento de exceções.