Real answer for me is neither, from my experience this "if condition then return x" code is usually sanity check related, like if the language has null values it is to check if the given variable is null and so on, and honestly if else are terrible language constructs for that. They are ok for one or two checks, but if the code involves extra ones things start looking ugly real fast, and the real intent of the software soon starts getting muddled.
This also tends to be part of a larger issue of handling domain expected errors as exceptions, which tends to see functions that might fail not really show that in the return type, and instead relying on function names to display that (say your TrySomeThing).
Like take the example of the GetFruitType Radnom posted above.
Code:
bool GetFruitType()
{
if (type == "orange")
{
return 1;
}
else if (type == "banana")
{
return 2;
}
return -1; //error: not a fruit
}
If you are the function caller you have no idea what constitutes an error, that the function can give an error and so on, because it is returning an int regardless, but if the function returns a result type then the user knew that function could fail, and would have to account that when calling it.
Something like F# computation expressions (for the purposes of this lets call that the result monad), it is just a lot cleaner for this sort of error handling code, since it maintains the code nice and linear while doing all the same functionality.
like say there is a function that takes some value that can be null, and then has to divide that value by some other value (obviously that value cannot be 0), if one did it with the if else, like one saw above we might get a function that looked like this:
Code:
someFunction (somePossibleBaseNullValue, valueToDivide) =
if somePossibleBaseNullValue = null then
return -1
if valueToDivide = 0 then
return -1
return somePossibleBaseNullValue / valueToDivide
and to make it more explicit maybe instead of returning -1 you do a raise exception, however in languages with the result monad, that function becomes something like this:
Code:
someFunction (somePossibleBaseNullValue, valueToDivide ) =
result {
let! checkedBaseValue = somePossibleNullValue |> Result.NotNull "Value was null"
let! checkedValueToDivide = (valueToDivide = 0) |> Result.isFalse "Cannot divide by 0"
return checkedBaseValue / checkedValueToDivide
}
The above function looks extremely similar to what a function without any error checking might look like, and ofc the advantages get bigger and bigger the more complex and the more error checking and so on there needs to be.
Adding to that the above function now returns a type of Result<int,string>, which means it can have either return an int or a string with the error, so the user has to check that, he can't just assume the function was a success when it might not have been, essentially turning a potential runtime error into an error that needs to be solved at compile time.
With all that being said, voted A, feel like it is pretty explicit, but can understand why B would be chosen in such a simple example, in the real world though I would argue most things are more complex so A makes more sense, since it is saying "if this fails the check return now", and then you end up with the main part of the function code without it looking nested, especially since realistically you could have and if inside that if, that just tends to read poorly.