Is the point of null safety to prevent the accidental assignment of null to a variable and then later doing something like nullable_variable.foo() which would cause a runtime error?
Yes:
With null safety, your runtime null-dereference errors turn into edit-time analysis errors.
It means that a lingering problem that would otherwise become known only when its already too late will turn into an error that you get while you are developing, so you will know about it and can fix it before it ever reaches a customer.
Related
As far as I know, the benefit of null safety is to prevent the accidental assignment of null to a variable and then later doing something like nullable_variable.foo() which would cause a runtime error.
But even when I am not using null safety, I do get a compilation error when calling a method on an object that have the null value, for example I get a compilation error when doing the following:
class Student
{
void foo()
{
}
}
void main()
{
Student? s1 = null; // not using null safety here
s1.foo(); // this causes a compilation error
}
So what I mean is that I am still getting the benefit of null safety without using null safety, so what is the point of null safety?!
You are using "Null Safety". The Null Safety feature is what allows you to write Student? to begin with, to distinguish between types which allow null and types which do not.
With that knowledge, the compiler can disallow calling methods on a nullable type that are not also allowed on null. And it does.
You get a compile-time error for something that, without Null Safety, you'd have written Student s1 = null;, had that accepted by the compiler, and gotten a runtime error.
The promise of Null Safety is that you get compile-time errors instead of runtime errors. The cost is that you need to check for null (or do unsafe casts to non-null types, but checking is better), and you have to explicitly include null in types where you do want to accept null.
To say in simple terms using your above example
Student s1 = null is valid without null safety which will lead to various other problems , Especially when you are dealing with the huge project.
So when you opt into null safety, types in your code are non-nullable by default, meaning that variables can’t contain null unless you say they can.
With null safety, your runtime null-dereference errors turn into edit-time analysis errors.
Where as in null safety , you can't have somethin like Student s1 = null,
Instead use Student? s1 = null. Meaning you are explicity saying the compiler that you are aware that this value can be null and take care of it in the entire program.
So flutter accepts that and helps you through by giving features like ! ?? ?.
To summarize , the null safety was introduced because,
Developers like statically-typed languages like Dart because they enable the type checker to find mistakes in code at compile time, usually right in the IDE. The sooner you find a bug, the sooner you can fix it. When language designers talk about “fixing null reference errors”, they mean enriching the static type checker so that the language can detect mistakes
And Dart is designed to run on an end-user’s device. If a server application fails, you can often restart it before anyone notices. But when a Flutter app crashes on a user’s phone, they are not happy. When your users aren’t happy, you aren’t happy.
Please follow the below links to dive deep into the null-safety concept.
https://dart.dev/null-safety
https://dart.dev/null-safety/understanding-null-safety
Let's say, in Dart/Flutter you are designing a plugin API have a function like this:
static Future<void> startPlaying(Uint8List bytes) async {
_channel.invokeMethod('playBytes', bytes);
}
Would it be true to say that, thanks to the null-safety feature of Dart, we are not responsible in the event that the 'bytes' parameter is passed in as null by the plugin user (and thus causing a runtime crash) because in order to do so, they would have to explicitly unwrap a nullable variable, thereby promising that it is is not null.
OR... is there some other thing we should do such as throwing an exception?
With sound null safety, there is no way to call that method with null as argument.
With unsound null safety, which is what you get if not every library of your program is opted into null safety, it's technically possible to pass null as an argument (because a non-null safe library could be doing the calling, or could be passing null into other null safe code, which doesn't check because it assumes null safety.)
You can choose to check the value coming in, as an extra precaution.
The language makes that hard for you, because locally the code looks null safe.
Something like
if (bytes as dynamic == null) throw ArgumentError.notNull("bytes");
I personally wouldn't bother with that, unless there is a real risk of something going spectacularly wrong if null manages to get into the code.
It's documented as not allowing a null value, and most well-behaved code will respect that. Eventually, when all programs are soundly null safe, that check would just be dead code.
First:
if you mean the final user that use app on device, you should have a validation for input.
Second:
if you mean someone try your plugin to code the app.
you can add required keyword, the dart analysis give the user the error if don't pass bytes.
static Future<void> startPlaying({required Uint8List bytes}) async {
_channel.invokeMethod('playBytes', bytes);
}
I'm using an IO Library which returns a Future<String>. While, yes, the returned type is String instead of String?, the documentation of that library method clearly states that null will be returned if the operation fails (Instead of throwing an exception). Therefore, I need to check for null myself and handle the exception throwing myself.
However, if I check the return value for null, Dart tells me that the operand can't be null and I therefore shouldn't be checking for it.
What should be done in such a case?
As is discussed in the comments, this issue can be seen when using legacy code that hasn't been updated for Dart 2.12 with null-safety.
In previous versions of Dart (pre-2.12), types did not have to have a trailing ? symbol to signify that a value may be null. A Future<String>, for example, could easily complete with a value of null.
To avoid this, make sure all your dependencies are null-safe.
I've recently upgraded Dart (using v2.12.4) and trying to migrate an app I've made.
I'm now stuck at an issue that I can't seem to resolve.
Consider the following pseudo-code:
class Notifications {
Future<List<NotificationItem>> notificationItems;
fillNotificationList() async {
notificationItems = await httpService.getFromEndpoint();
}
}
The notificationItems currently errors with Non-nullable instance field 'notifications' must be initialized..
I've tried different solutions; adding late keyword makes the application throw a LateInitializationError exception and appending = [] gives a type error.
How can I successfully have a Future variable with the null safety features in recent versions of Dart?
It seems to be a nullable variable. Meaning there is a point in time in your program where this is clearly null. So declare it as such:
Future<List<NotificationItem>>? notificationItems;
The rest of your code seems a little weird to me. You named a future like I would name the actual result. You have an async method that doesn't do any async work. Maybe that's just because the example here is simplified.
Or maybe you really really want to insist this is never null. You could initialize it with a completed Future with an empty list:
Future<List<NotificationItem>>? notificationItems = Future.value(<NotificationItem>[]);
I have a desire to satisfy compiler warning level 5. So I have 32 warnings in one file FS0052 The value has been copied to ensure the original is not mutated by this operation
I've followed the only SO post that seems to be related to this warning, but since my type is being type provider generated by Microsoft I can't just go mark the field mutable to quiet the warning. plus making something mutable that actually shouldn't ever be mutated seems like a hack not a fix.
examples:
Nullable .GetValueOrDefault()
Nullable .ToString()
Guid .toString()
struct method calls of any sort I believe
What is the recommended way to deal with this warning from a proper functional perspective?
Not sure if you're still interested.
It seems to me that the compiler emits the warning when it is unsure whether the method call is going to destroy the state of original instance (this should mostly come from any library outside F#).
Explicit copy the value into a variable is, in my case, often mitigate the warning. For example:
open System
// generate the warning due to "ToString()"
let DirSeparator = Path.DirectorySeparatorChar.ToString()
// no warning
let ExplicitCopy = let x = Path.DirectorySeparatorChar in x.ToString()
let Alternative = sprintf "%c" Path.DirectorySeparatorChar
What is the recommended way to deal with this warning from a proper
functional perspective?
I found many questions about the issue, but this particular question I found nowhere else. After having fixed many such warnings, this is my conclusion.
I believe there is no single solution. (Unless you want to resort to silencing the warning all over the place with a compiler directive or something, and I certainly don't want to do that. I have a feeling you agree with me on that, having bumped up the warning level to 5.)
First option
There is frequently another way to code, without having to resort to intermediate values or other complex expressions.
For example, to silence the warning in this case
myStruct.someField <- myRecord.SomeField.ToString()
simply change it to
myStruct.someField <- string myRecord.SomeField
Second option
If you do not find a function or some way to easily rewrite your way out of it, and it is a particular case that repeats frequently in your source, then there is the possibility to create a function or functions that you can use in these cases in order to silence the warning.
For example, I use this function instead of GetValueOrDefault.
let valueOrDefault (v: 'a Nullable) = if v.HasValue then v.Value else Unchecked.defaultof<'a>
Third option
If you have only a single particular case or barely a handful of similar cases, then using an intermediate value is possibly the easiest way to silence the warning. I tend to comment the reason for the verbosity in these cases.