-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add "Safe" (nullable) cast operator as?
#399
Comments
Thanks for filing an issue - just a head up, this issue tracker is for issues with the website. Language feature requests can be filed at https://github.com/dart-lang/language |
Ahh, you're right, sorry ;) |
Moved to the language repo! |
I like this. I was honestly just about to file a request for the exact same thing (thanks to GitHub for listing relevant existing issues!) Another practical use case would be; int x = o as? int ?? 0; // Could perhaps use some parentheses for readability :) This is the safe cast operator that was originally requested when the current |
I like it, too! I missed this when I came from C#
|
Definitely something I miss from Kotlin. Would be great timing to have this implemented this alongside the upcoming null safety. |
Any progress about this issue? I'm from Swift and suffered exceptions when casting from time to time. |
We could also consider this to be a proposal to have a few extensions in a conveniently accessible library: extension AsExtension on Object? {
X as<X>() => this as X;
X? asOrNull<X>() {
var self = this;
return self is X ? self : null;
}
}
extension AsSubtypeExtension<X> on X {
Y asSubtype<Y extends X>() => this as Y;
}
extension AsNotNullExtension<X> on X? {
X asNotNull() => this as X;
}
void main() {
num? n = 1 as dynamic;
n.as<int>().isEven;
n.asSubtype<int>().isEven; // `n.asSubtype<String>()` is an error.
n.asNotNull().floor();
n.asOrNull<int>()?.isEven; // Corresponds to `(n as? int)?.isEven`.
} |
hey @eernstg EDIT: This question is answered here: #399 (comment) One question for the awesome extension you posted, why is it not possible to get it to work with For example: import 'package:my_flutter_project/src/app/utils/type_utils.dart';
class SomeClass {
/// This does NOT work.
/// `as` or any other method within the extensions imported are not recognized!
/// The import statement is marked as unused as well.
void testCastingDynamicObject() {
const dynamic someNumber = 1;
final someInt = someNumber.as<int>();
print(someInt);
}
/// This works!
void testCastingNormalObject() {
// const num someNumber = 5;
// final someInt = someNumber.as<int>();
// print(someInt);
}
/// This works also!
void testCastingDynamicObjectWithPrecast() {
// const dynamic someNumber = 1;
// const Object someNumberObject = someNumber as Object;
// final someInt = someNumberObject.as<int>();
// print(someInt);
}
}
|
@om-ha, I believe it's because the extensions are declared on |
Very insightful, thank you @Levi-Lesches. I presumed |
I think I'll add a little bit more detail. There are actually some situations where the static type of an expression could be any type whatsoever, and we're still going to invoke an extension method extension E on Object? {
void foo() => print('Running E.foo!');
}
void f<X>(X x) {
x.foo();
}
main() => f<num>(2); // 'Running E.foo!'. So the fact that we don't run extension methods on receivers of type
An extension method is only applicable in the case where the static type of the receiver does not have a member with that name (technically: with that 'basename', which is needed in order to include setters), and this means that we will simply never call an extension method on a receiver of static type |
Thank you @eernstg for the awesome explanation! |
Other use case: [ for (final key in keys) box.get(key) as? Item ] |
No but let's say I wanted null if key not in box (to later take action on null elements from the list) |
// The list type is List<Item?>
[ for (final key in keys) box.get(key) as? Item ] @gruvw The code above may add null to the list. Why not check it like below and keep the code null-safe? // The list type is List<Item>
[ for (final key in keys) if (box.get(key) is Item) key ] EDIT: Forgot to write the variable name after the loop You may write less characters now, but in the future you will need to check if the element is not null for each list element. for (final element in list) {
if (element != null) { ... }
} In the end you will lose null-safely, write more code and have a worse performance. |
If we had null aware elements (#323), then [for (var key in keys) ?(box.get(key) as? Item)] would work well. keys.map(box.get).whereType<Item>().toList() already works. The alternative needs an object after the [ for (final key in keys) if (box.get(key) is Item) box.get(key) as Item] or it needs away to introduce a local variable. Say we had [for (final key in keys) let value = box.get(key) in if (value is Item) value] Still, nothing beats the brevity of the first version. Edit: We now allow patterns in collection [ for (final key in keys) if (box.get(key) case Item item) item) ] Still not as short as the first version, but also more generally applicable. We can implement extension AsQ<T> on T {
R? tryAs<R>() {
var self = this;
return self is R ? self : null;
} That's longer than So it's not because the functionality cannot exist, just that |
Any chance this will be added to Dart? Super handy. atm we just use something like |
@seanhamstra May I ask what is the complete function/method body? |
With patterns, you should be able to do switch (value) {case SomeClass x => x, _ => null} instead. Not much of a saving in size, but you don't need to repeat the With #2664 it would be |
It'll be a little enhancement but so much pleasant one :)
Kotlin and Swift has something like Safe casting with
as?
operator. It gives an opportunity to casting withnull
fallback if cast can't be performed:The text was updated successfully, but these errors were encountered: