Cannot access var defined in multilayer imported file - dart

Say i got 3 dart scripts in the same folder.
// a.dart
import 'b.dart';
void main(){
print(foo);
}
// b.dart
import 'c.dart';
// c.dart
var foo = 1;
and I got Cannot resolve 'foo' in a.dart

Import doesn't automatically reexport.
You can use one of these variants:
// b.dart
import 'c.dart';
export 'c.dart';
// foo is available in b.dart and a.dart
or
// b.dart
export 'c.dart';
// foo is not available in b.dart but in a.dart
This is the same as my answer to How can I import all files in a folder? was about ;-)

A few alternate options.
Option 1
Solely use import statements and reference the actually files you need. For example:
// a.dart
import 'b.dart';
import 'c.dart';
void main(){
print(foo);
print(bar);
}
// b.dart
import 'c.dart';
var bar = foo + 1;
// c.dart
var foo = 1;
This doesn't allow for inherited imports, but if you follow this pattern throughout your app, your dependencies are very easy to see (they won't be hidden in another file).
Option 2
Don't use imports, but rather just make everything part of the same library.
// a.dart
library myLib;
part 'b.dart';
part 'c.dart';
void main(){
print(foo);
print(bar);
}
// b.dart
part of myLib;
var bar = foo + 1;
// c.dart
part of myLib;
var foo = 1;
This option works well if your application isn't too large and all your classes and global variables have unique names (that is to say you don't nee namespacing). You can also implement this pattern into a small subsection of your applicaiton rather than the whole thing.

Related

Why is it an error in Dart to try to set a static variable in the global namespace?

Why is it an error in Dart to try to set a class's static variable in the global space?
Example:
class Name {
static String? firstName;
}
Name.firstName = 'Mike'; // Error
void main() {
Name.firstName = 'Mike'; // Ok
}
It's not a big deal. I just came across this and then couldn't find an explanation for why it is. Where in the documentation does it describe the nuance here?
[UPDATE]
The actual error thrown is, among others: "Variables must be declared using the keywords 'const', 'final', 'var', or a type name."
You actually can execute statements outside of a function, but they have to be statements that declare scoped variables. Maybe these aren't technically statements, but just variable instantiations.
class Name {
static String? staticName;
String? lastName;
}
final me = Name(); // Ok
me.lastName = 'Jones'; // Error
void main() {
Name.staticName = 'Mike'; // Ok
final you = Name(); // Ok
you.lastName = 'Smith'; // Ok
}
Without the variable scoping, the compiler thinks I must be defining a function and it gets confused when there is no parameter list or function body.
It makes sense that statements are restricted to variable instantiations of function definitions only, so that there won't be side effects related to execution order to other importers of the file, as per #jamesdlin answer.
Name.firstName = 'Mike'; is a statement. You can't execute arbitrary statements in the global namespace. In what order would they execute? Suppose you had:
name.dart:
class Name {
static String? firstName;
}
and mike.dart:
import 'name.dart';
Name.firstName = 'Mike';
and spike.dart:
import 'name.dart';
Name.firstName = 'Spike';
and finally:
import 'name.dart';
import 'mike.dart';
import 'spike.dart';
void main() {
print(Name.firstName);
}
What should happen? Should it be illegal for multiple libraries to assign to Name.firstName? Should the last one imported win? If so, then suddenly importing a library would have side-effects, and order would matter. What would happen if an imported library imports other libraries with side-effects?
It's a huge headache that is completely unnecessary since you could have just done:
class Name {
static String? firstName = 'Mike';
}
in the first place.

Reflectable: myAnnotation.annotatedClasses different result CmdApp<>Client

Say I have the following Annotation and 2 classes:
class AppModel extends Reflectable {
final String name;
const AppModel([this.name])
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
#appModel
class ImGonnaBePickedUp {
}
#AppModel(' :( ')
class AndImNotPickedUpOnServer_IDoOnWebClient {
}
main() {
appModel.annotatedClasses // that's what I mean by "Picked Up".
}
On CmdApp side (Server): only AndImNotPickedUpOnServer_IDoOnWebClient is given in appModel.annotatedClasses.
On the web side, both classes are given.
Long story short, how do I retrieve classes annotated with direct const constructor calls like in the example above #AppModel(' :( ') (for both CmdApp and Web)?
since version 0.5.4 reflectable classes doesn't support constructors with arguments
This appears in reflectable documentation:
Footnotes: 1. Currently, the only setup which is supported is when the metadata object is an instance of a direct subclass of the class [Reflectable], say MyReflectable, and that subclass defines a const constructor taking zero arguments. This ensures that every subclass of Reflectable used as metadata is a singleton class, which means that the behavior of the instance can be expressed by generating code in the class. Generalizations of this setup may be supported in the future if compelling use cases come up.
one possible solution could be to use a second annotation to handle the name, for example:
import 'package:reflectable/reflectable.dart';
import 'package:drails_commons/drails_commons.dart';
class AppModel extends Reflectable {
const AppModel()
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
class TableName {
final String name;
const TableName(this.name);
}
#appModel
class ImGonnaBePickedUp {
}
#appModel
#TableName(' :( ')
class AndImNotPickedUpOnServer_WorksOnWebClient {
}
main() {
print(appModel.annotatedClasses); // that's what I mean by "Picked Up".
print(new GetValueOfAnnotation<TableName>()
.fromDeclaration(appModel.reflectType(AndImNotPickedUpOnServer_WorksOnWebClient)).name);
}
Note: I'm also using drails_common package

Reflect non-imported class

I'm trying to get the properties of a dynamic Class name (also trying to instantiate it) but the next code doesn't work because I think I need to import the dart file that has the Class code in the file where I want to reflect it:
//I import the file in other Dart file
import 'MyClass.dart'; //This only have a class named MyClass with some properties
import 'OtherClass.dart'
class mainClass {
void mainFunction () {
var properties = OtherClass.getProperties('MyClass');
}
}
Here is the OtherClass contents:
import "dart:mirrors";
class OtherClass {
static getProperties (String className) {
ClassMirror cm = reflectClass(className);
for (var m in cm.declarations.values)
print(MirrorSystem.getName(m.simpleName));
}
}
is there anyway to reflect a class that is not imported in the actual Dart file?
Hope this makes sense, thanks in advance.
You need to find the library containing the class first. Use currentMirrorSystem().libraries to get all libraries imported in your application. If you want to avoid disambiguities, add unique library declarations to your library and pass the library name to getProperties() for exact lookups.
import "dart:mirrors";
class OtherClass {
static getProperties(String className) {
var classSymbol = new Symbol(className);
var libs = currentMirrorSystem().libraries;
var foundLibs = libs.keys.where((lm) =>
libs[lm].declarations.containsKey(classSymbol) &&
libs[lm].declarations[classSymbol] is ClassMirror);
if (foundLibs.length != 1) {
throw 'None or more than one library containing "${className}" class found';
}
ClassMirror cm = libs[foundLibs.first].declarations[classSymbol];
for (var m
in cm.declarations.values) print(MirrorSystem.getName(m.simpleName));
}
}

Dart library layout

I'm struggling with Dart library layout.
I tried the following
lib/
A.dart
B.dart
my_lib.dart
where:
A.dart
class A {
B myB;
}
B.dart
class A {
B myB;
}
my_lib.dart
#library('my_lib');
#source('A.dart');
#source('B.dart');
But in A.dart, in Dart Editor there is a problem: B - no such type.
If I import B.dart in that file, via
#import('B.dart)',
but now it claims that part of library can only contain part directive.
According to http://news.dartlang.org/2012/07/draft-spec-changes-to-library-and.html
partDirective:
metadata part stringLiteral “;”
;
But that doesn't work for me either.
What am I missing?
Download the latest SDK and try:
a.dart
class A {
B myB;
}
b.dart
class B {
}
lib.dart
library mylib;
part 'a.dart';
part 'b.dart';
That should work.
Due to new release changes the layout has to look like the followed example:
a.dart
part of mylib;
class A {
B myB;
}
b.dart
part of mylib;
class B {
}
lib.dart
library mylib;
part 'a.dart';
part 'b.dart';

Reading static files under a library in Dart?

I am writing a library in Dart and I have static files under the library folder. I want to be able to read those files, but I'm not sure how to retrieve the path to it... there is not __FILE__ or $0 like in some other languages.
Update: It seems that I was not clear enough. Let this help you understand me:
test.dart
import 'foo.dart';
void main() {
print(Foo.getMyPath());
}
foo.dart
library asd;
class Foo {
static Path getMyPath() => new Path('resources/');
}
It gives me the wrong folder location. It gives me the path to test.dart + resources/, but I want the path to foo.dart + resources/.
As mentioned, you can use mirrors. Here's an example using what you wanted to achieve:
test.dart
import 'foo.dart';
void main() {
print(Foo.getMyPath());
}
foo.dart
library asd;
import 'dart:mirrors';
class Foo {
static Path getMyPath() => new Path('${currentMirrorSystem().libraries['asd'].url}/resources/');
}
It should output something like:
/Users/Kai/test/lib/resources/
There will probably be a better way to do this in a future release. I will update the answer when this is the case.
Update: You could also define a private method in the library:
/**
* Returns the path to the root of this library.
*/
_getRootPath() {
var pathString = new Path(currentMirrorSystem().libraries['LIBNAME'].url).directoryPath.toString().replaceFirst('file:///', '');
return pathString;
}
The dart mirrors API (still experimental, and not available on all platforms such as dart2js yet) exposes a url getter on the LibraryMirror. This should give you what you want.
I'm not aware of any other way to get this information on a library.
#import('dart:mirrors');
#import('package:mylib/mylib.dart');
main(){
final urlOfLib = currentMirrorSystem().libraries['myLibraryName'].url;
}
Generally the usual method of accessing resources which are located at a static position with your library is by use using a relative path.
#import('dart:io');
...
var filePath = new Path('resources/cool.txt');
var file = new File.fromPath(filePath);
// And if you really wanted, you can then get the full path
// Note: below is for example only. It is missing various
// integrity checks like error handling.
file.fullPath.then((path_str) {
print(path_str);
});
See addition API information on Path and on File
As an aside.. If you absolutely wanted to get the same type of output as __FILE__ you can do something like the following:
#import('dart:io');
...
var opts = new Options();
var path = new Path(opts.script);
var file = new File.fromPath(path);
file.fullPath().then((path_str) {
print(path_str);
});

Resources