Dart: A value of type 'int' can't be assigned to a variable of type 'int' [duplicate] - dart

This question already has answers here:
The argument type 'String' can't be assigned to the parameter type 'String'
(3 answers)
Closed 1 year ago.
When I write an extension like so:
extension MyExtension<int> on List<int> {
void myMethod() {
int a = 1; // error
}
}
I get a seemingly nonsensical error message from the compiler:
A value of type 'int' can't be assigned to a variable of type 'int'.
Try changing the type of the variable, or casting the right-hand type to 'int'. dart(invalid_assignment)
I can fix the problem by removing <int> after the extension name:
extension MyExtension on List<int> {
void myMethod() {
int a = 1;
}
}
But I'd like to know what was going on in the original problematic code. What was the reason for the cryptic error message?

So you are having a simple problem, you are reassigning the meaning of int
extension MyExtension<int> on List<int>
Your extension takes a type argument, which means that when using the extension, you can pass many different types to it, but the name of this new type argument is int.
So you are assigning an int (the number) to int (the type argument) which is impossible because dart does not know if int (the type argument) will be an int.
In order to fix this, you can remove the type argument as you did, the code you show does not need a type argument, you can also rename the type argument, the convention says type arguments should be called T:
extension MyExtension<T> on List<int> ...
if what you want is for the type argument to always be an int, or a class that extends int you can also declare that:
extension MyExtension<T extends int> on List<int> ...
If you still have trouble understanding what type arguments are and how they work, here is the documentation for type arguments and here is the documentation for extensions with type arguments

Related

dart lambda type inference

void main() {
print(doStuff.runtimeType);
print(((e) => doStuff(e)).runtimeType);
}
int doStuff(String hallo) {
return 42;
}
executed in the dartpad yields
(String) => int
(dynamic) => int
I would expect both to have the same type. Can somebody explain why dart fails to infer the type of the argument e?
Dart type inference is limited in some ways that inference in purely functional languages is not.
It's not constraint solving based.
So, when the compiler sees (e) => doStuff(e), it checks whether there is a context type from which it can deduce the parameter type.
There isn't (being the receiver of .runtimeType provides no hint). So, it infers dynamic for the parameter, which needs a type before the body of the function can be type analyzed at all.
Then it looks at the body and sees that doStuff(e) is valid and has type int, so that becomes the return type.

Get type of Key and Value from a Map variable?

Given a Map variable, how can I determine the type of Key and Value from it?
For example:
void doSomething(Map m){
print('m: ${m.runtimeType}');
print('keys: ${m.keys.runtimeType}');
print('values: ${m.values.runtimeType}');
print('entries: ${m.entries.runtimeType}');
}
void main() async {
Map<String, int> m = {};
doSomething(m);
}
This will print
m: _InternalLinkedHashMap<String, int>
keys: _CompactIterable<String>
values: _CompactIterable<int>
entries: MappedIterable<String, MapEntry<String, int>>
But how can I get the actual type of Key and Value (i.e. String and int), so that I can use them in type checking code (i.e. if( KeyType == String ))?
You cannot extract the type parameters of a class if it doesn't provide them to you, and Map does not.
An example of a class which does provide them is something like:
class Example<T> {
Type get type => T;
R withType<R>(R Function<X>() callback) => callback<T>();
}
If you have an instance of Example, you can get to the type parameter, either as a Type (which is generally useless), or as a type argument which allows you to do anything with the type.
Alas, providing access to types variables that way is very rare in most classes.
You can possibly use reflection if you have access to dart:mirrors, but most code does not (it doesn't work with ahead-of-time compilation, which includes all web code, or in Flutter programs).
You can try to guess the type by trying types that you know (like map is Map<dynamic, num>, then map is Map<dynamic, int> and map is Map<dynamic, Never>. If the first two are true, and the last one is false, then the value type is definitely int. That only works if you know all the possible types.
It does work particularly well for platform types like int and String because you know for certain that their only subtype is Never.
If you can depend on the static type instead of the runtime type, you could use a generic function:
Type mapKeyType<K, V>(Map<K, V> map) => K;
Otherwise you would need to have a non-empty Map and inspect the runtime types of the actual elements.

In Dart, given the nullable type `T?`, how do I get the non-nullable one `T`

Given some nullable type T?, how do I get the corresponding non-nullable one T ?
For example:
T? x<T extends int?>(T? value) => value;
Type g<T>(T Function(T) t) => T;
Type type = g(x);
print(type); // Prints "int?"
Now I want to get the non-nullable type. How do I create the function convert so that:
Type nonNullableType = convert(type);
print(nonNullableType); // Prints "int"
If you have an instance of T?, and you're trying to do something where the expected type is T, you can use use T! wherever dart is showing an error. It is not exactly a conversion from T? to T, its just a shortcut to do a null check.
In general, you do not. There is no simple way to strip the ? of a type, or destructure types in other ways. (You also can't find the T of type you know is a List<T> at run--time)
If you have the type as a Type object, you can do nothing with it. Using Type object is almost never what you need.
If you have the type as a type parameter, then the type system don't actually know whether it's nullable. Example:
void foo<T>() { ... here T can be nullable or non-nullable ... }
Even if you test null is T to check that the type is actually nullable, the type system doesn't get any smarter, that's not one of the tests that it can derive type information from.
The only types you can improve on are variable types (or rather, the type of a single value currently stored in a variable). So, if you have T x = ...; and you do if (x != null) { ... x is not null here }, you can promote the variable to T&Object, but that's only an intermediate type to allow you to call members on the variable, it's not a real type that you can capture as a type variable or a variable type. It won't help you.
All in all, it can't be done. When you have the nullable type, it's too late, you need to capture it before adding the ?.
What problem are you actually trying to solve?
If you have an instance of T?, I think you could do:
Type nonNullableTypeOf<T>(T? object) => T;
void main() {
int x = 42;
int? y;
print(nonNullableTypeOf(x)); // Prints: int
print(nonNullableTypeOf(y)); // Prints: int
}
If you have only T? itself (the Type object), then I'm not confident that there's much you can do since what you can do with Type objects is very limited. (And given those limitations, it's not clear that nonNullableTypeOf ultimately would be very useful either.)
A related question: How do I check whether a generic type is nullable in Dart NNBD?

Dart 2.7 migration for typedef with Null type parameter

I'm trying to migrate some old dart 1.25 code to 2.7 on windows.
I face some errors and I don't understand how to fix these.
The code used some Null type parameters in a typedef like this :
typedef dynamic PropertyGetter(Null object);
I don't understand exactly why this was coded like this, but it worked on 1.25.
This typedef was use to get a property on an any passed type of object which may be Null I suppose.
I also suppose the Null type parameter had his own reason to be there.
But now, with dart 2.7, when executing the code I've got errors like this :
type 'XXXType' is not a subtype of type 'Null'
Any idea how the typedef code can be fixed ?
--- Edit 1 ---
Here is a test case to experiment with the problem :
typedef int PropertyGetter(Null object);
void main() {
testTypedef(test1, 2);
testTypedef(test2, 'foo');
}
void testTypedef(PropertyGetter pg, param){
pg(param);
}
int test1(int val) {
print('val:$val');
return val;
}
int test2(String val) {
print('val:$val');
return 0;
}
console error message :
Unhandled exception:
type 'int' is not a subtype of type 'Null'
You almost certainly don't want to be using Null as a type here as a parameter of type Null can only accept null as an argument which is pretty useless.
If you're looking to define a typedef for a function that can take in any object, you should either use dynamic or Object as the type. However, if you use Object, you'll need to know what type to cast the object to before you can access any properties of the underlying object. I'd recommend using dynamic if you're just looking for a quick fix.

outputting a value to a typedef pointer in swift

I'm almost certain the title of this isn't correct but here goes...
I'm bridging to an Objective-C class to set a typedef. The bridge is set up and I'm able to declare the typedef var correctly.
In Objective-C I also called a method from the same class that, when called, output a value to the variable TestHandle.
var TestHandle : TESTHANDLE
TestInit(&TestHandle)
When I try this using Swift 5 I get this error:
Cannot convert value of type 'inout TESTHANDLE' (aka 'inout UnsafeMutableRawPointer') to expected argument type 'UnsafeMutablePointer<TESTHANDLE?>?' (aka 'Optional<UnsafeMutablePointer<Optional<UnsafeMutableRawPointer>>>')
Any pointers?
Some observations:
TESTHANDLE appears to be an alias for UnsafeMutableRawPointer
&testHandle is taking a reference (a pointer to the location) of the testHandle, producing a value of type inout UnsafeMutableRawPointer
As the error says, your TestInit function takes a variable of type UnsafeMutablePointer<TESTHANDLE?>?, a.k.a. Optional<UnsafeMutablePointer<Optional<UnsafeMutableRawPointer>>>
Swift has some rules about how & automatically bridges to the various pointer types, but to be frank, I don't understand them very well.
As far as I know, the Swift pointer types cannot represent nil (0x000...000). To do that, they need to be wrapped within an optional. So when you see the type
Optional<UnsafeMutablePointer<Optional<UnsafeMutableRawPointer>>>
It's actually two "semantic" parts:
Optional<UnsafeMutablePointer< Optional<UnsafeMutableRawPointer> >>
↳ A nullable pointer to ... ↳ ... something that's a nullable pointer of unspecified (void) type
The reason you're getting your error is because &testHandle can only bridge your UnsafeMutableRawPointer to a Optional<UnsafeMutablePointer<UnsafeMutableRawPointer>>, but not the required Optional<UnsafeMutablePointer<Optional<UnsafeMutableRawPointer>>> (the difference is in that missing layer of "inner" nullability). To get around this, make your testHandle optional, yourself:
var testHandle: TESTHANDLE? // a.k.a. Optional<TESTHANDLE>, a.k.a. Optional< UnsafeMutableRawPointer>
Then, when you use the & operator, Swift will wrap your value in the required Optional<UnsafeMutablePointer< ... >> outter layer.
typealias TESTHANDLE = UnsafeMutableRawPointer
func testInit(_ p: UnsafeMutablePointer<TESTHANDLE?>?) {
print("Success!")
}
var testHandle: TESTHANDLE? = nil
testInit(&testHandle)

Resources