I have a method callback
var _onFinished = void Function(bool wasUser);
I now want to assign a lambda to onFinished:
_onFinished = (wasUser) => print('wasUser $wasUser');
The problem is that i get a compile error:
A value of type 'void Function(bool)' can't be assigned to a variable of type 'void Function({wasUser: bool})'.
Try changing the type of the variable, or casting the right-hand type to 'void Function({wasUser: bool})'.
I can't find any doco on what the method signature should be for a lambda that takes a named parameter.
Related
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
I want to send a Function as a parameter to an annotation like this:
#JsonKey(fromJson: ...)
final int variable;
where fromJson is a Function, but it gives me this error:
Arguments of a constant creation must be constant expressions.
what is the solution? any help would be greatly appreciated.
You didn't write what you wanted for ..., and that's the part that causes the problem.
The argument to the fromJson parameter must be a compile-time constant value because annotations must be constant.
The only constant function values are top-level or static functions, so you need to declare the function type want, let's say as static:
class MyClass {
#JsonKey(fromJson: _variableFromJson)
final int variable;
static int _variableFromjson(dynamic json) => ...;
...
}
You can't write the function in-line as (fromJson: (json) => ...) because function expressions are not compile-time constant.
I have a map structured like so:
Map<dynamic, dynamic> optionsMap = {1: true, 2: false, ..., "totalCount": 1};
I explicitly declared the values as dynamic to avoid Dart's intelligent typing, even though it should handle this and make it dynamic.
I'm going to map it to provide a Map with the ending structure:
{1:{index1Name:index1Value}, 2:{index2Name:index2Value}...}
When trying to map this Map, using
Map optionsMap = optionsState.map(
(dynamic key, dynamic value) => MapEntry(key, [options[key], value]));
I get the following error:
type 'String' is not a subtype of type 'int'
I never strong typed an int. Why do I get this error?
What's the type of the options variable? If it is a list, the error may be caused by MapEntry(key, [options[key], value]) within the map function running at
options['totalCount']
In the following code I define two interfaces, the second of which takes the first as a type parameter. However the code gives the error "type parameter 'a' is not defined".
type IFirst<'a> =
abstract Data : 'a
type ISecond<'First when 'First :> IFirst<'a>> =
abstract First : 'First
abstract SomeData : 'a
My question is why can't f# infer what type 'a' is when ISecond is derived, since the information is embedded in 'First'?
For example in the following code the compiler could infer that 'a' is a string.
type First () =
interface IFirst<string> with
member x.Data = ""
type Second () =
interface ISecond<First> with
member x.SomeData = ""
member x.First = First()
Is there any way around this or does ISecond have to take two type parameters?
EDIT: I Am aware that ISecond can take two type parameters (note the last line of my initial question). To make it clearer what I mean consider the following code
type IFirst<'a> = interface end
type ISecond<'First, 'a when 'First :> IFirst<'a>> = interface end
type First () =
interface IFirst<string>
type Second () =
interface ISecond<First, int>
It gives the error "This expression was expected to have type string but here has type int", meaning the compiler knows that 'a' is a string, yet I still have to declare it as such. I wish to know why this is the case and whether there is a workaround without specifying the second type parameter.
Your definition of ISecond is incorrect: you're mentioning some type 'a, but not defining it. In other words, ISecond actually has two generic parameters - 'First and 'a, but you've only defined one of them.
This would work:
type ISecond<'a, 'First when 'First :> IFirst<'a>> =
abstract First : 'First
abstract SomeData : 'a
But then, of course, you'll need to amend your definition of Second as well:
type Second () =
interface ISecond<string, First> with
member x.SomeData = ""
member x.First = First()
I think you have conflated two different questions. One is:
Do a type definition's generic parameters all need to be explicit?
The answer is yes. This has nothing to do with type inference, it's just how type definitions work in F# - the type parameter 'a will only be in scope to be used as an argument to IFirst<_> if it's also a parameter of ISecond.
The other question is:
Can the compiler infer a super-type's type parameters when defining a subtype?
Here, the answer is slightly more subtle. When defining a class type, the answer is that it is a syntactic requirement that you specify all of the type parameters. If you try something like:
type Second() = interface ISecond<First,_> with ...
you'll get the error message
error FS0715: Anonymous type variables are not permitted in this declaration
However, there are other contexts where the parameters can be inferred without issue:
let second() = { new ISecond<_,_> with
member x.SomeData = ""
member x.First = First() }
Here you can see that when using an object expression both of the parameters can be inferred.
I want to create a dictionary of type against instance in Delphi.
If I declare the following:
m_things: TDictionary<TClass, TThing>;
that gets me dictionary of any type against an instance of TThing. How do I restrict the type to be an instance of TThing or derived classes? I'd like to do:
m_things: TDictionary<class of TThing, TThing>;
but I get the following error:
[dcc32 Error] collector.pas(13): E2058 Class, interface and object types only allowed in type section
I also tried:
m_abstract: TDictionary<T: TThing, TThing>;
but then I get this error:
[dcc32 Error] collector.pas(13): E2003 Undeclared identifier: 'T'
I'm not clear if this is possible, and what the syntax might be.
You need to declare a type to represent the metaclass using the class of syntax. Like this:
type
TThingClass = class of TThing;
....
var
m_things: TDictionary<TThingClass, TThing>;