What does the exclamation mark mean before a function call? - dart

I was following a PR for Flutter and came across this code:
if (chunkCallback != null) {
chunkCallback!(0, 100);
}
What does the exclamation mark mean after chunkCallback? Nothing I search on Google works.

"!" is a new dart operator for conversion from a nullable to a non-nullable type.
Read here and here about sound null safety.
Use it only if you are absolutely sure that the value will never be null and do not confuse it with the conditional property access operator.

chunkCallback is a nullable reference to a function.
If you are sure that chunkCallback can't be null at runtime you can "Cast away nullability" by adding ! to it to make compiler happy
typedef WebOnlyImageCodecChunkCallback = void Function(
int cumulativeBytesLoaded, int expectedTotalBytes);
...
class Class1 {
final WebOnlyImageCodecChunkCallback? chunkCallback;
Class1(this.chunkCallback);
void test() {
if (chunkCallback == null) {
throw Exception("chunkCallback is null");
}
chunkCallback!.call(0, 100);
}
}
Esentially, ! in this case is a syntactic sugar for
(chunkCallback as WebOnlyImageCodecChunkCallback).call(0, 100);

I think it is a shorthand syntax for “Casting away nullability”, as per the docs: https://dart.dev/null-safety/understanding-null-safety#null-assertion-operator

The variable chunkCallback must be able to accept null and you cannot call a function on a nullable type without either using ! or ?. This is part of Darts sound null safety
Some great videos on this:
Flutter vid
YouTube vid
Even though the conditional statement checks for null, Dart still requires the exclamation mark before the function call. The difference between using ! over ? is that it will throw an exception instead of using the variable if the value is null.
Some examples:
class Car {
String? make; // String or null type
Car([this.make]); // parameter is optional
}
main() {
Car test = Car('Ford'); // initialised with a value
Car test2 = Car(); // no value given so null is default
// returns 4
if (test.make != null) {
print(test.make!.length); // ! still needed even though !=null condition stated
} else {
print('The value is null');
}
// returns The value is null
if (test2.make != null) {
print(test2.make!.length);
} else {
print('The value is null');
}
}
Above example shows that conditional check for null is not enough.
And choosing between ? and !
class Customer {
String? name;
String? surname;
Customer(this.name, [this.surname]); // constructor with optional parameter []
}
main() {
Customer ford = Customer('John'); //only name is given a value
// calling a method on a nullable type doesn't work
// so ? and ! used here after variable name and before method
print(ford.name!.length); // operation executed as usual => 4
print(ford.surname?.length); // ? on null value returns null => null
print(ford.surname!.length); // Exception is thrown => TypeError
}

Related

dart throw unchecked_use_of_nullable_value error unnecessary? [duplicate]

This question already has answers here:
"The operator can’t be unconditionally invoked because the receiver can be null" error after migrating to Dart null-safety
(3 answers)
Closed 2 months ago.
Even below code already check t.s!=null, dart still throws Error:
t.dart:7:26: Error: Property 'length' cannot be accessed on 'String?' because it is potentially null. Try accessing using ?. instead. if (t.s != null && t.s.length > 5) {}
class Test {
String? s;
}
void main() {
Test t = Test();
if (t.s != null && t.s.length > 5) {}
}
Add extra var would solve it as below:
void main() {
Test t = Test();
var s = t.s;
if (s != null && s.length > 5) {}
}
Why dart throws error even t.s!=null already checked?
Is there a way to do it without adding extra var?
Additionally, in Typescript, it won't throw error:
function main(t:{s?:string}){
if(t.s!==undefined && t.s.length > 5){
}
}
if you check t.s != null, after that you can safely convert it from String? to String.
( ! will convert you from String? to String )
void main() {
Test t = Test();
if (t.s != null && t.s!.length > 5) {}
}
https://dart.dev/null-safety/understanding-null-safety
“Casting away nullability” comes up often enough that we have a new shorthand syntax. A postfix exclamation mark (!) takes the expression on the left and casts it to its underlying non-nullable type."
Since s is nullable, a subclass might change s to a getter that randomly returns either a null or a string. Thus, the analyzer correctly cannot type-promote s to non-null upon seeing t.s != null, because it might be null in the next expression. This is why copying it to a local variable works, because there's no chance of that any more.
I have a video on this: https://youtu.be/rqS_Q34RcUk
There's nothing to fix. There is a discussion on allowing a library-private class to permit this type promotion since it could not be overridden by unknown code.

Bang operator vs assert statements

In the code below, I'm casting away the nullability by using the bang operator.
void main() {
String? foo;
foo!.toLowerCase();
}
But when I use assert just before calling the function, I get an error.
void main() {
String? foo;
assert(foo != null);
foo.toLowerCase(); // Error
}
Is bang operator not doing the same thing behind the scene?
Note: I'm not looking for a solution to how to make it work, there are many ways, even the flow statement ones, if (foo == null) return;
(Adding this an answer instead of a comment.)
The point of asserts is that they can be disabled and that they will not incur any runtime penalty. It's been some matter of debate, but the current philosophy is that this means that asserts will not perform type promotion, so even if you do:
bool foo(Object object) {
assert(object is String);
// error: The getter 'isEmpty' isn't defined for the type 'Object'
return object.isEmpty;
}
For the same reason, assert(someLocalVariable != null) will not promote someLocalVariable to a non-nullable type:
bool bar(String? string) {
assert(string != null);
// error: The property 'isEmpty' can't be unconditionally accessed
// because the receiver can be null.
return string.isEmpty;
}
As of Dart 2.12 with null-safety enabled, however, you can get the desired effect by just performing the cast directly. That will promote the type and throw a runtime exception if the cast fails:
bool foo(Object object) {
object as String;
return object.isEmpty;
}
bool bar(String? string) {
string!;
return string.isEmpty;
}

Why does F# compiler check `this != null`? [duplicate]

What should IEquatable<T>.Equals(T obj) do when this == null and obj == null?
1) This code is generated by F# compiler when implementing IEquatable<T>. You can see that it returns true when both objects are null:
public sealed override bool Equals(T obj)
{
if (this == null)
{
return obj == null;
}
if (obj == null)
{
return false;
}
// Code when both this and obj are not null.
}
2) Similar code can be found in the question "in IEquatable implementation is reference check necessary" or in the question "Is there a complete IEquatable implementation reference?". This code returns false when both objects are null.
public sealed override bool Equals(T obj)
{
if (obj == null)
{
return false;
}
// Code when obj is not null.
}
3) The last option is to say that the behaviour of the method is not defined when this == null.
leppie is right. Just to elaborate on his answer (and confirm his suspicion that F# doesn't guarantee this != null): discriminated unions may be marked with the attribute [<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>] allowing cases to be represented by the value null. Option<'T> is such a type. The None case is represented by null at run-time. (None : option<int>).Equals(None) is syntactically valid. Here's a fun example:
[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type Maybe<'T> =
| Just of 'T
| Nothing
[<CompilationRepresentation(CompilationRepresentationFlags.Instance)>]
member this.ThisIsNull() = match this with Nothing -> true | _ -> false
Decompiling ThisIsNull with Reflector shows
public bool ThisIsNull()
{
return (this == null);
}
And the result:
Nothing.ThisIsNull() //true
The reason F# does this (I suspect) to optimize empty lists as null.
By adding this check, it allows one to call an instance method on a null instance without any problems.
See my blog post from a while back.
In C#, this is irrelevant.
To answer the question:
It should return true as both instances are null and deemed equal.
If this is null, the code can't be called, so that case needn't be considered (in C# anyway, there are cases where languages allow a null object to have a method dereferenced though obviously if it internally examines any of its non-existent fields it will error. Consider:
return x.Equals(y);
If x is null, we don't even get to call into Equals for the null check to count.
Hence we need only consider:
public bool Equals(T obj)
{
if(obj == null)
return false;
//logic defining equality here.
}
Where the possibility of both objects being null does come up, is when we are examining them from a static == operator override or from an IEqualityComparer<T> implementation:
public bool Equals(T x, T y)
{
if(x == null)
return y == null;
if(y == null)
return false;
//logic defining equality here.
}
Note that a useful shortcut here if equality can be lengthy to determine (e.g. comparing long strings), then we may take advantage of the fact that identity entails equality - that is something is always equal to itself, even Ayn Rand could figure that out ;) There are also algorithms that make comparing an item with itself quite common, making this shortcut well worth including. In this case the identity comparison already includes the check for both being null, so we leave it out again:
public bool Equals(T x, T y)
{
if(ReferenceEquals(x, y))
return true;
if(x == null || y == null)
return false;
//logic defining equality here.
}
For most methods I assume undefined behavior when called with this==null. That's because most programmers write their code under the assumption that this!=null, which is guaranteed by the C# specification if the calling code is written in C#.
That's why every sane caller of x.Equals(y) should either know for sure that that x is not null, or add a manual null check.
In most cases I wouldn't call Equals directly at all, but instead use EqualityComparer<T>.Default.
I would definitelly go with option 1:
if (this == null)
{
return obj == null;
}
if (obj == null)
{
return false;
}
null object always equals null object.
Sample code is in the MSDN: http://msdn.microsoft.com/en-us/library/ms131190.aspx?ppud=4
If this==null you will get a runtime exception calling Equals() on that object.

Why is `== null` preferable to `is Null`?

In Dart, checking for a value to be == null seems similar to checking if it is Null. Why is the former more preferable?
It is the type of comparison you are doing. In == null, you are comparing an object/primative to null whereas in the latter, is Null, null is an object. It makes no difference in the compiler.
== null is more favourable as the two being compared could be both primitives, which saves memory in the system.
== null is familiar to developers coming from other popular languages.
Using this type check in Dart not a quite correct.
if(value is Null) {
}
In Dart the static type of null is bottom type.
An as we know, the bottom type is a subtype of all types.
Now we test subtypes in Dart (including value of bottom type, null)
void main() {
var subtype = new Subtype();
var typeOfBase = new TypeOf<Base>();
test(subtype, typeOfBase);
test(null, typeOfBase);
}
void test(value, TypeOf typeOf) {
var type = typeOf.type;
var runtimeType = value.runtimeType;
if(typeOf.isSubtypeOf(value)) {
print("Value [$value] of type [$runtimeType] is a subtype of [$type[");
} else {
print("Value [$value] of type [$runtimeType] is NOT a subtype of [$type]");
}
}
class Base {
}
class Subtype implements Base {
String toString() => "subtype";
}
class TypeOf<T> {
Type get type => T;
bool isSubtypeOf(value) => value is T;
}
Results:
Value [subtype] of type [Subtype] is a subtype of [Base[
Value [null] of type [Null] is NOT a subtype of [Base]
So, here we can see that performing this test is not quite correct in Dart because null has not bottom type but a value of regular type Null which are not a bottom type and, of course, not a subtype of Base type.
So, I not recommend using is Null in Dart because in the future the class Null can be considered as deprecated and replaced by some internal implemented type as void or dynamic.

Returning NULL Structure

I am calling a function which returns a structure of the type CvBox2D, however I want to check for an error in the function and return NULL if there is an error.
CvBox2D function()
{
...
if(ERROR)
return NULL;
...
}
I am getting an error : cannot convert from 'int' to 'CvBox2D'
Your function return type is CvBox2D, so you can't convert a (NULL) pointer to it.
If you really need to return "nothing" if the check inside the function fails, you can change the return type to a pointer to CvBox2D:
CvBox2D* function()
{
...
}
You will also have to change the way the returned object is created inside your function.
Note that using raw pointers in C++ usually isn't a good idea.
Take a look at std::shared_ptr (available in C++11) if you think you really have to use pointers.
If you want to return some error code, you can do the following:
int function(CvBox2D* output) {
// code...
// Assign to struct.
output->center = ...;
if (error) {
return RC_ERROR_FOO;
}
return RC_OK;
}
Then you call this function using a struct you've already allocated (for example, on the stack):
{
CvBox2D myBox;
int retval = function(&myBox);
if (RC_OK == retval) {
printf("Good! Angle of box: %g", myBox.angle);
} else {
printf("Error: %d", retval);
}
}
Where RC_OK, RC_ERROR_FOO are defined as constant integers, or better, as an enum (if you're using C++).
The other answers solve your problem, but if you want to keep the signature of your function, instead of returning an error code, you should throw an exception.

Resources