Why ternary operator doesn't replace if-else - c#

I've met a little problem and a knowledge gap
I found using If-Else style is too boilerplate sometimes and wanted to replace it with elvis-operator, for example:
Dictionary<string, List<List<int>> VarsWithInfo;
want to replace:
if (VarsWithInfo.ContainsKey(ruleVar))
{
VarsWithInfo[ruleVar] = new List<List<int>> { NestingBlocks };
}
else
{
VarsWithInfo[ruleVar].Add(NestingBlocks);
}
with that:
VarsWithInfo.ContainsKey(ruleVar) ?
VarsWithInfo[ruleVar] = new List<List<int>> { NestingBlocks } :
VarsWithInfo[ruleVar].Add(NestingBlocks);
I know that line with ternar operator is too long in this case, but I want to know the primary reason.
Thank you.

The conditional operator ?:, commonly known as the ternary conditional operator, evaluates a Boolean expression, and returns the result of evaluating one of two expressions, depending on whether the Boolean expression evaluates to true or false
From MSDN
The ternary operator always returns a value. In the expression x = a ? b : c, if a is true then it will assign the value of b to x, otherwise it will assign the value of c to x.
Therefore both b and c need to be expressions which result in a value, and both of those values need to be of the same type.
Neither VarsWithInfo[ruleVar] = new List<List<int>> { NestingBlocks } nor VarsWithInfo[ruleVar].Add(NestingBlocks) are expressions, and they do not return a value. Therefore they cannot be used in a ternary.
I'm assuming your code was supposed to be:
if (!VarsWithInfo.ContainsKey(ruleVar))
{
VarsWithInfo[ruleVar] = new List<List<int>> { NestingBlocks };
}
else
{
VarsWithInfo[ruleVar].Add(NestingBlocks);
}
A common way of writing this is:
if (!VarsWithInfo.TryGetValue(ruleVar, out var list))
{
list = new List<List<int>>();
VarsWithInfo[ruleVar] = list;
}
list.Add(NestingBlocks);
This avoids the duplicate dictionary lookup (i.e. calling VarsWithInfo.ContainsKey(ruleVar) and then reading from VarsWithInfo[ruleVar]).

Related

Inline variable declaration outside of scope

Let's say I have two dictionaries with the same keys but with different values.
var metrics1 = new Dictionary<string, double>()
{
{ "Albert", 1.5513 },
{ "Becca", 3.3184 },
{ "Colton", -4.4001 },
{ "Danielle", 6.7 }
};
var metrics2 = new Dictionary<string, double>()
{
{ "Albert", 0.84156 },
{ "Becca", -6.7525 },
{ "Colton", 1.1102 },
{ "Danielle", 0.507944 }
};
If I then choose a dictionary at random to get a value from, using the ternary operator ?:, Visual Studio says that I can inline declare a variable.
var rng = new Random();
var name = "Albert"; // Any name that's present in both dictionaries above
/* Unmodified code */
double metric;
var validName = rng.NextDouble() > 0.5
? metrics1.TryGetValue(name, out metric)
: metrics2.TryGetValue(name, out metric);
/* After suggestion was applied */
// double metric;
var validName = rng.NextDouble() > 0.5
? metrics1.TryGetValue(name, out double metric) // 'metric' is declared here?
: metrics2.TryGetValue(name, out metric);
Why is it that the metric variable in the modified version can be populated by both sides of the ternary ?: operator? Should it not be contained entirely in the scope of the first branch?
Let me answer your comment, // 'metric' is declared here? first. Yes, metric is declared there (well... not technically... see below). To test this try to declare it in the second arm of the ternary statement; if you do this you get,
error CS0841: Cannot use local variable 'metric' before it is declared
on the line containing the first arm. As to,
Why is it that the metric variable in the modified version can be populated by both sides of the ternary ?: operator?
Because the compiler compiles that code to IL that looks something like the IL that would be generated for the previous code, which means in both cases the declaration is above both arms of the ternary assignment.
So for,
Should it not be contained entirely in the scope of the first branch?
the answer is no, because in both cases the declaration is in the scope of the method above the ternary assignment that is also within that scope.
Essentially, the second implementation is just syntactic sugar for the first.

Using the ternary operator with a lambda expression inside a foreach in C#

I'm trying to lear how to properly use lambda expressions in C# and I got into this problem. I have an array of booleans defined like this:
public bool[] worldState = new bool[25];
Now, after giving values to it, I want to cycle thorugh it and simply print "T" when the bool is true, and "F" when it's false. I know how to do it with loops, but I wanted to do it with a one-liner, so I came up with this:
Array.ForEach(worldState, x => x? Console.WriteLine("T"): Console.WriteLine("F") );
This, however, won't work. Why? What's the correct way to do this?
Try:
Array.ForEach(worldState, x => Console.WriteLine(x ? "T" : "F") );
The ternary function requires a value be returned, so in this case your T or F should be returned to the WriteLine method.
Personally, I think a foreach or for loop would be cleaner and more efficient.
foreach(bool bVal in Array) { Console.WriteLine(bVal ? "T" : "F"); }
or
for(i = 0; i < Array.Length; i ++) { Console.WriteLine(Array[i] ? "T" : "F"); }
It's because Console.WriteLine() doesn't return anything. From the Ternary operator documentation, emphasis mine:
The conditional operator (?:) returns one of two values
and Console.WriteLine() does not return a value.
Just use an if statement:
Array.ForEach(worldState, x => { if(x) Console.WriteLine("T"); else Console.WriteLine("F"); } );
Another possibility is just return the string you want using the ternary operator:
Array.ForEach(worldState, x => Console.WriteLine( x ? "T" : "F" ) );
The proper syntax for an if-else in ForEach would be:
Array.ForEach(worldState, x => { if(x) { Console.WriteLine("T"); } else { Console.WriteLine("F");}} );
The ternary operator ? : requires expressions that return compatible values as the arguments. Console.WriteLine is a void function and does not return a value.
Although I would note that a standard foreach loop is much easier to read and debug. I would not recommend using .ForEach() for this type of operation. In fact I wouldn't recommend it for any operation since it doesn't add any capability over the standard loop.

Is there a ternary operator to run a function in c#?

In C# I know you can do things like this:
int number = true ? 1 : 0;
This returns the left or right side depending on if the Boolean is true or not.
But is there a way to do the same thing but instead run a function instead of returning a value? Something like this:
This doesn't work (I get multiple syntax errors)
WPS.EDIT_MODE ? ExecuteEditMode() : ExecutePublicMode();
Thanks.
The conditional operator must return a value. Assuming the functions don't both return a meaningful value for you, you should use an if statement to do that:
if(someCondition)
doA();
else
doB();
Although technically you could use an anonymous function to do this if you really wanted:
int number = someCondition ?
new Func<int>(() => { doA(); return 0; })() :
new Func<int>(() => { doB(); return 1; })();
but that's not suggested; using an if/else is both easier and more readable for that case.
If both functions return an int, yes.
The ternary operator is about returning values. Not returning values doesn't make sense.
The conditional operator (?:) returns one of two values depending on
the value of a Boolean expression.
http://msdn.microsoft.com/en-us/library/ty67wk28(v=vs.80).aspx

?: Operator return void

I want to use the ?: operator intstead of if else
e.g.
var directory = new DirectoryInfo(path);
if (!directory.Exist())
{
directory.Create();
}
else
{
// do nothing
}
I tried to use ?: like this:
var directory = new DirectoryInfo(path);
!directory.Exist() ? directory.Create() : void;
but it says "Invalid expression term void", null also isn't working.
Can anyone tell me a solution?
In you scenario, only having a if condition is better suited.
Just for your understanding, A ternary Operator (?:) needs to result into a value in the right side and also needs a variable in left side to assign the result value e.g.:
x = (y== null) ? 0: 1;
This means assign 0 to x when y is null otherwise assign 1.
So in your example/scenario, you may write something like this to result into a directory creation status as below:
var newDirectoryCreated = (!directory.Exist()) ? directory.Create() : false;
This way, if new directory is created then newDirectoryCreated will assigned with true otherwise false.
Simply keep the if statement and remove the else clase since you aren't doing anything in there.
You're trying to use the ternary operator which, by definition, must return a value.
From the documentation:
The conditional operator (?:) returns one of two values depending on the value of a Boolean expression.
If your just looking for brevity, you could try this instead:
if (!directory.Exist())
directory.Create();
Ternary operator are not designed to replace if/else They are to simplify assignment and declaration. It should be able to assign the result the statement to something like variable or function. There major use are in assignment or reading.
Something like
var status = !directory.Exist() ? directory.Create() : false;
The correct solution would be to stick to native if condition. The following is enough:
var directory = new DirectoryInfo(path);
if (!directory.Exist())
{
directory.Create();
}
The ?: operator's behavior is roughly this:
for x ? y : z, it will return y if x is true, and otherwise it will return z.
From this we can deduce a couple of things:
both y and z must return something (it won't work if either of them evaluate to void), and
y and z must evaluate to the same type. (Imagine you had something like this: var r = x ? y : z;. Which type is r? Is it the type of y or z? We don't know which of them will be returned, but we have to pick a type at compile-time. So they have to return the same type.
In your case, both evaluate to void, which doesn't work. (And if you changed the last part to null, as you said you'd tried, then they evaluate to different types, one of which is void, which breaks both rules)
The conditional operator (?:) musts return one of two values depending on the value of a Boolean expression. So you can stick with if clause instead, it is still simple to understand rather than conditional operator:
var directory = new DirectoryInfo(path);
if (!directory.Exist()) directory.Create();
The ?: operator is an extention of the if-then-else construction.
The extention is in the then-block and the else-block. Where the then-block and the else-block return void for the if-then-else construciton it must return a type for the ?: operator. An aditional constraint for the types in the ?: operator is that the two types must be identical. This constraint is softened a bit by the fact that automatic casting will be used by the compiler to make the two types identical.
Code using ?: operators is in general shorter but also harder to read. This is one point to consider when replacing the if-then-else construct with the ?: operator. Unless your then-block and else-block are one liners it seldom is worth replacing it with the ?: operator.
The if-then construction is a limited version of the if-then-else construction (or visa versa, the if-then-else construction is an extention of the if-then construction). Since the if-then construction has only one code block, the then-block, it is not possible to replace the if-then construction with the ?: operator. You first have to extend the if-then construct with an empty else-block.
Examples:
// initialising an integer with an if-then construct.
int x = 0;
if (some_condition)
{
x = 1;
}
Think of this as if the then-blockreturns an integer.
It is not possible to use the ?: operator strait away.
// initialising an integer with an if-then-else construct.
int y;
if (some_condition)
{
y = 1;
}
else
{
y = 0;
}
Extended the if-then construct to a if-then-else construct and think of the then-block and else-block as returning a integer for witch the types coincidently ;-) match with each other.
It is possible to use the ?: operator in this case.
// initialising an integer with a ?: operator.
int z = (some_condition) ? 1 : 0;
About your code:
var directory = new DirectoryInfo(path);
if (!directory.Exist())
{
directory.Create();
}
In this case I do not see a sensible way to make the then-block returning a value. That makes using the ?: operator impossible or highly complicated with ugly code as a result. My advise, stick to the if-then construct in this case.

How-to: short-circuiting inverted ternary operator implemented in, e.g. C#? Does it matter?

Suppose you are using the ternary operator, or the null coalescing operator, or nested if-else statements to choose assignment to an object. Now suppose that within the conditional statement, you have the evaluation of an expensive or volatile operation, requiring that you put the result into a temporary variable, capturing its state, so that it can be compared, and then potentially assigned.
How would a language, such as C#, for consideration, implement a new logic operator to handle this case? Should it? Are there existing ways to handle this case in C#? Other languages?
Some cases of reducing the verbosity of a ternary or null coalescing operator have been overcome, when we assume that we are looking for direct comparisons, for example. See Unique ways to use the Null Coalescing operator, in particular the discussion around how one can extend the usage of the operator to support String.IsNullOrEmpty(string). Note how Jon Skeet is using the PartialComparer from MiscUtil, to reformat 0s to nulls,
Why is this possibly necessary? Well, take a look at how we write a comparison method for complex objects without any shortcuts (examples from the cited discussions):
public static int Compare( Person p1, Person p2 )
{
return ( (result = Compare( p1.Age, p2.Age )) != 0 ) ? result
: ( (result = Compare( p1.Name, p2.Name )) != 0 ) ? result
: Compare( p1.Salary, p2.Salary );
}
Jon Skeet writes a new comparison to fallback the equality case. This allows the expression to extend by writing a new specific method which returns null, allowing us to use the null coalescing operator:
return PartialComparer.Compare(p1.Age, p2.Age)
?? PartialComparer.Compare(p1.Name, p2.Name)
?? PartialComparer.Compare(p1.Salary, p2.Salary)
?? 0;
The null coalescing operator is more readable because it has two sides, not three. The boolean condition clause is separated into a method, in this case returning null if the expression must be continued.
What would the above expression look like if we could more easily put the condition in-line? Take the expression from PartialComparer.Compare which returns null, and place it in a new ternary expression which allows us to use the evaluation of the left-side expression, with an implicit temporary variable value:
return Compare( p1.Age, p2.Age ) unless value == 0
: Compare( p1.Name, p2.Name ) unless value == 0
: Compare( p1.Salary, p2.Salary );
The basic "flow" of an expression would be:
expression A unless boolean B in which case expression C
Rather than being an overloaded comparison operator, I suppose this is more like a short-circuiting inverted ternary operator.
Would this type of logic be useful? Currently the null coalescing provides us a way to do this with the conditional expression (value == null).
What other expressions would you want to test against? We've heard of (String.IsNullOrEmpty(value)).
What would be the best way to express this in the language, in terms of operators, keywords?
personally I'd avoid the short circuit from operators and just let the methods chain it:
public static int CompareChain<T>(this int previous, T a, T b)
{
if (previous != 0)
return previous;
return Comparer<T>.Default.Compare(a,b);
}
use like so:
int a = 0, b = 2;
string x = "foo", y = "bar";
return a.Compare(b).CompareChain(x,y);
can be inlined by the JIT so it can perform just as well as short circuiting built into the language without messing about with more complexity.
In response to your asking whether the above 'structure' can apply to more than just comparisons then yes it can, by making the choice of whether to continue or not explict and controllable by the user. This is inherently more complex but, the operation is more flexible so this is unavoidable.
public static T ElseIf<T>(
this T previous,
Func<T,bool> isOK
Func<T> candidate)
{
if (previous != null && isOK(previous))
return previous;
return candidate();
}
then use like so
Connection bestConnection = server1.GetConnection()
.ElseIf(IsOk, server2.GetConnection)
.ElseIf(IsOk, server3.GetConnection)
.ElseIf(IsOk, () => null);
This is maximum flexibility in that you can alter the IsOk check at any stage and are entirely lazy. For situations where the is OK check is the same in every case you can simplify like so and entirely avoid extensions methods.
public static T ElseIf<T>(
Func<T,bool> isOK
IEnumerable<Func<T>[] candidates)
{
foreach (var candidate in candidates)
{
var t = candidate();
if (isOK(t))
return t;
}
throw new ArgumentException("none were acceptable");
}
You could do this with linq but this way gives a nice error message and allows this
public static T ElseIf<T>(
Func<T,bool> isOK
params Func<T>[] candidates)
{
return ElseIf<T>(isOK, (IEnumerable<Func<T>>)candidates);
}
style which leads to nice readable code like so:
var bestConnection = ElseIf(IsOk,
server1.GetConnection,
server2.GetConnection,
server3.GetConnection);
If you want to allow a default value then:
public static T ElseIfOrDefault<T>(
Func<T,bool> isOK
IEnumerable<Func<T>>[] candidates)
{
foreach (var candidate in candidates)
{
var t = candidate();
if (isOK(t))
return t;
}
return default(T);
}
Obviously all the above can very easily be written using lambdas so your specific example would be:
var bestConnection = ElseIfOrDefault(
c => c != null && !(c.IsBusy || c.IsFull),
server1.GetConnection,
server2.GetConnection,
server3.GetConnection);
You've got lots of good answers to this question already, and I am late to this particular party. However I think it is worthwhile to note that your proposal is a special case of a more generally useful operation which I dearly wish C# had, namely, the ability to in an expression context, give a name to a temporary computation.
In fact C# has this operator but only in query comprehensions. I wish we had been able to add this as an operator in C# 3:
public static int Compare(Person p1, Person p2) =>
let ages = Compare(p1.Age, p2.Age) in
ages != 0 ?
ages :
let names = Compare(p1.Name, p2.Name) in
names != 0 ?
names :
Compare(p1.Salary, p2.Salary);
"Let expressions" are one of those expressions that are so useful, and found in so few languages, and I genuinely do not understand why language designers do not add it immediately in version one.
If C# had this feature then your proposed:
A() unless B() : C()
is simply
let a = A() in B() ? C() : a
which is hardly more difficult to understand, and bonus, you get to use a in expressions B() and C() if you like.
Let expressions can be emulated in any language that has lambdas; of course let x = y in z is simply (x=>z)(y), but there is no concise way to write that in C# either because C# requires a conversion to a delegate type on every lambda.
Incidentally, in Roslyn we do not represent temporaries as let-expressions, though we could. Rather, we go even one level below that and have a representation for "sequence of operations that might produce values, one of which will become the value of this expression". "let x = y in z" is simply the sequence "allocate x, x = y, z, deallocate x" where the third element is the value. And in the original pre-roslyn C# compiler we had internal operators "left" and "right", which were binary operators that took two expressions and produced either the left or right side, so we could generate ((allocate x) right ((x = y) right z)) left (deallocate x).
My point here is: we often get requests for bespoke language features with unusual punctuation, but it would in general have been better to implement the basic building blocks that you could build these operators out of in a natural way.
To place one proposed implementation away from a very verbose question, let's run with the unless keyword.
(expression A) unless (boolean B) <magical "in which case" operator> (expression C)
... would be all there is to it.
Boolean expression B would have access to the evaluation of expression A through the keyword value. Expression C could have the unless keyword in its expression, allowing for simple, linear chaining.
Candidates for the <magical "in which case" operator>:
:
|
?:
otherwise keyword
Usage of any symbols tend to diminish readability for the average developer. Even the ?? operator is not used widely. I, myself, do prefer to develop verbose code, but that I can easily read one year from now.
So a candidate for your :
expression A unless boolean B in which case expression C.
would be
expression A unless boolean B sothen expression C.
Although many people like me would still use:
if (B) {expression C;}
else {expression A;}
This comes in when you are developing a software with a big team, with different backgrounds, each one on the team master of one language, and just user of others.
More #ShuggyCoUk: Ah, I see that this might work for more than just comparisons? I haven't used C# 3 and extension methods, but I suppose you can declare, for my previous example, below, a
public delegate bool Validation<T>( T toTest );
public static T Validate<T>( this T leftside, Validation<T> validator )
{
return validator(leftside) ? leftside : null;
}
Followed by, per Skeet:
Validation<Connection> v = ( Connection c ) => ( c != null && !( c.IsBusy || c. IsFull ) );
Connection bestConnection =
server1.GetConnection().Validate( v ) ??
server2.GetConnection().Validate( v ) ??
server3.GetConnection().Validate( v ) ?? null;
Is this how that would work in C#? Comments appreciated. Thank you.
In response to ShuggyCoUk:
So this is an extension method in C# 3, then? Also, the result here is an int, not an arbitrary expression. Useful for overloading yet another comparison method. Suppose I wanted an expression for choosing the best connection. Ideally, I want something to simplify the following:
Connection temp;
Connection bestConnection =
( temp = server1.GetConnection() ) != null && !(temp.IsBusy || temp.IsFull) ? temp
: ( temp = server2.GetConnection() ) != null && !(temp.IsBusy || temp.IsFull ) ? temp
: ( temp = server3.GetConnection() ) != null && !(temp.IsBusy || temp.IsFull ) ? temp
: null;
Ok, so one could have a method
bool IsOk( Connection c )
{
return ( c != null && !(c.IsBusy || c.IsFull) );
}
Which would produce:
Connection temp;
Connection bestConnection =
( temp = server1.GetConnection() ) && IsOk( temp ) ? temp
: ( temp = server2.GetConnection() ) && IsOk( temp ) ? temp
: ( temp = server3.GetConnection() ) && IsOk( temp ) ? temp
: null;
But how would method chaining for comparisons work, here? I am pondering something which looks like:
Connection bestConnection =
server1.GetConnection() unless !IsOk(value) otherwise
server2.GetConnection() unless !IsOk(value) otherwise
server3.GetConnection() unless !IsOk(value) otherwise null;
I think that there are so far, hoops to jump through, if I want the result of a conditional to be an expression or result of a method which was in the original conditional.
I assume that the object returned by such methods will be expensive to produce, or will change the next time the method is called.

Categories

Resources