Thursday we ran accross this issue:
#1. If Structure
This is fairly easy to code as is, the trouble is it looks horrible:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
string result; | |
result = Win(); | |
if (result != null) | |
{ | |
return result; | |
} | |
result = Advantage(); | |
if (result != null) | |
{ | |
return result; | |
} | |
result = ScoreNormal(); | |
if (result != null) | |
{ | |
return result; | |
} | |
result = ScorePerson1(); | |
if (result != null) | |
{ | |
return result; | |
} | |
result = ScorePerson2(); | |
if (result != null) | |
{ | |
return result; | |
} | |
result = ScoreTie(); | |
return result; |
#2. Pass in result
One solution is to call all the methods but abort early if you've already found a solution.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
string result; | |
result = Win(); | |
result = Advantage(result); | |
result = ScoreNormal(result); | |
result = ScorePerson1(result); | |
result = ScorePerson2(result); | |
result = ScoreTie(result); | |
return result; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public string Advantage(string previousResult) | |
{ | |
if (previousResult != null) | |
{ | |
return previousResult; | |
} |
#3. Linq
If you like linq you can solve this with a bit of functional code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
return new Func<string>[] | |
{ | |
Win, | |
Advantage, | |
ScoreNormal, | |
ScorePerson1, | |
ScorePerson2, | |
ScoreTie | |
}.FirstNonNull(); | |
public static T FirstNonNull<T>(this IEnumerable<Func<T>> methods) | |
{ | |
return methods.Select(x => x()).First(x => x != null); | |
} |
This reads nicely, but is a bit confusing as to why it works and means all your methods must not use any parameters.
but It can also be used with the yield keyword, which is neat and allows parameters but splits logic.
so we kept looking...
at this point someone pointed out the ?? operator...
It's worth noting that if your language has 'truthiness' (like javascript) you can also do this with the or (||) operator
but It can also be used with the yield keyword, which is neat and allows parameters but splits logic.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private IEnumerable<string> ProcessScores() | |
{ | |
yield return Win(); | |
yield return Advantage(); | |
yield return ScoreNormal(); | |
yield return person2.ScoreOpponentHasntScored(person1); | |
yield return person1.ScoreOpponentHasntScored(person2); | |
yield return ScoreTie(); | |
throw new Exception("Unreachable code was executed"); | |
} |
#4. Do If Null
We were able to get closer to the 'Pass in result' without leaking with the addition of an extension method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
string result = null; | |
result = result.DoIfNull(Win); | |
result = result.DoIfNull(Advantage); | |
result = result.DoIfNull(ScoreNormal); | |
result = result.DoIfNull(ScorePerson1); | |
result = result.DoIfNull(ScorePerson2); | |
result = result.DoIfNull(ScoreTie); | |
return result; | |
public static T DoIfNull<T>(this T t, Func<T> f ) | |
{ | |
if (t == null) | |
{ | |
return f(); | |
} | |
return t; | |
} |
#5. ?? Operator
The ( a ?? b ) operator says if a is null do b. The resulting code is rather nice
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
return Win() | |
?? Advantage() | |
?? ScoreNormal() | |
?? person2.ScoreOpponentHasntScored(person1) | |
?? person1.ScoreOpponentHasntScored(person2) | |
?? ScoreTie(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
return Win() | |
|| Advantage() | |
|| ScoreNormal() | |
|| person2.ScoreOpponentHasntScored(person1) | |
|| person1.ScoreOpponentHasntScored(person2) | |
|| ScoreTie(); |
Which is Best?
Of course that's up to you. For us most liked the ?? operator best, while a few thought the Linq solution was the nicest.
Which one do you like?
Which one do you like?