So I've been following along to a fireship course on dart and I got the error: "Null check operator used on a null value". Was just wondering why? Here is the code:
String? answer;
String result = answer!;
That's working exactly as intended.
The String? answer; declaration introduces a nullable variable with a current value of null.
The answer! expression reads that value, checks whether it's null, throws if the value is null, or evaluates to the non-null value if it isn't null.
Since the value is indeed null, that operation throws the error you see.
The ! is the "null check operator". It's used on the value null. The error message is actually quite precise.
To avoid that, make sure the answer variable has a non-null value when you use the ! operator on it. (Often you won't need the ! for local variables because assigning a non-null value to the variable also promotes the variable's type to non-nullable, but there are cases where the compiler can't see that assignment, for example if it happens in a callback function.)
Related
I'm a student who's new in Swift.
While I'm studying about the Optional, I got curious about the keyword nil, so I tried some experiment with it. I'm using Swift version 5.5.
As you can see in the image below, if I assign nil to a optional variable (which I named 'name') and then print it with print(name) and print("(name)") (string interpolation), I got nil on the console in both cases. (Line 5, 9)
But when I print nil without the optional variable, which I printed it with print(nil) and print("(nil)"), I got an error on both cases. (Line 7, 11)
I expected them all to print out nil but they didn't.
I really want to know the difference between those cases.
The issue is that nil isn't just one single value, like null in Java/C#.
nil is syntactic sugar for Optional<Wrapped>.none. There's one different kind of value for every possible Wrapped. E.g. there is Optional<Int>.none and Optional<String>.none, and you can't assign from one to the other, because they're unrelated types.
When you use nil, the value of the Wrapped generic parameter is inferred from context, much like when you do:
let a = Optional<Int>.none // most explicit
let b: Optional<Int> = Optional.none // Generic Wrapped param inferred from the type annotation
let c: Optional<Int> = nil // Same inference
print takes an Any, so that doesn't give any relevant contextual type information. When you say print(nil), it's not clear what the typed of Wrapped should be. You might not care (because Optional<Int>.none and Optional<String>.none both print "nil"), but the type system can't leave it open ended, so it's a type error.
If you added contextual type information, it works, such as using a variable of a known type, or using a coercion:
print(nil as String?)
Interesting question actually. If you look at the Swift documentation:
Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”.
So think of it as nil is the absence of some value. As an example if you have:
var name: String?
name can either be a string value, or the absence of a string value.
So it makes no sense to try and print nil explicitly since you already know that it's the absence of a value, however, it makes sense to print name to check if it has a string value and in that case what it is, or if it has no string value.
The error message in XCode tells you exactly what happens: nil is not compatible with expected argument type Any - the print function expects a non-nil argument, as does the string interpolation with \(),
I'm using this repository to familiarize myself with Amazon's Cognito user system. In the file lib/screens/signup_screen.dart, starting at line 27 there is this piece of code:
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(labelText: "Email"),
controller: _emailController,
validator: (value) =>
!validateEmail(value) ? "Email is Invalid" : null,
),
However, since we have null safety in Dart since version 2.x, this piece of code fails with the error message: The argument type 'String?' can't be assigned to the parameter type 'String'.
What I got from that is that value may not be equal to null and the code cannot guarantee that as it is. Please correct me if I'm wrong and I'm also hoping someone can explain to me why the code cannot guarantee null safety here. If the textfield is empty, value should be equal to "" instead of null.
Anyhow, I decided to use the ternary operator to fix this issue:
!validateEmail(value == null ? "" : value) ? ...
Which the IDE suggested I correct to:
!validateEmail(value ?? "") ? ...
Dart also suggested to insert a null check as another alternative:
!validateEmail(value!) ? ....
Up till now, I have just been using these fixes as a workaround to produce code fast without trying to understand what's actually going on.
So what's the difference between these methods? Does the ?? in the second method have an integrated == null check and is it exactly the same as writing value == null ? "" : value?
Also, what does the nullcheck value! do? Yes, it checks if value is equal to null, but what does it do for me when value is in fact equal to null?
The ?? is a null-aware operator , which returns the expression on its left unless that expression’s value is null, in which case it evaluates and returns the expression on its right:
print(1 ?? 3); // <-- Prints 1.
print(null ?? 12); // <-- Prints 12.
Which is the same as doing a ternary operator but more readable.
The bang operator ! casts aways the nullability of the variable, meaning YOU explicitly say that the value CAN'T be null.
Of course, like any cast, using ! comes with a loss of static safety.
The cast must be checked at runtime to preserve soundness and it may
fail and throw an exception.
For further reading check out the documentation.
You can start learning more about sound null safety in Dart here: Understanding Null Safety
The null assertion value! is equal to casting to a non-nullable type: value as String. It raises an exception if value is null.
The conditional ?? operator acts as you expect: value ?? "" is a shorthand equivalent for value != null ? value : ""
What I got from that is that value may not be equal to null and the code cannot guarantee that as it is.
value might be null, but validateEmail requires that its argument is not null.
can explain to me why the code cannot guarantee null safety here. If the textfield is empty, value should be equal to "" instead of null.
Because that's what TextFormField's constructor specifies. Its validator parameter is declared to be a FormFieldValidator<String>?, and FormFieldValidator<T> is defined to be a String? Function(T? value). In other words, the validator callback is declared to be a function that must accept null as an argument. The compiler does not have semantic knowledge to know whether TextFormField will actually invoke that callback with null instead of an empty string in practice.
So what's the difference between these methods? Does the ?? in the second method have an integrated == null check and is it exactly the same as writing value == null ? "" : value?
?? is one of Dart's null-aware operators; it automatically checks for null for you. As stated in the Dart Language Tour:
expr1 ?? expr2
If expr1 is non-null, returns its value; otherwise, evaluates and returns the value of expr2.
So yes, it is equivalent to expr1 == null ? expr2 : expr1 (except that ?? would evaluate expr1 only once, which matters if evaluation has side effects). You should prefer ?? anyway because it better conveys intent.
Also, what does the nullcheck value! do? Yes, it checks if value is equal to null, but what does it do for me when value is in fact equal to null?
value! will throw an exception (specifically a TypeError) if value turns out to be null at runtime. Do not use ! unless you can logically guarantee that value will not be null.
I'm getting the error with the following code in my cellForRowAt method:
self.db.collection("myCollection").document(self.currentUser!).updateData(["myArray":FieldValue.arrayRemove(myArray![indexPath.row])]).
The Cannot convert value of type 'String' to expected argument type '[Any]' error is happening at myArray![indexPath.row]
My function is meant to remove a String value from myArray, so I'm not sure how to resolve this error.
I appreciate any help/guidance!
arrayRemove takes an array of values to be removed, you you'd want to use:
.arrayRemove([myArray![indexPath.row]])
See the added brackets
(https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array)
That being said, be aware that you're force unwrapping multiple things with ! -- be aware that if one of these values is nil, your program will crash.
I'm reading "Programming in Lua" book and I don't understand exercise 2.1:
What is the value of the expression
type(nil)==nil?
(You can use Lua to check your answer.) Can you explain this result?"
When I execute this code I get "false" as result. I could not explain this result, from my point of view correct result should be "true". I tried
type(some_undeclared_variable)==nil
and it also gives me "false".
The function type() always returns a string, the value of type(nil) is the string "nil", which is not the same as nil, they have different type.
I'm using C++ Builder XE6. I'm getting a UnicodeString as a parameter and I wish to check if the string is set to NULL, and not an empty string.
I've tried to do some simple compares to see if the param is null, but seem to be failing. I'm using the == operator which doesn't seem to be working, which makes me think it is overloaded.
I've tried:
if (searchString == NULL)
In the debugger view, it shows the value of { NULL } in the local variables. If I add the variable to the watch list, then it shows it has a property of "Data" which is NULL.
Any ideas on how I can properly do the compare?
There is no such thing as a NULL value for a UnicodeString. A string is a series of characters, but NULL is a pointer (well - actually it is a macro that evaluates to an int, 0, but it is supposed to be used to indicate null pointers if your compiler doesn't support nullptr).
Internally, the data member of UnicodeString is NULL when the string is empty, and non-NULL when the string has at least 1 character.
To check if the string is empty, use the IsEmpty() method, which checks if the data member is NULL or not. There is only one empty state; there is no distinction between "empty" and "null" like some languages have.
The value you see in the debugger is the internal data member of UnicodeString, it is not a part of UnicodeString's interface. When you see NULL in the debugger, you should treat it as being an empty string.