-
Notifications
You must be signed in to change notification settings - Fork 34
Description
Currently nuru has a module system.
The aim of this proposal is to improve on this system.
This introduces breaking changes to the core language.
For consistency, the following terms are defined as:
- Module: A file containing functions and 'objects'
- Object: The smallest unit of code that can be used e.g function and variables.
- Package: Collection of modules.
The current module system
The current module system is both file based and inbuilt.
To use a module, tumia keyword followed by the module is used.
For "inbuilt" modules, the module name is not quoted e.g tumia hesabu.
For file based, quotes around the name is used example tumia "hesabu".
The file extension is not used as its implied.
Examples used here are generously donated by Victor Kariuki
File based modules
An example of usage is:
tumia "hesabu"
andika("abs: ",hesabu.abs(-42));
andika("acos: ",hesabu.acos(0.5));
andika("acosh: ",hesabu.acosh(2));
andika("asin: ", hesabu.asin(0.5));
andika("asinh: ",hesabu.asinh(2));
andika("atan: ",hesabu.atan(1));
Example declaration:
pakeji hesabu{
//CONSTRUCTOR METHOD
andaa = unda() {}
// Constants
// π (Pi)
PI = unda() {
rudisha 3.141592653589793;
}
}
The modules here have to be declared using special syntax pakeji keyword.
ONLY functions can be exported under the current system so every 'entry' must be a function.
The current system has several advantages:
- Only functions can be exported, so you only have to deal with that one type.
- Special syntax clearly denotes that this is a package and not a normal piece of source code.
- The name of the package is the same as the file which is easy to manage.
Despite the advantages, it has its share of disadvantages:
- Only one package can be declared per file, using a construct
pakeji {}is syntax bloat. - Only current directory is used, this means all the code must be copied to the current directory.
- Only functions can be exported, this limits the developer to making functions for trivial code even for simple constants like
PI. - The module must match the file its declared in (Java?) which defeats the purpose of naming it.
Inbuilt modules
This are modules that are packages with the language itself.
They are more a language feature than a package.
Example Usage:
tumia mtandao
tumia jsoni
// Main function to execute the recommendation and saving
fanya main = unda(){
fanya game = mtandao.peruzi("http://localhost:4000/game-state")
fanya gameState = jsoni.dikodi(game)
andika(game,gameState)
fanya gameBoard = gameState["gameBoard"]
fanya currentPlayer = gameState["currentPlayer"]
fanya move = recommendMove(gameBoard, currentPlayer)
headers = {"Authentication": "Bearer XXXX"}
mtandao.tuma(yuareli="http://localhost:4000/recommend-a-move", vichwa=headers, mwili={"move": move})
}
Proposed new module system
There are several module system in existence.
For this we'll focus on file based module.
This proposal is partially inspired by the Zig Build system and Python module system.
Since nuru has weak type system, some of the concepts that will be borrowed will have to be heavily modified to fit.
Removal of pakeji keyword
The pakeji keyword is not useful as is.
Using the current usage as an example, it does nothing but add bloat and complexity to the source code.
Removing the keyword will make any file become a package.
By making any file a possible package file, it means that breaking down code logic is easier.
The keyword removal will mean that every object will be public.
This can be mitigated by adding modifiers e.g siri which makes all the objects public or a wazi which will make all objects private.
The second approach of making the objects private and optionally making them public is the industry standard hence will be used.
An example can be:
wazi PI = 3
wazi elezo = unda() {
rudisha "Hili ni elezo la utumiaji"
}
This will limit the amount of information shared with outside repositories.
This change will affect all the modules until this point.
Since the module system is not widely used (only a few examples so far) the changes' impact is minimal.
Import style
To import a package/module, the following pattern can be used tumia package::module::[object...].
The :: is used as path seperator for packages/modules.
When using file imports, the search will start in the current directory.
To start in the parent directory, .. can be used.
The path should not be outside the parent package directory.
The parent package directory is where __pakeji__.nuru file is located in.
If __pakeji__.nuru is not found in parent directory, traversal is allowed upto root directory in file system.
tumia nyuki.nuru::* // Faili inapatikana hapa
tumia ..::wanyama.nuru::*
Each module import should be placed in a seperate line.
Multiple objects can be imported in an import.
To import all the modules that can be imported, star import can be used.
tumia xf::p9 // One object
tumia xp::[p1,p2,p3] // Specific objects
tumia xt::* // All the modules
An object can be aliased using ni keyword.
tumia re::p3 ni re3
tumia rr::[p4 ni rm, p8 ni pb]
tumia rt::[br ni brm, bb]
Its not a must to import to the level of objects, module level is supported.
This keeps the module as the namespace.
Aliasing can be done on this level too.
tumia re
tumia ry ni yr
Special package name msingi is used as the standard package.
No user package is allowed to be named as such to avoid name squatting.
Special file __pakeji__.nuru
To manage modules, a special file is used to track the package information.
The file is not required if only std is used in only one file.
All the information about the package are to be stored inside here.
All the values here are pre-initialized to their 'zero values'.
If the expected type and the found type are a mismatch, the program will fail to run.
Due to the weak type system, this may prove to be a bad idea but this also reduces the number of languages here.
Using nuru itself instead of other configuration formats like json, xml and, toml helps reduce the amount of syntax required to start and helps in gauging the language maturity.
This are the versioning rules and syntax that will be used henceforth:
-
Semantic Versioning 2.0.0 will be used or full git hash
-
For SemVer, the rules applies:
"v" is used to denote the version.
This will be used as minimal version number.An example: "v12.3.202"
To make it exact, a preceding "!" can be used.
An example "!v2.9.0"
To make it maximum, a preceding "~" can be used
An example "~v13.0.23"
Range can be used when refering to versions.
"..." can be used between the versions for this.
The versions here are taken to be exact hence SHOULD NOT have a modifier.An example "v2.1.23...v2.90.23"
-
For git hash, a "#" is used before the git hash.
An example "#1a410efbd13591db07496601ebc7a059dd55cfe9"
-
Multiple versions can be specified seperated by commas.
-
When specifying multiple versions, its a additive operation which means that if a broad range is specied next to a specific version, the specific may have no effect.
-
To exlude certain versions, "-" can be used before the version (space between the modifier and the version)
Example for single version "- v23.02.44"
Multiple versions can be done in the same wan
"~v23.23.89, - v12.13.0, - !v23.20.0"
-
Git hash can't be used in a range.
-
NO mixing between the two modes of versioning.
Versions should follow the SemVer specification or git hash.
The following are the expected values and their types.
-
toleo_nuru: Tungo (inahitajika)
This is the minimal version of nuru that is required. (Required)
Version rules should be observed.
-
jina: Tungo (inahitajika)
This the name of the project. (Required)
The name should only contain ASCII letters.
-
toleo: Tungo (inahitajika)
This is the version of the project. (Required)
Version rules should be observed.
-
pakeji: Kamusi (inahitajika)
This is the modules in the project.
Themainmodule should be defined if this is to be executed with the name "kuu".
If this is a library, then themainmodule can be skipped.The
keypart of the dictionary should be ASCII letters.
This is the name of the package.The
valuepart is the path of the 'root' file.
The rules of path applies. -
hazina: Kamusi
This is the repository where the packages will be downloaded from.
This enables multiple repositories to be used having the best of centralized and distributed systems.The
keypart is the name of the repository.
It should contain only ASCII letters.
it can contain optional path seperator (useful for git when the project is in a sub directory)The
valuepart has the syntax:url $standardThe url is the full url to the repository.
The
$standardpart is the standard to be used.
The conceived standards aregitandapi.The standard API should have a way to retrieve metadata, get the package files and post package files.
The API should be REST based.
Authentication should be supported as first class and not an addon. -
moduli: Kamusi
This is where external modules are specified.
The
keypart is the name of the package.
To avoid collisions, a new name can be used by using$modifier.
The name should be ASCII letters.An example is "hashbrown $hash"
The
valuepart has the pattern:@hazina toleo.
The@hazinaif the one declared in thehazinadictionary.
Thetoleoshould follow the version spec.Everything after
hazinais taken to be the version.
If the two are swithed around, then the program will fail.
An example of __pakeji__.nuru:
toleo_nuru = "v0.15.18"
jina = "milima"
toleo = "v1.23.9"
pakeji = {
"elgon" : "src::elgon.nuru",
"kenya" : "src::kenya.nuru",
"kilimanjaro" : "src::kilimanjaro.nuru",
}
hazina = {
"nuru" : "https://nuruprogramming.org/moduli $api",
"gtx" : "https://example.com/gtx $api" ,
"avicenna" : "https://github.com/avicenna $git",
}
moduli = {
"hashbrown" : "@nuru v1.2.3",
"rand" : "@nuru v0.34.4",
"rand $r2" : "@gtx v0.12.209",
"x45" : "@gtx v9.0.23",
"gisqusting" : "@avicenna #85a2569dd32802736d0b6dec0d571d877250824a",
}