[ Prev | Index | Next ]
Japanese English

Modules and Libraries

This section covers the basics of modules and how to import libraries.

Sponsored Link


Modules and Libraries

What is a Library?

A library is a modular program that contains reusable processes, values, and other components frequently used in various applications.

The term "library" can refer to anything from a small memo-like script to a highly sophisticated collection of functionality. But what they all have in common is that they are **called and used as components by other programs.

Modules

So far, we've written all our programs in a single file, with all processing self-contained within it. However, when using libraries, programs often span multiple files, with different components working together.

While it is possible to merge all these files into one for execution, doing so may cause conflicts when the same variable or function names are used. To avoid this, each file is typically loaded and executed as an independent module.

That might sound a bit abstract, but in VCSSL, each file automatically corresponds to a single module. So you can simply think of a module as the content of a file. For example, a file named "A.vcssl" defines a module called "module A".

Executable Modules vs. Library Modules

An executable module is one that is directly executed -- as we've done so far -- rather than being used by another module.

In contrast, a library module is not executed directly. Instead, it's used as a component by being loaded from another module.

Importing Libraries

To use functions provided in a library module from another module (i.e., a program written in a separate file), you need to declare an "import" statement at the beginning of the module:

import library.path;

The "library.path" should be specified using dot notation representing the relative path from the executable module. You do not need to include the file extension ".vcssl."

If the library module is located in the same folder as the executable module, you can just write the filename.

For example, to use "TestLib.vcssl" located in the same folder:


import TestLib;
ImportLib.vcssl

This allows you to use all the functions and constants defined in "lib.vcssl."

To import lib.vcssl located in the bbb folder inside the aaa folder, relative to the executable module:


import aaa.bbb.TestLib;
ImportAaaBbbLib.vcssl

Using Functions and Variables from Other Modules

To use functions or variables from another module, if there are no naming conflicts, you can use them just like any other function or variable -- no special syntax is required.

For example, to call a function defined in module B from executable module A:

- Executable Module A (A.vcssl) -


import B; // Import library module B

fun();
A.vcssl

- Library Module B (B.vcssl) -


void fun() {
	print("B.fun was called");
}
B.vcssl

When you execute "A.vcssl," the VCSSL console will display:

Even though the fun() function is not defined in module A, calling fun() invokes the one declared in module B.

Module Precedence

In the example above, if the function or variable name (and the argument signature, in the case of functions) exists in multiple modules, conflicts can occur.

For instance, try running the following code:

- Executable Module A (A.vcssl) -


import B; // Import library module B

void fun() {
	print("A.fun was called");
}

fun(); // Note: Function name 'fun' exists in both A and B
A.vcssl

- Library Module B (B.vcssl) -


void fun() {
	print("B.fun was called");
}
B.vcssl

When you execute A.vcssl, the output will be:

A.fun was called

In other words, the "fun" function in module A is called, not the one in module B.

As you can see, when calling a function, VCSSL gives priority to functions declared in the current module.

If the function or variable is not found in the current module, then the interpreter searches the modules listed in the import statements. If there are multiple candidates, the one imported later takes precedence.

If it still cannot be found, VCSSL interpreter searches across all modules that have been loaded -- including modules imported by other modules. Again, later-loaded modules take precedence.

Here's an example:

- Executable Module A (A.vcssl) -


import B; // Import library module B

fun();
A.vcssl

- Library Module B (B.vcssl) -


import C; // Import library module C
B.vcssl

- Library Module C (C.vcssl) -


void fun() {
	print("C.fun was called");
}
C.vcssl

When you execute A.vcssl, the VCSSL console will display:

C.fun was called

Even though module A only imports module B, it can still call the fun function in module C because module B imported module C, and the interpreter is aware of C's existence.

However, this feature can make it difficult to track precedence and may reduce readability when many modules are involved.

Therefore, as a general rule, you should explicitly import the modules you intend to use directly.
In the example above, it is recommended to add "import C;" in module A as well.

Explicitly Specifying the Module

The automatic module resolution based on precedence, as discussed earlier, is convenient for small-scale programs.

However, when dealing with many modules -- or when using third-party library modules -- it becomes difficult to fully track which functions (with what names and arguments) are defined in which modules. In such cases, if two functions have the same name and one accidentally calls the wrong one, it can lead to unexpected behavior.

To avoid this, you can explicitly specify the module name before the function or variable name, separated by a dot (.):

- Executable Module A (A.vcssl) -


import B; // Import library module B
import C; // Import library module C

B.fun();
C.fun();
A.vcssl

- Library Module B (B.vcssl) -


void fun() {
	println("B.fun was called");
}
B.vcssl

- Library Module C (C.vcssl) -


void fun() {
	println("C.fun was called");
}
C.vcssl

When executing A.vcssl, the VCSSL console will display:

B.fun was called
C.fun was called

By explicitly specifying the module, you can avoid accidentally calling the wrong function due to naming conflicts, while also improving the readability of your code.

Access Modifiers

Explicitly specifying the module name helps prevent the caller from accidentally accessing the wrong function or variable.

In contrast, the callee -- that is, the module being called -- can also control access using access modifiers. VCSSL provides two access modifiers: private and public.

If there are functions or variables that should not (or need not) be accessed from outside the module, you can mark them as private. This prevents them from being accessed externally -- they will be treated as if they don't exist outside the module.

On the other hand, if you declare a function or variable with public, it becomes accessible from other modules. By default, any function or variable declared without an access modifier is treated as public.

Here's an example:


// This variable cannot be accessed from outside the module
private int a;

// This variable can be freely accessed from outside
public int b;


// This function cannot be called from outside the module
private void funA() {
	println("funA was called");
}

// This function can be freely called from outside
public void funB() {
	println("funB was called");
}
Access.vcssl

In the example above, variable "a" and function "funA" are marked private, so they cannot be accessed from outside the module.

In contrast, variable "b" and function "funB" are marked public, so they can be freely used externally.

Note that explicitly writing "public" behaves the same as omitting the access modifier. So functionally, there's no difference.

However, using "public" explicitly improves clarity -- it makes clear that the function or variable is intentionally accessible from outside and not just an oversight.

Module Uniqueness

VCSSL guarantees module uniqueness: even if a module is imported multiple times, it exists only once in memory.

For example, consider the following:

- Executable Module A (A.vcssl) -


import B; // Import library module B
import C; // Import library module C

C.x = 2;

B.fun();
A.vcssl

- Library Module B (B.vcssl) -


import C; // Import library module C here again

void fun() {
	println(C.x);
}
B.vcssl

- Library Module C (C.vcssl) -


int x = 0;
C.vcssl

When you execute this program, the VCSSL console will output:

2

This confirms that the C module imported from A and the C module imported from B are the same instance.

Relative Paths Inside Library Modules

When accessing files from within a library module, you must be careful about the path specification.

This is because the relative path must be specified from the perspective of the executable module, not the library module.

For example:

  • If a library module imports another library module,
  • Or if it performs file I/O,
  • Or if it loads images,

In all of these cases, the paths must be written **relative to the executable module**, not the library's location.

This is important to ensure consistent behavior regardless of where a library module resides in the file structure.

Execution Order of Global Areas in Modules

As you've seen throughout this guide, you can write regular statements in the global scope of a VCSSL module.

In such cases, the order in which each module's global area executes becomes important.

VCSSL follows a depth-first, import-based execution order:

  • Modules imported deeper in the import tree are executed earlier.
  • At the same depth level, modules are executed in the order they were imported.
  • The executable module is considered the shallowest (last to run).

Initialization Order of Global Constants

Variables declared with the "const" keyword become constants that cannot be changed after initialization:


const int CONSTANT_VALUE = 255;
Const.vcssl

Global constants like these are initialized before the global code execution begins.

Therefore, by the time any global execution starts, all global constants in all modules are guaranteed to be initialized.

Using "include" to Embed File Contents into a Single Module

VCSSL also provides an "include" directive, similar to import.

Instead of importing a file as a separate module, "include" embeds the contents of another file directly into the current module, as if you had written the contents inline.

So the included file and the including file become part of the same module.

This is useful when:

  • You want to create multiple similar modules that share a common base,
  • Or you want to write a shared "template" or framework file that can be included and then customized by overriding specific functions.

VCSSL allows function overriding within the same module. If the same function (with the same arguments) is declared multiple times, the one declared later (further down in the file) takes precedence.

This allows you to include a shared function, then override it as needed in the including file.



Sponsored Link



Japanese English
Index
News From RINEARN
* VCSSL is developed by RINEARN.

VCSSL 3.4.52 Released: Enhanced Integration with External Programs and More
2025-05-25 - This update introduces enhancements to the external program integration features (e.g., for running C-language executables). Several other improvements and fixes are also included. Details inside.

Released: Latest Version of VCSSL with Fixes for Behavioral Changes on Java 24
2025-04-22 - VCSSL 3.4.50 released with a fix for a subtle behavioral change in absolute path resolution on network drives, introduced in Java 24. Details inside.

Released the Latest Versions of RINEARN Graph and VCSSL - Now Supporting Customizable Tick Positions and Labels!
2024-11-24 - Starting with this update, a new "MANUAL" tick mode is now supported, allowing users to freely specify the positions and labels of ticks on the graph. We'll explain the details and how to use it.

Released Exevalator 2.2: Now Compatible with TypeScript and Usable in Web Browsers
2024-10-22 - The open-source expression evaluation library, Exevalator, has been updated to version 2.2. It now supports TypeScript and can be used for evaluating expressions directly in web browsers. Explains the details.

Behind the Scenes of Creating an Assistant AI (Part 1: Fundamental Knowledge)
2024-10-07 - The first part of a series on how to create an Assistant AI. In this article, we introduce the essential knowledge you need to grasp before building an Assistant AI. What exactly is an LLM-based AI? What is RAG? And more.

Launching an Assistant AI to Support Software Usage!
2024-09-20 - We've launched an Assistant AI that answers questions about how to use RINEARN software and helps with certain tasks. Anyone with a ChatGPT account can use it for free. We'll explain how to use it.

Software Updates: Command Expansion in RINEARN Graph, and English Support in VCSSL
2024-02-05 - We updated our apps. This updates include "Enhancing the Command-Line Features of RINEARN Graph" and "Adding English Support to VCSSL." Dives into each of them!

Inside the Repetitive Execution Speedup Impremented in Vnano Ver.1.1
2024-01-17 - Delves into the update in Vnano 1.1 from a developer's viewpoint, providing detailed insights into the specific improvements made to the internal structure of the script engine.