is there a way to perform optional casting in Dart? - 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)

Related

Difference between "toString" and "as String" in Dart?

Is there any difference between .toString and as String in Dart?
toString() is a method on Object and is therefore available on every object. The method is used to get a string representation of the object:
A string representation of this object.
Some classes have a default textual representation, often paired with a static parse function (like int.parse). These classes will provide the textual representation as their string represetion.
Other classes have no meaningful textual representation that a program will care about. Such classes will typically override toString to provide useful information when inspecting the object, mainly for debugging or logging.
https://api.dart.dev/stable/2.13.4/dart-core/Object/toString.html
as String is a typecast in Dart and is used to tell the analyzer/compiler that whatever it assumes, you are now going to tell it that your object is in fact a String at runtime. You can hereafter use the object like a String.
But the compiler will add a check at runtime and if the object is not compatible with the interface of String, your application will crash because you have lied to the compiler.
It is therefore two entire different things and is used for different purposes. You can e.g. not use as String on an object which is not already a String.
The safest you can do is just call toString() since toString() on String will just return itself.
They are completely different!
.toString() is a method to represent data of a object but as String is a type cast which tries to convert the object itself to a String .
Imagine you have a class named Person
class Person {
String firstName;
String lastName;
Person(
this.firstName,
this.lastName,
);
}
now casting person to a String will lead to an _CastError error since Person is not a String or a subtype of String(inherited classes from String class)
final person = Person('sajad', 'abd');
final personAsString = person as String;
Meanwhile, the method .toString() will represent you object in a String.
final person = Person('sajad', 'abd');
final personToString = person.toString();
print(personToString); // result: Instance of 'Person'
.toString() is defined for every class in dart and you can override it in you custom classes
for example you can override it in Person class to represent firstname and lastname of person
class Person {
String firstName;
String lastName;
Person(
this.firstName,
this.lastName,
);
#override
String toString() => 'Person(firstName: $firstName, lastName: $lastName)';
}
And now the result of
final person = Person('sajad', 'abd');
final personToString = person.toString();
print(personToString);
would be
Person(firstName: sajad, lastName: abd)

'String?' can not convert to 'String' in 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.

Mismatching types 'Int64' and '_' when trying to assign optional Int64 to a dictionary key

Question regarding Swift 2.1 in Xcode 7.
I have declared an optional variable like this:
var something: Int64?
I would like to later assign it to a dictionary key using a shorthand if, like this:
dictionary['something'] = (something != nil) ? something! : nil
XCode is giving me the following validation error:
Result values in '? :' expression have mismatching types: 'Int64' and
'_'
What is the issue here? Why can't optional Int64 be nil?
There are a number of problems here. First, Int64 isn't an AnyObject. None of the primitive number types are classes. They can be bridged to AnyObject using NSNumber, but you don't get that bridging automatically for Int64 (see MartinR's comment. I originally said this was because it was wrapped in an Optional, but it's actually because it's fixed-width).
Next, this syntax:
(something != nil) ? something! : nil
Is just a very complicated way to say something.
The tool you want is map so that you can take your optional and convert it to a NSNumber if it exists.
dictionary["something"] = something.map(NSNumber.init)
Of course, if at all possible, get rid of the AnyObject. That type is a huge pain and causes a lot of problems. If this were a [String: Int64] you could just:
dictionary["something"] = something
You can't add a Int64 to a dictionary of type [String : AnyObject], you need to wrap in in an NSNumber object. You can only store objects that conform to AnyObject in your dictionary.
var something: Int64?
something = 42
if let myVal: Int64 = something { // unwrap to make sure the value is there
let myNum = NSNumber(longLong: myVal) // create an NSNumber from your Int64
dictionary["something"] = myNum // insert it into the dictionary
}
As Anton Bronnikov said below, if your dictionary was type [String : Int64], you would be able to add your Int64 to it no problem.
It seems that others have already pointed out the issues with the types in your dictionary. I want to add that you can also use the nil coalescing operator '??' as even more concise shorthand for what you are doing in your example. It is most useful when you want to do a check for nil, (and if non-nil) unwrap the value and assign it, otherwise provide a default value.
var maybeSomething: Int?
var dictionary:[String:Int?] = [:]
dictionary["something"] = maybeSomething ?? nil
something! has type Int64. Not optional Int64, but Int64. nil has type nil. You can't have an expression
condition ? Int64 : nil
What would be the type of it?
And the whole thing is pointless. On the right hand side you would have just "something". If that doesn't work then your dictionary doesn't accept optionals.
PS. Noticed that your dictionary wants to store Objective-C objects. In that case, no way it accepts an optional. And it only accepts an Int64 after converting to NSNumber.

Swift: difference as String? vs. as? String [duplicate]

This question already has answers here:
Downcasting in Swift with as and as?
(3 answers)
Closed 8 years ago.
Is there a difference between as? String vs. as String? in Swift? If so, what's the difference and when should I use one vs. another?
There's a subtle but important difference:
variable as? String: variable can be any type, such as an array, an integer, etc. Cast to string if it's a string, set to nil otherwise.
variable as String?: variable is a String?, but stored in an opaque type, such as AnyObject?, or it's a non optional string. If it's something different, a runtime exception is generated.
Some examples:
var x: AnyObject? = "Test"
x as String? // OK, the result is an optional string
x as? String // OK, evaluates to an optional string
"string" as String? // OK, evaluates to optional string
x as? Int // OK, evaluates to nil, it's not an Int
x as Int? // Runtime exception, it's not castable to optional Int
So:
as? Type means: cast to this type, if possible, otherwise evaluate to nil
as Type? means: cast to an optional Type, because I know it's an optional Type. I understand that if it's not that, a runtime exception is generated
However, the real difference is between as? and as: the former is an attempt to cast, the latter is a forced cast, resulting in runtime error if not possible.
Update Dec 14, 2015 Since Swift 1.2, there are 3 variations of the as operator:
as? is an attempt to cast, evaluating to nil if cast fails
as! is a forced cast, resulting to an runtime exception if cast fails (this is what as previously did)
as is now a special type of cast to be used when casting to equivalent types, usually bridged types, such as Swift's String and NSString.
From The Swift Programming Language book,
as is a type cast operator which we use to downcast to the subclass and as? is used for an optional form, when we are not sure if the downcast will succeed. Consider the following example
for item in library {
if let movie = item as? Movie {
println("Movie: '(movie.name)', dir. (movie.director)")
} else if let song = item as? Song {
println("Song: '(song.name)', by (song.artist)")
}
}
The example starts by trying to downcast the current item as a Movie. Because item is a MediaItem instance, it’s possible that it might be a Movie; equally, it’s also possible that it might be a Song, or even just a base MediaItem.
String? An optional value either contains a value or contains nil to indicate that the value is missing.
From this,
as? String means when you don't know what you're downcasting, you are assuming that as a String, but it might me Integer or Float or Array or Dictionary
as String? means it's an Optional Value, it may either contain a String or Nil value.
Yes there is a difference.
In the first case, you are doing an optional cast to the type String. This will return a value if the object you are attempting to cast is indeed a String or nil if it is not.
In the second case, you are doing a forced cast to the type String?. If the value you are casting is not a string, it will crash your program.
YES, there is diffrence.
variable as String? downcast to optional String.If variable is not String? it will cause run-time exception.
while variable as? String will return nil if your variable is not String type or return downcast variable to String. This is conditional downcasting, if you not sure about down-casting you need to use this .

Object.ReferenceEquals returns incorrect results (in Silverlight 3 at least)

I just discovered a very strange behaviour. I have a class with a string property. In the setter of this property I compare the old value with the new value first and only change property if the values differ:
set
{
if ((object.ReferenceEquals(this.Identifier, value) != true))
{
this.Identifier = value;
this.RaisePropertyChanged("Identifier");
}
}
But this ReferenceEquals almost always returns false! Even if I call object.ReferenceEquals("test", "test") in Quick Watch I get false.
How is this possible?
That's because strings are immutable in C#:
The contents of a string object cannot
be changed after the object is
created, although the syntax makes it
appear as if you can do this.
Since you can't modify an existing string reference, there's no benefit in reusing them. The value passed to your property setter will always be a new string reference, except maybe if you do this.Identifier = this.Identifier;.
I'll try to clarify with an example:
string s = "Hello, "; // s contains a new string reference.
s += "world!"; // s now contains another string reference.

Resources