'String?' can not convert to 'String' in dart - dart

A value of type 'String?' can't be assigned to a variable of type 'String'.
Try changing the type of the variable, or casting the right-hand type to 'String'.
This error message i got when i run this code.
This is a simple user input code on dart.
var person = ['abc', 'qwe', 'dfg'];
stdout.write('Enter Index : ');
String p = stdin.readLineSync(); //Error
int per = int.parse(p);
per > person.length
? stderr.write('Index does not exist')
: stdout.write('Person ${person[per]}');
}

Seems like readLineSync() returns nullable type. But you declare variable p as non-nullable. Either declare p as nullable: String? instead of String or make readLineSync() return default value if null:
String p = stdin.readLineSync() ?? "";// will return empty String if method readLineSync() returns null.

First of all check the null safety documentation, you'll learn everything you need to know
https://dart.dev/null-safety/understanding-null-safety
readLineSync returns a value of Type String? Meaning the return value must be a nullable String.
p is of type String and therefore expects a String (not a nullable String). the trick here is to cast stdin.readLineSync() to String:
String p = stdin.readLineSync() as String;
String p = stdin.readLineSync()!; #shorthand syntax
On top of that, your code needs some improvements. What if p can't be cast into an integer? One way to handle this is to add a try block and catch any FormatException.

Related

How to parse a 'String?' variable in Dart [duplicate]

This question already has answers here:
"The argument type 'String?' can't be assigned to the parameter type 'String'" when using stdin.readLineSync()
(3 answers)
Closed 6 months ago.
I am trying to parse an input with the type 'String?' into a double, but it is saying that -
The argument type 'String?' can't be assigned to the parameter type 'String'.
stdout.write("Enter the first number - ");
String? vari = stdin.readLineSync();
var first = int.parse(vari);
Change it to:
int? first = int.tryParse(vari.toString());
This is because String? is nullable, vs String.
.parse functions require non-nullable Strings.
tryParse returns an int if the string is parsable, and returns null if it can't be parsed. This is why I changed var first to int? first.
You can check afterwards if first is null or not. You can also perform this check before parsing it, and your code would look like this:
String? vari = stdin.readLineSync();
if (vari != null) var first = int.parse(vari);
This would work.

Why compiler assuming `json['x'] = int?`?

class Point {
int x;
int y;
Point(this.x, this.y);
Point.zero()
: x = 0,
y = 0;
Point.fromJson({required Map<String, int> json})
:x = json['x'], //Error : `The initializer type 'int?' can't be assigned to the field type 'int'`
y = json['y']; // Error :`The initializer type 'int?' can't be assigned to the field type 'int'`
}
As you can see the argument json here is Map<String , int> so why am getting this error here.When both are non-nullable here ?
Why compiler assuming json['x'] = int? ?
Because the [] operator on Map returns a nullable by spec:
V? operator [](Object? key)
The value for the given key, or null if key is not in the map.
https://api.dart.dev/stable/2.15.1/dart-core/Map/operator_get.html
So if you are asking for a key that is not in your Map you will get a null value back and not an exception.
If you are 100% sure json['x'] will always work and want the application to crash in case this is not the case, you can use json['x']!. Alternative, you need to provide default values or other type of handling in case these values is not in the map.

is there a way to perform optional casting in Dart?

in Swift or Kotlin I can do something like this
var fullName = myMap["fullName"] as? String
then as a result that fullName data type will be optional String ( String? ).
I need to get optional type after type checking like that
I can't directly perform null coalescing operator to that map, because dart will give weird result. for example like this
// 'data' is Map<String, dynamic>
final fullName = data["fullname"] ?? "John Doe";
final double myNumber = fullName;
as you can see, the IDE will not show an error at all, I expect that fullName will be a String, so it will have an error when I assign a String to myNumber that require double.
If you know in advance that data["fullname"] is a String, then you could do:
final fullName = (data["fullname"] ?? "John Doe") as String;
If data["fullname"] turns out not to be a String at runtime, you'll get a runtime exception from the cast failure. If that's something you need to handle, then you could easily make a trivial helper function that checks if a dynamic value is the desired type first and that returns null if it isn't:
T? tryCast<T>(dynamic object) => object is T ? object : null;
final fullName = tryCast<String>(data["fullname"]) ?? "John Doe";
and now fullName is statically known to be a String, and accidentally assigning it to a double will be a compile-time error.
The safe nullable cast operator known from Kotlin currently doesn't exist in Dart but it soon might.
In your case though, why not simply write
String? fullname = myMap["fullname"];
The nullable cast operator as? in Kotlin yields null if myMap["fullname"] contains anything but a non-null String. As long as you're only dealing with Strings or null, the above works just fine. (And if there's anything but a String or null it crashes, which is probably better than just continue on with null in most situations)

Passing Object.Attr to function

Usually, a reference to an Object's Attribute Value returns that value.
Object o = current Object
display o."Object Text"
However, if I pass that reference to a function that expects a string parameter, I get an error.
string displaySomeString(string s) {
display s
}
Object o = current Object
displaySomeString(o."Object Text")
I get this result from the debugger:
-E- DXL: incorrect arguments for function (displaySomeString)
-I- DXL: All done. Errors reported: 1. Warnings reported: 0.
What gives? How do I robustly pass an Attribute value into a function?
Here's my suspicion. If you're passing the object attribute value directly in the function call--
displaySomeString(o.attr)
--instead try passing it with an empty string at the end:
displaySomeString(o.attr "")
Or set the attribute value as something like
string v = o.attr
and then pass v in as
displaysomeString(v)
and I think it might work. o.attr really isn't a string, but a derived type, and concatenating an empty string at the end casts it to a string.

'?'must be followed by a call, member lookup or subscript

I have defined a String type computed property:
var name : String? {
//an optional variable
var theName : String?
if SOME_CONDITION {
theName = “I have a name”
}
//ERROR: '?'must be followed by a call, member lookup or subscript
return theName?
}
I want to return whatever theName is, if it is nil, return nil. So I use return theName? , I don’t want to have runtime error. The compiler however raise an error '?'must be followed by a call, member lookup or subscript Why? How to get rid of it.
What about this? Looks more elegant to me:
var name : String? {
let condition = true // your own condition here of course
return condition ? "I have a name" : nil
}
The problem in your code:
var name : String? {
var theName : String?
let condition = true // your own condition here of course
if condition {
theName = "I have a name"
}
return theName // get rid of the ? here
}
The field theName is already optional, no need to add another ? there.
Why is my proposed solution not an alternate solution:
The construct I used is called ternary operator:
The ternary conditional operator is a special operator with three parts, which takes the form question ? answer1 : answer2. It is a shortcut for evaluating one of two expressions based on whether question is true or false. If question is true, it evaluates answer1 and returns its value; otherwise, it evaluates answer2 and returns its value.
It behaves like the if statement but is suitable here as it is shorter and thus clearer to read: Depending on the condition, the value is either theName or nil. You really don't need to assign the value to any other variable, because, afterall, you are computing it, so might as well simply return it as the condition decides, what the value is.
Adding ? to the end of a type makes it Optional.
Adding ? to the end of an optional variable invokes Optional Chaining.
You specify optional chaining by placing a question mark (?) after the
optional value on which you wish to call a property, method or
subscript if the optional is non-nil. This is very similar to placing
an exclamation mark (!) after an optional value to force the
unwrapping of its value. The main difference is that optional chaining
fails gracefully when the optional is nil, whereas forced unwrapping
triggers a runtime error when the optional is nil.
To reflect the fact that optional chaining can be called on a nil
value, the result of an optional chaining call is always an optional
value, even if the property, method, or subscript you are querying
returns a non-optional value. You can use this optional return value
to check whether the optional chaining call was successful (the
returned optional contains a value), or did not succeed due to a nil
value in the chain (the returned optional value is nil).
Specifically, the result of an optional chaining call is of the same
type as the expected return value, but wrapped in an optional. A
property that normally returns an Int will return an Int? when
accessed through optional chaining.
Example
class Foo {
var bar: Int
}
var x: Foo? // ? is attached to type Foo, it makes x an optional variable
let y: Int? = x?.bar // ? is attached to the variable x, this is optional chaining, it makes .bar return Int?

Resources