Get type of variable at run-time without having it assigned to an instance of an object and without mirrors - dart

Is it possible to get the type of a variable in Dart at run-time, without having it assigned to an instance of an object and without using mirrors?
I know I can do this without mirrors (which is great!):
Foo foo;
foo = new Foo();
var fooType = foo.runTimeType; // This will give me a type of "Foo"
But I want to know the type of the variable before it is assigned to an object:
Foo foo;
var fooType = foo.runTimeType; // This will not give me a type of "Foo"
I am guessing it is not possible since the typing info is lost in run-time but would like to have it confirmed.
(My actual scenario is that I am doing dependency injection into a Polymer Element using Custom Events. I would like to put as much of this code as possible in an element base-class and have as little code as possible in each derived element class. One thing that I need to do this is to know the type of variables that are to be injected).

Related

The argument type 'ListOf5' can't be assigned to the parameter type 'ListOf5'

I need to implement an abstract class function, which own a an specific data type. But I need inside my logic layer to make the attribute which is going to be passed as a dynamic data type. But when i Pass it to the function, i am sure that its data type will be as needed. So, i type (product.value.pickedImages) as ListOf5) . But it does an Exception.
The Abstract Class Code Is:
Future<Either<FireStoreServerFailures, List<String>>> uploadProductImages(
{required ListOf5<File> images});
The Implementation Code Is:
Future<Option<List<String>>> _uploadImagesToFirestorage() async {
return await productRepo
.uploadProductImages(
images: (product.value.pickedImages) as ListOf5<File>) // Exception
}
The Exception Is:
The argument type 'ListOf5 < dynamic>' can't be assigned to the
parameter type 'ListOf5 < File>'.
You are trying to cast the List from List<dynamic> to List<String>.
Instead, you should cast each item, using something like this:
void main() {
List<dynamic> a = ['qwerty'];
print(List<String>.from(a));
}
Not sure about the implementation of this ListOf5 though...
The cast (product.value.pickedImages) as ListOf5<File> fails.
It fails because product.value.pickedImages is-not-a ListOf5<File>, but instead of ListOf5<dynamic> (which may or may not currently contain only File objects, but that's not what's being checked).
Unlike a language like Java, Dart retains the type arguments at run-time(it doesn't do "erasure"), so a ListOf5<dynamic> which contains only File objects is really different from a ListOf5<File> at run-time.
You need to convert the ListOf5<dynamic> to a ListOf5<File>.
How to do that depends on the type ListOf5, which I don't know.
For a normal List, the two most common options are:
(product.value.pickedImages).cast<File>(). Wraps the existing list and checks on each read that you really do read a File. It throws if you ever read a non-File from the original list. Perfectly fine if you'll only read the list once.
List<File>.of(product.value.pickedImages). Creates a new List<File> containing the values of product.value.pickedImages, and throws if any of the values are not File objects. Requires more memory (because it copies the list), but fails early in case there is a problem, and for small lists, the overhead is unlikely to be significant. If you read the resulting list many times, it'll probably be more efficient overall.
If the ListOf5 class provides similar options, you can use those. If not, you might have to build a new ListOf5 manually, casting each element of the existing ListOf5<dynamic> yourself.
(If the ListOf5 class is your own, you can choose to add such functionality to the class).

Difference between Object, Dynamic and Var in Dart?

There is a discussion about dynamic and var before null-safety. Then what's the Object? between each of them?
Is Object? == dynamic?
How about var? and dynamic??
Any difference between dynamic? and dynamic?
I see the official document about null-safety, but can't find the related topic.
dynamic is a special type that disables static type-checking. You can attempt to call any method on a dynamic type. If the object turns out not to have such a method, then it will result in a runtime failure instead of a compile-time one.
Object? is a base type suitable for referencing any object, including null. Unlike dynamic, it is statically type-checked, so you would get compile-time failures if you attempt to call most methods on it without explicitly checking the runtime type or without performing a cast.
var? is not valid syntax. var is not a type; it declares a variable without explicitly specifying a type, allowing the type to be inferred.
dynamic? is valid but is redundant. (See #3.)
Variables of type dynamic can already include null, so adding a ? to make it nullable is redundant. The Dart analyzer will tell you so.
3: About dynamic vs dynamic?: they are the same.
Since dynamic also represents nullable types, for the compiler it is the same of dynamic?.
From Why operator ==(Object other) accepts a nullable argument?:
You can also see the analyzer and runtime will call it dynamic even if we check the signature of a method declared to return dynamic?:
void main() {
print(test.runtimeType); //runtimeType of the test function: () => dynamic
}
dynamic? test() { }
In fact a hint of the dart linter reports as 'unnecessary' the use of ? in dynamic? (as in Null?):
The '?' is unnecessary because 'dynamic' is nullable without it. (unnecessary_question_mark).
Personally, I don't understand why dynamic? Is only reported by a hint (which many people, myself included, don't notice) keeping it valid as a syntax.
1: A variable declared with Object? type behaves like all other normal variables whose type is specified, such as String? etc. Since every class -apart Null (the type of null)- is a subclass of Object (and since in Dart there are no primitive values as opposed to objects, unlike in Java; in Dart also null, int and bool are objects. But forget this clarification, if you don't know Java), a variable declared with Object? can contain any value. But the compiler will only allow access -after a null check- to the properties of Object (toString(), ==(), runtimeType, etc).
A variable declared with dynamic (or dynamic?, see point 3) instead allows access to any public member: the compiler will not perform any checks (unless the property begins with an underscore _, because in that case it is clear that it is not public); if you try to access a non-existent member you will instead have an error at runtime Note1. Furthermore, with dynamic we also renounce null safety: dynamic is equivalent to dynamic? (in practice the question mark can be considered implicit, it is as if it were always there).
2: using var, or final -if you want an immutable reference- without declare the type, the compiler check the value assigned to the variable (in fact the omission of the type is not allowed if the variable is not initialized immediately) and treats the variable as if it were declared with that type.
dynamic at runtime:
One use of 'dynamic' that can lead to confusion is with generic classes, because dynamic as parametric type exists also at runtime:
with
dynamic obj = true;
obj at runtime has bool type, but with
List list = [bool];
list at runtime has List<dynamic> type.
However, using
var list2 = [true];
the parametric type is inferred correctly (list2 has List<bool> runtimeType).
Note1 More precisely, a invocation such as myDynamicVariable.nonexistentMember cause an invocation of the noSuchMethod() method on the object; noSuchMethod() can also be overridden and not throw any exception; but this is a rare practice, in Dart 2).

Error: The instance member ... can't be accessed in an initializer

Why does this code:
class _SequentialTextPageState {
String jsonTextPref = 'seqtext';
int jsonTextSuff = 10;
String jsonText = jsonTextPref + jsonTextSuff.toString();
}
generate these errors?
Error: The instance member 'jsonTextPref' can't be accessed in an initializer.
Error: The instance member 'jsonTextSuff' can't be accessed in an initializer.
It seems to me that concatenation between String and int is correct?
Dart initializes objects in multiple phases. Initializing members directly ("field initializers") occurs early in object initialization, before this becomes valid, so that phase cannot initialize members that depend on other parts of the object.
Dart provides multiple ways to initialize members, so if one member needs to depend on another, you can initialize it in a later phase by using a different mechanism. For example, you could do one of:
Add the late keyword to make the dependent member lazily initialized.
Move initialization of the dependent member into the constructor body.
In the case of a Flutter State subtype, you could initialize the dependent member in its initState method, which in some cases is more appropriate.
Note that in some cases you additionally can consider replacing the member variable with a read-only getter instead. For example, in your case, perhaps you could use:
String get jsonText => jsonTextPref + jsonTextSuff.toString();
That would be appropriate if jsonText should always depend on jsonTextPref and jsonTextSuff, would never need to have an independent value, and if it's acceptable for jsonText to return a new object every time it's accessed.
Dart does not allow field initializers to refer to the object itself. Fields must always be fully initialized before any access is given to the object begin created.
The initializers can only access static and top-level variables, not any instance variables on the object itself.
With null safety, you will be allowed to write late String jsonText = this.something + this.other;. That field will then not be initialized until it's first read or written, which is necessarily after the object itself has been created.
You can only use constant expressions as initializers. x=this.y is not constant.
The error was displayed when I did following:
class MyClass {
String id;
String[] imagePaths;
}
It will mark the String in the line String id; as error, but the error is in the next line, it should be List<String> imagePaths; instead of String[] imagePaths; then the error in the line above also disappears. This can be very confusing if you have a big class and the actual error is many lines underneath the first marked line (talking from experience...)

If a set literal is of type set then what is its class in dart?

So the following code snippet
Set mySet = {1,2,3};
is an instance of type Set which is permissible, however what would the class of the set literal be. I have tried to search for this, however I have found no answer in the dart documentation.
A literal exists only in your source code. Asking for its "class" doesn't make a lot of sense.
Using a Set, Map, or List literal is just syntactic sugar for invoking a corresponding constructor. The Set factory constructor constructs a LinkedHashSet.
However, you'll see that LinkedHashSet is also abstract. Its factory constructor returns an instance of a private, internal class. You can see its typename via print(Set().runtimeType); the actual type might be different for different platforms and is unlikely to be useful to you.

Create new instance of certain user type

I'm using tolua++ to automatically expose C++ types to Lua. It seems that when I expose some type, e.g.
struct TestComponent
{
float foo;
string bar;
}
What tolua does (at least this is what it seems like to me) is add a new metatable to the lua environment (in this case it would just be called TestComponent) with some regular metamethods such as __add, __lt, as well as __index, __newindex, etc. It also has some custom functions (called .set and .get) which seem to be used when you get or set certain members of the struct/class. The type of TestComponent here seems to be just "table".
However, what it seems to lack, for simple structure definitions like above, are functions/methods to create a new instance of the type TestComponent, e.g.
a = TestComponent:new()
The question, then, is, how do I create a new instance of this type and assign it to a variable? For example, to hand it to a function that expects an argument of type TestComponent.
It's been a few years since I used tolua++, but based on the docs it appears that if your struct had a constructor, then you could create the object with a = TestComponent() or a = TestComponent:new() (both should work, unless you have an older version of tolua++). Without a constructor in the C++ struct, the docs don't say, but based on what you state, it seems like the TestComponent becomes a regular table object with the given fields and associated values, in which case it does not make sense to have a constructor (the table is the object, you can't create multiple instances of it).
So if you can edit the C++ header of the struct to add a constructor to it, it'll probably work. If you can't do that, then you could define a constructor yourself (note: not tested):
function TestComponent:new()
local obj = {}
for k,v in pairs(self) do
obj[k] = v
setmetatable(obj, self)
return obj
end
You might have to filter the keys so you only get values (not functions, for example), or replace the loop with explicit assignments such as:
function TestComponent:new()
local obj = {}
obj.foo = self.foo
obj.bar = self.bar
setmetatable(obj, self)
return obj
end

Resources