Why Is the "library" line needed for Dart? - dart

For a library file (say foo.dart), you start it with a line like this:
library my_foo_lib;
Why is it needed? The import is based on file name (foo.dart), not library string (my_foo_lib):
import 'package:foo.dart';
Having to declare library seems redundant and error-prone. Is there a good reason behind it?

You can omit the library statement then it is an implicitly named library with an empty string as name but when you import a library you need to name it explicitly otherwise you get an error that you have several libraries with the same name.
Identifiers starting with an _ (underline) are private. Privacy in Dart is per library.
The part of references the library name.
When you use reflection to look up classes or functions you include the library name. This way you can differentiate classes with the same name in different libraries.
Dart Programming Language Specification (17 Libraries and Scripts) also says
"The name may be relevant for further language evolution."

Related

Does dart allows users to write platform specific implementation?

If not - are there are any plans to make it so?
I know that dart itself has different backends that might have different implementation. I was curious if users can do the same, e.g. have a function that delegates to one #patch for js runtime and to another #patch in case of dart vm.
If you're creating a package, you can export different implementations for different platforms, see here: https://dart.dev/guides/libraries/create-library-packages#conditionally-importing-and-exporting-library-files
The way to make platform specific code (or rather platform library specific code) is to use conditional imports.
The syntax is:
import "helper_default.dart"
if (dart.library.js) "helper_js.dart"
if (dart.library.io) "helper_io.dart";
This import statement will import one of three libraries. If the dart:js library is available on the platform you are compiling for, you will import helper_js.dart. If not, and dart:io is available, then you will import helper_io.dart. If that's also not there, you will import helper_default.dart.
The trick is then to have the same library API implemented in all three libraries, but based only on the available platform library.
The helper_js.dart library can implement something using dart:js and helper_io.dart can import dart:io. The default library will likely not be able to do anything useful, so it might just throw an UnsupportedError if you try to use it.
The code in the importing library must be valid for all three imports, which is why they must have "the same" API. That might include declaring a class, but you'd usually define the interface of that class in a non-platform dependent library that the three implementations can share, to ensure that they actually have the same interface.
Example:
library mypkg.shared_types;
import "helper_default.dart"
if (dart.library.js) "helper_js.dart"
if (dart.library.io) "helper_io.dart"
as helper;
class SharedClass {
factory SharedClass(int something) = helper.SharedClassImpl;
int get value;
}
and
library mypkg.helper_io;
import "dart:io";
import "shared_types.dart";
class SharedClassImpl implements SharedClass {
int _id;
SharedClassImpl(this._id);
int get value { // Something depending on dart:io.
var bytes = File("pathToSomething-$id").readAsBytesSync();
return bytes[0];
}
}

How to access private (underscore) identifiers in the same library but in a different file

According to dart.dev, "If an identifier starts with an underscore (_), it’s private to its library.". This should mean that separate files using the same library directive should be able to see private identifiers in the other ones, right? For instance:
other.dart:
library mylib;
const _foo = 42;
main.dart:
library mylib;
import 'other.dart';
void main() {
print(_foo); // Error: Getter not found: '_foo'.
}
What am I doing or understanding wrong here?
Although this is not a duplicate of Dart and underscores as suggested, that question itself (rather than one of its answers) did include a clue for answering this one. You need to use the part/part of directives to accomplish what I was trying to do. dart.dev mentions them but seems so determined to discourage their use that it refuses to even begin to explain how they work, so see dart import and part of directives in same file for a brief explanation.

Can a struct file have any name (in this case)?

While a class usually has the same name as it's contained class - how about the filename of a struct? The below example actually works.
File names and files themselves are completely arbitrary. You can put multiple object type declarations in one file, and they need have nothing to do with the name of the file. (You can also spread out an object type declaration over multiple files, thanks to extensions.) And the names of those types are unrelated to the name of the file.
The reason for giving a file a name that has something to do with its contents is so that you can find those contents; it does not affect the behavior or compilation of the program in any way.
Okay, exceptions:
In Swift, only main.swift has special behavior based on its name - and you don't have a main.swift.
Privacy in Swift is file-based, so you want to separate object type declarations that need to keep things private from each other into separate files.
They usually do but in Swift you honestly can call any file anything you want. I have many different files with not directly related names, some with one class, some with multiple, some with just structs, some with class(es) and structs. The new class function in Xcode will give it a specific name but that was never necessary.

Warning that 'imported libraries have the same name when they DO NOT"

I have the following import statements in a class
import 'package:dart_web_toolkit/ui.dart';
import '../../util/flex_table_builder.dart' as ftBldr;
import '../factors_list_view.dart';
class MediatingFactorsView extends Composite
{
//...
}
However, the last import statment is flagged with a warning:
The different imported libraries 'flex_table_builder.dart' and 'factors_list_view.dart' should not have the same name
The names are quite different and I see this being repeated throughout my code after I updated to the latest Dart Editor. Is this a bug?
Make sure that you are assigning library names to each file. The first line of the file should be:
library foo;
You should use different names for each library that you use. The library name is specified by the library directive, but anonymous libraries are treated as having the same name, which is where the warning comes from.
It is a warning in the Dart specification to import two libraries with the same name.
You can read more about how to use libraries here in the language tour.
You could follow the Package layout conventions.
For the error :
The different imported libraries onset_view.dart and duration_view.dart should not have the same name
you should define distinct library names in each imported dart file.
One additionnal note, you should use import 'package:epimss/shared.dart'; instead of import 'packages/epimss/shared.dart'; and import 'site_view.dart'; instead of import './site_view.dart';
The warnings correctly indicate there is a problem.
The correct solution depends on if the Dart files are conceptually separate from each other or are related.
Different libraries
If they are conceptually separate, then they should be defined as belong to different libraries with different library names.
The import command is used to reference a compilation unit from a different library, not a compilation unit that belongs to the same library. It expects every library to have a unique library name.
If a Dart file is treated as a library (i.e. is the subject of an import statement) and is not explicitly named then its implicit name is the empty string. In this case, both files are treated as libraries, and it is complaining about there being two libraries with the same name (of an empty string).
For this to work as separate libraries, given them different names:
Top file:
import 'foo.dart';
import 'bar.dart';
foo.dart:
library foo;
bar.dart:
library bar;
Part of the same library
But if they related they should not be referenced as libraries. That is, do not use the import command. Use the part command, which treats the Dart file as compilation unit that belongs to the same library.
Top file:
library baz;
part 'foo.dart';
part 'bar.dart';
foo.dart:
part of baz;
bar.dart:
part of baz;
Only the top library file can contain the part statements. You do not need (and cannot have) part statements inside the other files, even if they reference definitions from each other. If there are multiple files, just list them all in the top library file (in any order).
Although the implicit name for a library is the empty string, there is no way to use that when there are multiple parts involved: so even if these files are never going to be imported as a library, you will still need to explicitly assign it a library name.
Always remember: import and part statements are very different from the #include macro in the C preprocessor.

How can I get a list of classes defined in my project at run time?

I want to load all classes from a current project in a TList. If I read the dpr file like a normal file it will return me only strings. I want to get all the classes defined in the dpr file and their names. Does someone know how to do that?
In the Delphi IDE, all classes are available in the .dcu files, corresponding to each .pas files. Those .dcu files have a proprietary binary evolving format, so can not be used outside the IDE.
At program execution, and within the exe file, there is no list of all existing classes. You can retrieve information about a known class using the RTTI functions (see TypInfo.pas and relatives as stated by the Embarcadero documentation). So at runtime, you just can retrieve information from a given class: you can use e.g. anObject.ClassName or anObject.ClassType methods.
But I suspect you want to retrieve all classes defined in a project, from its source code. For this, you will need a source code parser, which will extract the logic from the .pas files. In short, the parser will read the .dpr then all necessary .pas files source code, interpret the object pascal type definitions, and create a list of units, classes, methods and properties. There are several parsers around: see for instance PasDoc or the version we embedded in SynProject.
Additional note - for an exhaustive list: If you generate a .map file during the compilation, this text file will contain all symbol names of the executable, including the classes. You'll have to parse it, but won't have much information to deal with, since there is no easy way of guessing if each symbol is a class or a record, for instance, or about classes inheritances or properties... This .map is intended about execution debugging, not RTTI.

Resources