Dart - Need explanation of library/part and import/export - dart

Yes, I read dart import and part of directives in same file
I have this structure:
lib/
src/
one/
SomeClass.dart
one.dart
mylib.dart
main.dart
I'm trying to achieve this behavior:
All public and hidden variables are fully accessible inside library.
All public variables from library are accessible to main.dart.
There is a problem. For some weird reason I can't use any directive with 'part of'. So I can't use this in the one.dart:
part of mylib;
import 'SomeClass.dart';
//somecode
So I either need to move class definition from SomeClass.dart to one.dart (and that will make code less readable and mixed up) or I need to move 'import' in the mylib.dart.
library mylib;
import 'SomeClass.dart';
part ..
I don't like either of the options. In the second case I will need to parse all modules then and move import/exports. Which will definitely break something.
It may sound weird but the project will build from various modules automatically. And one/ is one of them.
This app design is bad, I know. But either I need to find a better way or just make all variables public and don't bother.

Default to defining one type per file, not using part, and importing only the files you need. This covers the majority of use cases.
Now, let's say you have two types that are commonly used together - for example, a Thing and a ThingException that gets thrown when Thing does bad things. Importing both of these files everywhere is tedious, so you have three options with their own tradeoffs:
Declare both types in the same file.
Declare each type in its own file, and have the 'primary' file export the other. So, thing.dart exports thing_exception.dart. Importing thing.dart gives the importing file access to both.
Declare each type in its own file, and have the other file be a 'part of' the primary file. So, thing_exception.dart declares that it is 'part of' thing.dart. Importing thing.dart gives the importing file access to both files.
For this simple type and its exception, your best bet is to use option 1. When the amount of code grows or the two types diverge in visibility, this option becomes less attractive. This puts options 2 and 3 are on the table.
When you have separate files, option 2 is often a better approach than options 3 because you maintain some flexibility - you could only import thing_exception.dart and not thing.dart. If you use option 3, you can't do this - you either import all of the parts or none of them. This is the error you are seeing when trying to do a part and import in the same file.
Option 3 becomes valuable when you the code is in the two files is highly dependent on one another and they need the ability to access private members of each other. This is less common.
When you have a bunch of files like this together, it becomes a 'library' in the more traditional sense. You declare a main library file (your my lib.dart file) that exports files:
export 'public.dart';
export 'other_public.dart';
The bin script imports the library as a whole, but it can't see anything that isn't explicitly exported from my_lib.dart.
import 'package:mylib/mylib.dart';
Here's an example of a smallish package that uses all three of these options together for a good reference.

I think you will have better luck using import, and export with show. (Use of part of is now discouraged.)
Answers to this question may help you: When to use part/part of versus import/export in Dart?
Also the Creating library packages documentation: https://www.dartlang.org/guides/libraries/create-library-packages

Related

correct way to import mydart.dart file in main

In my dart project projectxyz, I have a dart class declared in in myclass.dart. In main.dart, Android Studio gives two ways, both work, but I did not understand what are the pros and cons of each method:
import 'myclass.dart';
or:
import 'package:projectxyz/myclass.dart';
What is the difference in these two approaches?
That depends on how the main file itself is invoked (and where it's located).
I'll assume the main.dart library is inside the lib/ directory, because otherwise you wouldn't have the two options for importing myclass.dart.
If you invoke the main file with a file: URI, then the relative import of myclass.dart will also be imported with a file: URI. Since Dart uses the import URI to distinguish different libraries, if someone else imports myclass.dart using a package: URI, then it will be treated as two different libraries introducing different classes with the same name.
It used to be that running dart lib/main.dart would treat that as a file: URI. The Dart parser has gotten smarter about that, and now it recognizes that an entry point library in a lib/ directory should have been a package: URI, and replaces the entry point URI with package:projectxyz/main.dart.
After that, it makes no difference whether you use myclass.dart or package:projectxyz/myclass.dart.
Really, there is no difference between the two. Saying import 'myclass.dart' is high-level sugar for import 'package:projectxyz/myclass.dart';.
On the other hand, import 'myclass.dart' is easier to read and understand, and generally looks better. It also decreases confusion as to where exactly your code is being imported from, as anybody who reads this statement knows to look for the file elsewhere in your project. Because of this, you should try to use this form wherever possible.

importing library modules using a frequent imports approach

Suppose there is a set of frequent imports that I would like not to have to repeat in every module. Is there a way to specify "frequent imports" that could be called instead. For example something like:
module frequentImports =
open System
open System.IO
...
Then instead of having to retype all the imports individually, the frequentImports module could be called instead. Obviously, the above approach doesn't work for me which is why the question.
Thanks.
There is no way to define something like a group of open statements and then just refer to the group. Generally, you just need to have all your open statements once per file.
The fact that you have too many of them that you want to repeat all the time might suggest that your code organisation is not optimal - I would think that if you have code structured by putting logically related things into a single file, then each file would need different imports.
One thing you could do - though I don't think it's all that nice - is that you could define a module with module and type aliases for the things you commonly need.
Say, if I wanted to avoid opening Microsoft.FSharp.Reflection and System.Collections.Generic, I could define a module with aliases for the things I need:
module MyThings =
type Dictionary<'k,'v> = System.Collections.Generic.Dictionary<'k, 'v>
type FSharpType = Microsoft.FSharp.Reflection.FSharpType
type FSharpValue = Microsoft.FSharp.Reflection.FSharpValue
Using open MyThings now gives me access to the three types (and the same would work for modules too). That said, this does not automatically import all definitions and I think it's probably not worth doing this - but it's an option.

What is the recommended way to make & load a library?

I want to make a small "library" to be used by my future maxima scripts, but I am not quite sure on how to proceed (I use wxMaxima). Maxima's documentation covers the save(), load() and loadFile() functions, yet does not provide examples. Therefore, I am not sure whether I am using the proper/best way or not. My current solution, which is based on this post, stores my library in the *.lisp format.
As a simple example, let's say that my library defines the cosSin(x) function. I open a new session and define this function as
(%i0) cosSin(x) := cos(x) * sin(x);
I then save it to a lisp file located in the /tmp/ directory.
(%i1) save("/tmp/lib.lisp");
I then open a new instance of maxima and load the library
(%i0) loadfile("/tmp/lib.lisp");
The cosSin(x) is now defined and can be called
(%i1) cosSin(%pi/4)
(%o1) 1/2
However, I noticed that a substantial number of the libraries shipped with maxima are of *.mac format: the /usr/share/maxima/5.37.2/share/ directory contains 428 *.mac files and 516 *.lisp files. Is it a better format? How would I generate such files?
More generally, what are the different ways a library can be saved and loaded? What is the recommended approach?
Usually people put the functions they need in a file name something.mac and then load("something.mac"); loads the functions into Maxima.
A file can contain any number of functions. A file can load other files, so if you have somethingA.mac and somethingB.mac, then you can have another file that just says load("somethingA.mac"); load("somethingB.mac");.
One can also create Lisp files and load them too, but it is not required to write functions in Lisp.
Unless you are specifically interested in writing Lisp functions, my advice is to write your functions in the Maxima language and put them in a file, using an ordinary text editor. Also, I recommend that you don't use save to save the functions to a file as Lisp code; just type the functions into a file, as Maxima code, with a plain text editor.
Take a look at the files in share to get a feeling for how other people have gone about it. I am looking right now at share/contrib/ggf.mac and I see it has a lengthy comment header describing its purpose -- such comments are always a good idea.
For principiants, like me,
Menu Edit:configure:Startup commands
Copy all the functions you have verified in the first box (this will write your wxmaxima-init.mac in the location indicated below)
Restart Wxmaxima.
Now you can access the functions whitout any load() command

Library written into more files

I found a Dart library, which hasn't got any main lib.dart file with library 'lib'; at the beginning, but which has more files with library 'lib.sublib'; at the beginning. I understand this notation, but I have a question:
What if I want to have no main lib.dart file, but have eg three parts of my library as explained above and additionally I want to have one file, which joins all three sublibs into one for case if the user wants to use all three parts of the library?
What's right? See my two drafts below. Is any of them correct? Or should it be written anyhow else?
Draft I:
//lib.dart
library 'lib';
part 'superlib.dart';
part 'bestlib.dart';
//superlib.dart
part of 'lib';
...
//bestlib.dart
part of 'lib';
...
Draft II:
//lib.dart
library 'lib';
export 'superlib.dart';
export 'bestlib.dart';
//superlib.dart
library 'lib.super';
...
//bestlib.dart
library 'lib.best';
...
Both attempts are fine.
The first difference is that the parts can access private fields, functions, classes, class members (where the name starts with an underscore _) of each other part because they are in the same library.
The second difference is that the parts can not be imported individually by user if they are in the same library. Just the library itself could be imported.

Erlang: "extending" an existing module with new functions

I'm currently writing some functions that are related to lists that I could possibly be reused.
My question is:
Are there any conventions or best practices for organizing such functions?
To frame this question, I would ideally like to "extend" the existing lists module such that I'm calling my new function the following way: lists:my_funcion(). At the moment I have lists_extensions:my_function(). Is there anyway to do this?
I read about erlang packages and that they are essentially namespaces in Erlang. Is it possible to define a new namespace for Lists with new Lists functions?
Note that I'm not looking to fork and change the standard lists module, but to find a way to define new functions in a new module also called Lists, but avoid the consequent naming collisions by using some kind namespacing scheme.
Any advice or references would be appreciated.
Cheers.
To frame this question, I would ideally like to "extend" the existing lists module such that I'm calling my new function the following way: lists:my_funcion(). At the moment I have lists_extensions:my_function(). Is there anyway to do this?
No, so far as I know.
I read about erlang packages and that they are essentially namespaces in Erlang. Is it possible to define a new namespace for Lists with new Lists functions?
They are experimental and not generally used. You could have a module called lists in a different namespace, but you would have trouble calling functions from the standard module in this namespace.
I give you reasons why not to use lists:your_function() and instead use lists_extension:your_function():
Generally, the Erlang/OTP Design Guidelines state that each "Application" -- libraries are also an application -- contains modules. Now you can ask the system what application did introduce a specific module? This system would break when modules are fragmented.
However, I do understand why you would want a lists:your_function/N:
It's easier to use for the author of your_function, because he needs the your_function(...) a lot when working with []. When another Erlang programmer -- who knows the stdlb -- reads this code, he will not know what it does. This is confusing.
It looks more concise than lists_extension:your_function/N. That's a matter of taste.
I think this method would work on any distro:
You can make an application that automatically rewrites the core erlang modules of whichever distribution is running. Append your custom functions to the core modules and recompile them before compiling and running your own application that calls the custom functions. This doesn't require a custom distribution. Just some careful planning and use of the file tools and BIFs for compiling and loading.
* You want to make sure you don't append your functions every time. Once you rewrite the file, it will be permanent unless the user replaces the file later. Could use a check with module_info to confirm of your custom functions exist to decide if you need to run the extension writer.
Pseudo Example:
lists_funs() -> ["myFun() -> <<"things to do">>."].
extend_lists() ->
{ok, Io} = file:open(?LISTS_MODULE_PATH, [append]),
lists:foreach(fun(Fun) -> io:format(Io,"~s~n",[Fun]) end, lists_funs()),
file:close(Io),
c(?LISTS_MODULE_PATH).
* You may want to keep copies of the original modules to restore if the compiler fails that way you don't have to do anything heavy if you make a mistake in your list of functions and also use as source anytime you want to rewrite the module to extend it with more functions.
* You could use a list_extension module to keep all of the logic for your functions and just pass the functions to list in this function using funName(Args) -> lists_extension:funName(Args).
* You could also make an override system that searches for existing functions and rewrites them in a similar way but it is more complicated.
I'm sure there are plenty of ways to improve and optimize this method. I use something similar to update some of my own modules at runtime, so I don't see any reason it wouldn't work on core modules also.
i guess what you want to do is to have some of your functions accessible from the lists module. It is good that you would want to convert commonly used code into a library.
one way to do this is to test your functions well, and if their are fine, you copy the functions, paste them in the lists.erl module (WARNING: Ensure you do not overwrite existing functions, just paste at the end of the file). this file can be found in the path $ERLANG_INSTALLATION_FOLDER/lib/stdlib-{$VERSION}/src/lists.erl. Make sure that you add your functions among those exported in the lists module (in the -export([your_function/1,.....])), to make them accessible from other modules. Save the file.
Once you have done this, we need to recompile the lists module. You could use an EmakeFile. The contents of this file would be as follows:
{"src/*", [verbose,report,strict_record_tests,warn_obsolete_guard,{outdir, "ebin"}]}.
Copy that text into a file called EmakeFile. Put this file in the path: $ERLANG_INSTALLATION_FOLDER/lib/stdlib-{$VERSION}/EmakeFile.
Once this is done, go and open an erlang shell and let its pwd(), the current working directory be the path in which the EmakeFile is, i.e. $ERLANG_INSTALLATION_FOLDER/lib/stdlib-{$VERSION}/.
Call the function: make:all() in the shell and you will see that the module lists is recompiled. Close the shell.
Once you open a new erlang shell, and assuming you exported you functions in the lists module, they will be running the way you want, right in the lists module.
Erlang being open source allows us to add functionality, recompile and reload the libraries. This should do what you want, success.

Resources