What Does Null! Statement Mean

What is a null statement in C?

From the msdn page:

The "null statement" is an expression statement with the expression missing. It is useful when the syntax of the language calls for a statement but no expression evaluation. It consists of a semicolon.

Null statements are commonly used as placeholders in iteration statements or as statements on which to place labels at the end of compound statements or functions.

know more: https://msdn.microsoft.com/en-us/library/1zea45ac.aspx


And explain a typical use of it.

When you want to find the index of first occurrence of a certain character in a string

int a[50] = "lord of the rings";
int i;

for(i = 0; a[i] != 't'; i++)
;//null statement
//as no operation is required

What does null! statement mean?

The key to understanding what null! means is understanding the ! operator. You may have used it before as the "not" operator. However, since C# 8.0 and its new "nullable-reference-types" feature, the operator got a second meaning. It can be used on a type to control Nullability, it is then called the "Null Forgiving Operator"



Typical usage

Assuming this definition:

class Person
{
// Not every person has a middle name. We express "no middle name" as "null"
public string? MiddleName;
}

The usage would be:

void LogPerson(Person person)
{
Console.WriteLine(person.MiddleName.Length); // WARNING: may be null
Console.WriteLine(person.MiddleName!.Length); // No warning
}

This operator basically turns off the compiler null checks for this usage.

Technical Explanation

Null Safety

C# 8.0 tries to help you manage your null-values. Instead of allowing you to assign null to everything by default, they have flipped things around and now require you to explicitly mark everything you want to be able to hold a null value.

This is a super useful feature, it allows you to avoid NullReferenceExceptions by forcing you to make a decision and enforcing it.

How it works

There are 2 states a variable can be in - when talking about null-safety.

  • Nullable - Can be null.
  • Non-Nullable - Can not be null.

Since C# 8.0 all reference types are non-nullable by default.
Value types have been non-nullable since C# 2.0!

The "nullability" can be modified by 2 new (type-level) operators:

  • ! = from Nullable to Non-Nullable
  • ? = from Non-Nullable to Nullable

These operators are counterparts to one another.
The Compiler uses the information, you define with those operators, to ensure null-safety.

Examples

? Operator usage.

This operator tells the compiler that a variable can hold a null value.

  • Nullable string? x;

    • x is a reference type - So by default non-nullable.
    • We apply the ? operator - which makes it nullable.
    • x = null Works fine.
  • Non-Nullable string y;

    • y is a reference type - So by default non-nullable.
    • y = null Generates a warning since you assign a null value to something that is not supposed to be null.

Nice to know: Using string? is syntactic sugar for System.Nullable<string>

! Operator usage.

This operator tells the compiler that something that could be null, is safe to be accessed. You express the intent to "not care" about null safety in this instance.

string x;
string? y;
  • x = y
    • Illegal! Warning: "y" may be null
    • The left side of the assignment is non-nullable but the right side is nullable.
    • So it does not work, since it is semantically incorrect
  • x = y!
    • Legal!
    • y is a reference type with the ? type modifier applied so it is nullable if not proven otherwise.
    • We apply ! to y which overrides its nullability settings to make it non-nullable
    • The right and left side of the assignment are non-nullable. Which is semantically correct.

WARNING The ! operator only turns off the compiler-checks at a type-system level - At runtime, the value may still be null.

Use carefully!

You should try to avoid using the Null-Forgiving-Operator, usage may be the symptom of a design flaw in your system since it negates the effects of null-safety you get guaranteed by the compiler.

Reasoning

Using the ! operator will create very hard to find bugs. If you have a property that is marked non-nullable, you will assume you can use it safely. But at runtime, you suddenly run into a NullReferenceException and scratch your head. Since a value actually became null after bypassing the compiler-checks with !.

Why does this operator exist then?

There are valid use-cases (outlined in detail below) where usage is appropriate. However, in 99% of the cases, you are better off with an alternative solution. Please do not slap dozens of !'s in your code, just to silence the warnings.

  • In some (edge) cases, the compiler is not able to detect that a nullable value is actually non-nullable.
  • Easier legacy code-base migration.
  • In some cases, you just don't care if something becomes null.
  • When working with Unit-tests you may want to check the behavior of code when a null comes through.


Ok!? But what does null! mean?

It tells the compiler that null is not a nullable value. Sounds weird, doesn't it?

It is the same as y! from the example above. It only looks weird since you apply the operator to the null literal. But the concept is the same. In this case, the null literal is the same as any other expression/type/value/variable.

The null literal type is the only type that is nullable by default! But as we learned, the nullability of any type can be overridden with ! to non-nullable.

The type system does not care about the actual/runtime value of a variable. Only its compile-time type and in your example the variable you want to assign to LastName (null!) is non-nullable, which is valid as far as the type-system is concerned.

Consider this (invalid) piece of code.

object? null;
LastName = null!;

Use of null statement in C

It's typically the side-effect of a code block that was stripped by the preprocessor, like

#if DEBUG
#define ASSERT(_x) Assert(_x)
#else
#define ASSERT(_x)
#endif


ASSERT(test); // Results in null statement in non-debug builds

That, or in loops where your condition already contains whatever needs to be done in each iteration.

NULL statement in VHDL

I will quote IEEE1076-2008:

10.14 Null statement

A null statement performs no action.

null_statement ::= [ label : ] null ;

The execution of the null statement has no effect other than to pass on to the next statement.

NOTE—The null statement can be used to specify explicitly that no action is to be performed when certain conditions are true, although it is never mandatory for this (or any other) purpose. This is particularly useful in conjunction with the case statement, in which all possible values of the case expression shall be covered by choices; for certain choices, it may be that no action is required.

The VHDL language requires a statement for every choice in a case statement: or synthesis will give an error. Example implementation:

case OPCODE is
when "001" => TmpData := RegA and RegB;
when "010" => TmpData := RegA or RegB;
when "100" => TmpData := not RegA;
when others => null;
end case;

Scheme null? statement

As you say,

if the integer N is a certain value, do this

and the difference is in the "do this".

The first one,

((= N 1) (car L))

says "to get the first element of a list, take the car of the list".

The second one,

((= N 0) L)

says "to remove no elements from a list, return the entire list".

The recursions look exactly the same, but the first one reads "get element N - 1 from the cdr of the list", while the second reads "remove N - 1 elements from the cdr of the list".

(It looks like the first function has been translated from Lisp, where nil is "false-y". A more Scheme-y function would return #f.)

Any minor difference between ; or {} to represent a null statement?

The two are semantically identical, and the compiler will generate the same code in both cases. If you're trying to intentionally include an empty loop body, {} makes it more clear that it's on purpose rather than just a stray semicolon. You should always explicitly comment such cases, and it's usually better to rework your code to avoid a busy-wait loop altogether.

What does just ; inside an if block mean?

It's an empty statement. A single semicolon by itself performs no operation.

In this context, it means that if the if condition is true, do nothing.

Without an else section, there is not much use to this code. If there is, then it's a matter of style whether the condition should be inverted and should contain just a non-empty if portion.

In this case it's a simple conditional, so style-wise it's probably better to invert it, however if the condition is more complicated it may be clearer to write this way. For example, this:

if ((a==1) && (b==2) && (c==3) && (d==4)) {
;
} else {
// do something useful
}

Might be clearer than this:

if (!((a==1) && (b==2) && (c==3) && (d==4))) {
// do something useful
}

Or this:

if ((a!=1) || (b!=2) || (c!=3) || (d!=4)) {
// do something useful
}

A better example from the comments (thanks Ben):

if (not_found) {
;
} else {
// do something
}

Versus:

if (!not_found) {
// do something
}

Which method to use depends largely on exactly what is being compared, how many terms there are, how nested the terms are, and even the names of the variables / functions involved.

Another example of when you might use this is when you have a set of if..else statements to check a range of values and you want to document in the code that nothing should happen for a particular range:

if (a < 0) {
process_negative(a);
} else if (a >=0 && a < 10) {
process_under_10(a);
} else if (a >=10 && a < 20) {
; // do nothing
} else if (a >=20 && a < 30) {
process_20s(a);
} else if (a >= 30) {
process_30s_and_up(a);
}

If the empty if was left out, a reader might wonder if something should have happened there and the developer forgot about it. By including the empty if, it says to the reader "yes I accounted for this and nothing should happen in this case".

Certain coding standards require that all possible outcomes be explicitly accounted for in code. So code adhering to such a standard might look something like this.

PHP if statement null === $variable: what for?

It's not an assignment, it's a comparison for equality. It determines if the variable $variable contains the value null.

More in the documentation:

  • Assignment Operators
  • Comparison Operators

why not to check $variable === null

Some people like to use the form with the constant on the left (a "Yoda condition", it is called) so that if they have a typo and only type a single =, it causes a syntax error rather than doing an assignment.



Related Topics



Leave a reply



Submit