Skip to content

Packages

Introduction

Packages are objects that allow you to extend the functionalities of the language. Once declared, they can be imported anywhere in the code. They can also be easily shared with others, so everyone benefits.

Available since: SurgeScript 0.5.2

Basic example

Suppose you want to extend the language by adding new routines related to string manipulation. These routines will be used frequently throughout your project, and you'd like easy access to them. This makes it perfect for implementing them as a package.

We'll define an object called StringUtils with a reverse() function that reverses a string. We make the object a package by annotating it with @Package. Take a look at the example below:

// File: stringutils.ss

@Package
object "StringUtils"
{
    fun reverse(str)
    {
        buf = "";
        for(i = str.length - 1; i >= 0; i--)
            buf += str[i];
        return buf;
    }
}

When you annotate an object definition with @Package, SurgeScript will spawn an instance of such an object before spawning the Application. Additionally, the package object may be imported anywhere with the using keyword:

// File: app.ss
using StringUtils;

object "Application"
{
    state "main"
    {
        str = StringUtils.reverse("alucard");
        Console.print(str); // will print "dracula"
        exit();
    }
}

Note: it's recommended not to include any special characters in the name of your packages.

In the example above, Application and StringUtils are located in two separate files. If you want to test them using the SurgeScript command line utility, pass both files as parameters:

surgescript package.ss app.ss

Spawning order

Although packages are spawned before the Application object, for the time being they are spawned in no particular order. You may not access a package from within the constructor of another package, as of now there is no dependency resolver implemented. Use the main state.

Note: before SurgeScript 0.5.4, you would annotate the object with @Plugin instead.

Package example

Packages may aggregate many code units with different functionalities. This lets you separate your code in coherent, logical units and also helps you to distribute it.

Suppose that user Parrot, the owner of ParrotSoft, created SurgeScript utilities related to string manipulation, matrix math and complex numbers. He decided to share his code as a single package called ParrotSoft. Since he implemented getters for each of his utilities, his package provides easy access to all of them. Furthermore, he annotated his package with @Package (but not the individual utilities), so his package can be accessed anywhere.

// File: parrotsoft.ss

@Package
object "ParrotSoft"
{
    public readonly Matrices = spawn("Parrot Matrices");
    public readonly Complex = spawn("Parrot Complex");
    public readonly StringUtils = spawn("Parrot StringUtils");
}

A user of the ParrotSoft package may import Parrot's utilities simply by importing the package. Individual utilities may also be imported. The code below shows an example:

using ParrotSoft.Matrices.Matrix2;
using ParrotSoft.Complex;
using ParrotSoft;

object "Application"
{
    state "main"
    {
        identity = Matrix2([[1, 0], [0, 1]]); // 2x2 matrix
        z = Complex(2, 3); // 2 + 3i
        neon = ParrotSoft.StringUtils.reverse("noen");
        exit();
    }
}

In the example above, writing Complex is equivalent to writing ParrotSoft.Complex, since we imported this utility with using ParrotSoft.Complex. Notice that ParrotSoft implements a getter for Complex. Additionally, ParrotSoft has been annotated with @Package, but Complex has not. This means that the statement using Complex will not yield the expected result. Since Complex is a part of ParrotSoft, it can only be accessed from it. Finally, since we haven't imported StringUtils explicitly, we type ParrotSoft.StringUtils to access it.