Namespaces

⚠️ This is an experimental feature.

Motivation

Namespaces solve the challenge of name collisions. A name collision occurs, if multiple definitions of the same name overlap.

Imagine that you want to integrate useful code from two different programmers in your own project. Both of them have defined and use a function substring in their code. Maybe it extracts part of a text in either case, but that part is identified by its start and its end in one case and by its start and its length in the other case. Maybe you have an equally named function in your own code already, too. This name collision will result in an error when substring is called, sometimes even earlier.

You could sift through the code and rename functions to resolve the conflict. This can be a lot of work though; it is error-prone and you can't simply copy updates of the foreign code into your project later.

It is more elegant to encapsulate each foreign code snippet in its own namespace within your project. Each namespace comes with a unique prefix that you can use to identify which substring function you refer to then.

Defining a Namespace

Code is encapsulated in a namespace by enclosing it in angle brackets < >. These brackets are usually called less-than and greater-than sign elsewhere, but they serve as brackets in Quirl. A name that is used as namespace prefix precedes the left angle bracket. Note that namespacing is a statement in Quirl – use a semicolon to separate it from other statements. Here is an example:

hyperbolic<
  sine(Float)   = mul(add(exp($a) neg@exp@neg($a)) !0.5);
  cosine(Float) = mul(add(exp($a)     exp@neg($a)) !0.5);
> ;

Encapsulated code between angle brackets is processed silently: you won't get a response for it in the Quirl chat unless an error occurs.

Predefined Functions in Namespaces

Currently, only core functions are predefined inside a namespace capsule.

⚠️ This will probably change in the near future.

Accessing Definitions in a Namespace

You can access functions defined inside a namespace from the outside by prepending the prefix and a dot. For instance,

hyperbolic.sine(1.4)

calls the namespaced function defined earlier and yields the response !1.904301501451534. Anything else defined in a namespace can also be accessed by prefix, dot and name: constants, structures and languages.

Aliasing Namespaced Names

Consider to define a constant, if you do not want to write a long prefixed name repeatedly. For example, the hyperbolic cosine function defined above could be aliased as

cosh = hyperbolic.cosine;

to be used as follows:

cosh(!0); # returns !1

Nesting Namespaces

Namespaces can be nested. In other words, you can define namespaces within another namespace:

canis<
  aureus<NAME="golden jackal"; RANGE="Eurasia">;
  latrans<NAME="coyote"; RANGE="Northern America">;
  familiaris<NAME="dog"; RANGE="Earth and low Earth orbits">
>

Now canis.latrans.RANGE does have the value "Northern America".