Imports

Let's unravel the art of importing files and libraries in FatScript! Why? Well, because in this language you can import whenever your heart desires, simply by using a left arrow <-.

Dot syntax

To use imports with dot syntax, project files and folders should neither start with a digit nor contain symbols.

you can specify any path you like by using literal paths

Named import

To import files, use the .fat extension for filenames (or no extension at all). However, omit the extension in the import statement. Here's an example:

ref <- filename

if both x and x.fat files exist, the latter takes precedence

For importing files from folders:

ref1 <- folder.filename
ref2 <- folder.subfolder.filename

To import all files from a folder, use the dot-underscore syntax:

lib <- folder._

Please note: only files immediately inside the folder are included using the above syntax. To include files from subfolders, explicitly mention them. Additionally, a "_.fat" file (or "_" file) inside a folder can override the dot-underscore import behavior.

slashes / can also be used as an alternative, such as ref <- folder/filename

Element access

Once imported, access elements using dot syntax:

ref1.element1

Element extraction

To extract specific elements from a named import or to avoid prepending the module name every time (e.g., lib.foo), employ destructuring assignment:

{ foo, bar } = lib

Visibility

Named imports are resolved at the global scope, irrespective of where they are declared. This means even if you declare a named import inside a function or a local scope, it will be globally accessible.

Local import

To import within the current scope, use:

_ <- filename

Local imports, unlike named imports, dump the file content directly into the current scope. Thus, an imported method can be invoked as baz(arg) rather than ref.baz(arg).

While local imports are best suited for importing types into the global scope, they should be used with caution when importing library content. Overusing local imports can lead to namespace pollution, which can make it more challenging to follow the code, because it becomes less apparent where the methods come from.

Literal paths

With literal paths, you may use any filename or extension. However, note that those imports are not evaluated during bundling, but at runtime. Here's an example:

ref <- '_folder/2nd-source.other'

You can also use smart texts as literal paths:

base = 'folder'
file = 'source.xyz'
ref <- '{base}/{file}'

Keep in mind that literal paths can make your code more complex, and those imports can only be dynamically resolved, so use them sparingly.

Import deduplication

FatScript utilizes an "import once" strategy with an in-scope flag mechanism, automatically bypassing files that have already been imported.

Pitfalls of import usage

  1. Local imports within method: Importing directly within a method body re-evaluates the import on every invocation, causing memory retention:

    myMethod = -> {
      _ <- lib  # potential memory leak
      ...
    }
    

    This behavior is not classified as a bug per se, but rather a consequence of design choices in FatScript's garbage collection (GC) system. The GC's optimizations exclude nodes directly derived from source code, allowing them to evade standard mark-and-sweep procedures. As a result, local imports within methods miss out on deduplication, causing their nodes to remain resident until the program's end.

  2. Selective local imports: Using destructuring assignment on local imports discards other members, but the whole import is processed and bound to the extracted member context:

    { foo1 } = { _ <- lib }  # lib is loaded and bound to foo1's context
    ...
    { foo2 } = { _ <- lib }  # lib is loaded again, and bound to foo2
    

    This pattern creates a closure. Using it for the same library results in repeated loads, increasing memory usage. For better efficiency, consider importing the library once at the top level and referencing it directly or using selective imports sparingly.

Best Practices

To avoid memory issues, follow these strategies:

  • Move imports to outer scope: Import libraries at a higher level to ensure single evaluation.
  • Use named imports: Prefer named imports to reuse code without redundancy.

results matching ""

    No results matching ""