Difference between revisions of "Import"
(Created page with "<c>import</c> is a Mini Micro function that loads a MiniScript file from the current directory, '''/sys/lib''', '''/usr/lib''', or some path defined in env.importPaths...") |
|||
(8 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | <c>import</c> is a [[Mini Micro]] | + | <c>import</c> is a function in [[Mini Micro]], [[Farmtronics]], [[command-line MiniScript]], and [[Soda]] that loads a MiniScript file from the current |
directory, '''/sys/lib''', '''/usr/lib''', or some path defined in | directory, '''/sys/lib''', '''/usr/lib''', or some path defined in | ||
[[env]].importPaths. <c>import</c> looks for a file with the module name plus ".ms". | [[env]].importPaths. <c>import</c> looks for a file with the module name plus ".ms". | ||
Any values defined by that code then become available in a map of the same name. | Any values defined by that code then become available in a map of the same name. | ||
+ | |||
+ | == Usage Notes == | ||
+ | |||
+ | <c>import</c> imports the named module into the current local variable space. Simple (and typical) usage is to do this at the top of your main program, where [[locals]] and [[globals]] are the same thing, which makes the imported module globally available. | ||
+ | |||
+ | However, if you have a large, complex project composed of many interdependent modules, '''and''' you want those various modules to be testable on their own, then those modules are likely to be importing other modules, in what can rapidly become a tangle of imports that leads to several problems: | ||
+ | |||
+ | # A recursive cycle of imports (e.g. A imports B which imports A) can result in an infinite loop. | ||
+ | # Importing a large module several times wastes time and makes your program take longer to load than necessary. | ||
+ | # If the module has any internal state, then you now have multiple separate copies of that internal state, which can lead to hard-to-find bugs. | ||
+ | |||
+ | The solution to all these problems is to make a function like the following: | ||
+ | |||
+ | <ms>// ensureImport: check whether the given module has been imported already | ||
+ | // (or is in the process of being imported). If so, return immediately. | ||
+ | // If not, then import that module into the global namespace. | ||
+ | globals.ensureImport = function(moduleName) | ||
+ | if globals.hasIndex(moduleName) then return | ||
+ | globals[moduleName] = "PENDING" // (module is being imported now) | ||
+ | import moduleName | ||
+ | globals[moduleName] = locals[moduleName] | ||
+ | end function</ms> | ||
+ | |||
+ | Put this in some tiny, stand-alone script that can be safely imported from anywhere. Import this with <c>import</c>, but then load all other modules with the <c>ensureImport</c> function it provides. For example, if the above function is in a script called "coreUtils": | ||
+ | |||
+ | <ms>import "coreUtils" | ||
+ | ensureImport "someModule" | ||
+ | ensureImport "someOtherOne"</ms> | ||
+ | |||
+ | This will ensure that no matter how your various files depend on each other, each one is only loaded once. | ||
+ | |||
+ | '''Note:''' This <c>ensureImport</c> function is available in the /sys/lib/importUtil standard library in Mini Micro. | ||
+ | |||
+ | == Alternate Return Value == | ||
+ | |||
+ | Normally, all the file-scope variables (what would be <c>[[globals]]</c> if the module were loaded and run by itself) are gathered into the map referenced by the name of the module itself. However, it is possible to change this by executing a <c>[[return]]</c> statement inside the module. In this case, the name of the module will refer to whatever value you return. See [https://luminaryapps.com/blog/advanced-import/index.html this blog post] for more detail. | ||
== Examples == | == Examples == | ||
Line 11: | Line 47: | ||
Some modules, like [[listUtil]], [[stringUtil]], and [[mapUtil]], extend these | Some modules, like [[listUtil]], [[stringUtil]], and [[mapUtil]], extend these | ||
− | built-in types with new methods. For example, the built-in list | + | built-in types with new methods. For example, the built-in [[list]] |
type does not have a .reverse method, but it does once you import | type does not have a .reverse method, but it does once you import | ||
"listUtil": | "listUtil": | ||
Line 17: | Line 53: | ||
<ms>import "listUtil" | <ms>import "listUtil" | ||
print [1,2,3].reverse // prints [3, 2, 1]</ms> | print [1,2,3].reverse // prints [3, 2, 1]</ms> | ||
+ | |||
+ | [[Category:Mini Micro]] | ||
+ | [[Category:Farmtronics]] | ||
+ | |||
+ | == Further Reading == | ||
+ | |||
+ | * [https://luminaryapps.com/blog/advanced-import/index.html Advanced Tricks with Import] (blog post) |
Latest revision as of 16:58, 28 July 2023
import
is a function in Mini Micro, Farmtronics, command-line MiniScript, and Soda that loads a MiniScript file from the current
directory, /sys/lib, /usr/lib, or some path defined in
env.importPaths. import
looks for a file with the module name plus ".ms".
Any values defined by that code then become available in a map of the same name.
Usage Notes
import
imports the named module into the current local variable space. Simple (and typical) usage is to do this at the top of your main program, where locals and globals are the same thing, which makes the imported module globally available.
However, if you have a large, complex project composed of many interdependent modules, and you want those various modules to be testable on their own, then those modules are likely to be importing other modules, in what can rapidly become a tangle of imports that leads to several problems:
- A recursive cycle of imports (e.g. A imports B which imports A) can result in an infinite loop.
- Importing a large module several times wastes time and makes your program take longer to load than necessary.
- If the module has any internal state, then you now have multiple separate copies of that internal state, which can lead to hard-to-find bugs.
The solution to all these problems is to make a function like the following:
// ensureImport: check whether the given module has been imported already
// (or is in the process of being imported). If so, return immediately.
// If not, then import that module into the global namespace.
globals.ensureImport = function(moduleName)
if globals.hasIndex(moduleName) then return
globals[moduleName] = "PENDING" // (module is being imported now)
import moduleName
globals[moduleName] = locals[moduleName]
end function
Put this in some tiny, stand-alone script that can be safely imported from anywhere. Import this with import
, but then load all other modules with the ensureImport
function it provides. For example, if the above function is in a script called "coreUtils":
import "coreUtils"
ensureImport "someModule"
ensureImport "someOtherOne"
This will ensure that no matter how your various files depend on each other, each one is only loaded once.
Note: This ensureImport
function is available in the /sys/lib/importUtil standard library in Mini Micro.
Alternate Return Value
Normally, all the file-scope variables (what would be globals
if the module were loaded and run by itself) are gathered into the map referenced by the name of the module itself. However, it is possible to change this by executing a return
statement inside the module. In this case, the name of the module will refer to whatever value you return. See this blog post for more detail.
Examples
The following example loads a script called "mathUtil.ms" (normally found in /sys/lib), and makes it available as a map called mathUtil
.
import "mathUtil"
print mathUtil.radToDeg(2*pi) // prints 360
Some modules, like listUtil, stringUtil, and mapUtil, extend these built-in types with new methods. For example, the built-in list type does not have a .reverse method, but it does once you import "listUtil":
import "listUtil"
print [1,2,3].reverse // prints [3, 2, 1]
Further Reading
- Advanced Tricks with Import (blog post)