S2 Guide: Language Tutorial

From Dreamwidth Notes
Jump to: navigation, search

S2 is a programming language designed to be a style system. It has properties in common with Perl, Python, and Java.


Comments are a way to leave notes in the program. If the first nonwhite space character on a line is a #, it makes that line into a comment:

# This variable holds the width of the image
var int width = 500;


A statement is an instruction in the program. Statements end with the ; character. They are usually formed by a combination of expressions, which are a combination of values, variables, operators, and functions that return a value.

Statements can also contain code blocks, which are surrounded by the { and } characters. Code blocks can contain one or more statements.


Variables are like containers that hold values. You can put values into them, use their values in your programming, or change their value to something else.

Variables are one of the basic concepts of programming. If you're not familiar with them, you may be able to pick up what they are and do from context here, or you can also look for some more in-depth explanations. Every programming language uses variables slightly differently, and many examples will use a specific language to demonstrate, but the underlying principles are the same.

More about variables (programming) on wikipedia

Variables on wikiversity

How to Think Like a Computer Scientist (Python version): Variables, expressions and statements (via [info]intro_to_cs)

Declaring a variable

In S2, variables must be declared ahead of time in order to be used. The basic format goes:

var TYPE variablename;
  • var indicates you're creating a new variable
  • TYPE describes what type of variable you're making. The type can be one of the basic types, described below, or a previously defined class (to be explained later). This type doesn't change.
  • variablename is the name you give the variable in your code. This name must start with a letter and can contain letters, digits, and the underscore character ("_").

You can assign a variable a value when declaring it, or wait until later--but make sure to assign a variable a value before you use it! An example of declaring a variable while assigning it is:

var TYPE variablename = VALUE;

Or, in real code:

var string greetings = "hello";

Note: you can assign the value of a variable to another variable, as well, if they are the same type. Here's an example that gives variable1 the value of variable2:

var TYPE variable1 = $variable2;

Or, in real code:

var string goodbye = $greetings;

Basic Types


String variables, which are lists of characters, are declared as string in S2. You can define strings in one of two ways.

The first way comes in between double quotes:

var string test = "Testing";

The second way comes in between sets of three double quotes--this is very useful when writing HTML, which can have a lot of single double quotes in it. Here's an example:

"""I am also a string, but I can have "quotes" inside me.""";

The above example demonstrates another property of string values, in that if you don't assign them to a variable name, they'll print to output.

Some characters need to be escaped to show up properly in strings, with a backslash (\):

  • If you need a newline, use: \n
  • If you need a double quote inside single double quotes (or need to make three or more double quotes inside a triple double quotes), use: \"
  • If you need to make a backslash, use: \\
  • If you want to make a dollar sign (you'll learn why later in the accessing variables section), use: \$


Integers (whole numbers) are another value like strings that the S2 language understands, and are declared with int. This is an example of a variable being assigned a literal integer value:

var int width = 500;


A boolean is a variable that is either true or false, and is declared with bool. Here is an example that expresses having candy but no cake as boolean variables:

var bool has_candy = true;
var bool has_cake = false;


An array is a list of items. They must all be the same type! Declaring an array variable is a little different from the usual variable declaration:

var TYPE[] variablename;

The [] after the type lets the program know this variable is an array.

Here is an example with strings:

var string[] counting = ["one", "two", "three"];

Associative arrays

Instead of an ordered list of items, an associative array gives each item in it a "key" that serves as an identifying label. All keys must be strings, and all the times must be the same type. Keys are unique--you can't have two items with the same key. Like regular arrays, declaring associative arrays is a little different:

var TYPE{} variablename;

The {} after the type lets the program know this variable is an associative array.

Here's an example with strings:

var string{} fruits = {"apple" => "red", "lemon" => "yellow", "grape" => "purple"};

Accessing variables

Putting a $ in front of the variable name lets you access it: $variablename. Remember how in strings, the dollar sign needed to be escaped with \$ to make $ show up properly? That's because when you reference a variable in a string, it's replaced with the value of the variable! For instance, this code:

# declare our greeting variable, assign it the value of "hi"
var string greeting = "hi";
# print out a sting containing our greeting
print "I greet you with: $greeting\n";
# change the value of our greeting to "hello"
$greeting = "hello";
# print out a string containing the new value of the greeting
print "I greet you with: $greeting\n";
# print out a string containing $greeting
print "I greet you with: \$greeting\n";

Will print out:

I greet you with hi
I greet you with hello
I greet you with $greeting

For regular arrays, you'll need to refer to the position of the value you want in the array; the count starts at 0. Example:

var string[] counting = ["one", "two", "three"]
print "I have $counting[2] bananas and $counting[1] apples and $counting[0] orange.\n";

Will print out:

I have three bananas and two apples and one orange.

For associative arrays, you'll want to use the key of the value you want. Example:

var string{} fruits = {"apple" => "red", "lemon" => "yellow", "grape" => "purple"};
print "I have $fruits{"grape"}-colored pants.\n";

Will print out:

I have purple-colored pants.

If you need to access a variable inside of a string but have trouble because it's right next to other characters instead of a space, put the variable name into ${}:

var string verb = "run";
print "I am ${verb}ing.";

Will print out:

I am running.


Properties are special global variables that are available between layers. EXPAND

Declaring properties

The basic format of a property declation goes:


Here is an integer property:

property int corner_radius {
  # the description for this property
  des = "Radius on corners, between 0-20px.";
  doc_flags = "[construct]";
  # the minimum allowed for this property
  min = 0;
  # the maximum allowed for this property
  max = 20;

Flags include:

  • des -- For describing the property.
  • noui -- This keeps a property from being included in the customization wizard.
  • label
  • grouped
  • grouptype
  • values
  • doc
  • doc_flags
  • example
  • note
  • size -- For string properties, the size of the text box.
  • maxlength -- For string properties, the maximum length of the string.
  • cols -- Number of columns for the text area.
  • rows -- Number of rows for the text area.
  • string_mode -- For string properties, uses values "css" and "html".
  • min -- For integer properties, the minimum.
  • max -- For integer properties, the maximum.
Expand: What does grouped=1 mean? What is the doc_flags for?

Setting properties

The basic format for setting a property is:



set entry_metadata_position = "bottom";
set use_shared_pic = false;
set comment_datetime_format_group = ["comment_date_format", "comment_time_format"];
set num_items_recent = 20;

Property groups

In the customization wizard, different properties can be grouped together like this:

propgroup images {
  property use image_background_page_group;
  property use image_background_header_group;
  property use image_background_header_height;
  property use image_background_entry_group;
  property use image_background_module_group;

Accessing properties

When you are trying to access a property, instead of $name, use $*name.


An operator takes in a certain number of arguments called operands and (usually) returns another value. A binary operator has two items, and a unary operator only uses one. They are often described by what position they inhabit on the line--left and right.


Because the assignment operator returns the value it is assigning, it's possible to chain multiple assignments together:

var string a;
var string b;
$a = $b = "text";

As previously mentioned, local variables can be assigned when they are declared.

var string a = "apple";

Arithmetic operators

Arithmetic operators are all made to do math on integers; they only take integers as arguments and return integers.

# + Addition, binary
var int total = $x + $y;
# - Subtraction, binary
var int difference = $x - $y;
# * Multiplication, binary
var int total = $x * $y;
# / Division, binary
# Note: since S2 only has integer numbers, the result is also an integer
#   even if there's no even division
var int ratio = $height / $width;
# % Modulus (remainder), binary
var int leftover = $x % $y;
# ++ Increment in-place, unary
# -- Decrement in-place, unary
# - Negation, unary
var int negative_margin = -$x;

Comparison operators

Comparison operators compare two arguments of the same type, and return a boolean (true or false). Equals (==) or does not equal (!=) can accept integers or strings as arguments; the rest only accept integers.

# == Equals, binary

if ( $var1 == $var2 ) {
    print "They are equal.";
# != Does not equal, binary

if ( $var1 != $var2 ) {
    print "They are not equal.";
# < Less than, binary

if ( $var1 < $var2 ) {
    print "var1 is less than var2";
# > Greater than, binary

if ( $var1 > $var2 ) {
    print "var1 is greater than var2";
# <= Less than or equal to, binary

if ( $var1 <= $var2 ) {
    print "var1 is less than or equal to var2";
# >= Greater than or equal to, unary

if ( $var1 >= $var2 ) {
    print "var1 is greater than or equal to var2";

Logical operators

Logical operators work with boolean (true or false) values, and also return a boolean value.

# and, Logical AND, binary
#   returns true only if both arguments are true

if ( $var1 and $var2 ) {
    print "Both var1 and var2 are true";
# or, Logical OR, binary
#   returns true if either argument is true

if ( $var1 or $var2 ) {
    print "At least one of var1 and var2 are true."
# not, Logical complement, unary
#   returns false if the argument is true, true if it is false

if ( not $var1 ) {
    print "var1 is not true"

Type operators

Type operators only work on object values. The left operand is the object in question, and the right operand is a class name.

# isa -- Returns true if the object is a given class or one of its children

# instanceof -- Returns true if the object is a given class only

# as -- Returns an object as if it was the given class if that's possible,
#   returns a null object if the object is incompatible with the given class

String concatenation (+)

Besides being used for addition, the + operand also concatenates (puts together) strings.

var string a = "one";
var string b = "two";
var string c = $a + " " + $b;

Range operator (..)

The range operator takes two integers and returns an array of integers inclusively listing all integers between the two numbers.

The conditional operator

The conditional operator is the only ternary operator, meaning that it uses three items! It is very similar to if/else; in fact, you can use if/else instead of the conditional operator in all cases.

Named unary operators

A unary operator takes one argument after the operator, and returns one value.

  • isnull returns a true value if the argument is null (has no value) and false otherwise
  • defined is the opposite of isnull--it returns true when the argument is defined and false if it hasn't been
  • new creates a new instance of the given classname; read more about this in the Classes section.
  • null creates an undefined variable of the given classname; chances are, you won't use this
  • reverse is used on strings and will return a copy of the given string with all the characters reversed
  • size takes an array and returns the number of elements in it
  • reverse takes an array and returns an array with all of the same items in reverse order

Operator precedence

Logic Flow


The if/else control statement is a good way to only run a bit of code if certain conditions apply.

The following pseudocode will execute the code inside the BLOCK if the EXPRESSION evaluates to true:


The following pseudocode example will execute the code inside BLOCK1 if the EXPRESSION evaluates to true, otherwise it will execute the code inside BLOCK2:


The following pseudocode example will execute the code inside BLOCK1 if EXPRESSION1 is true. Next, it tries to evaluate EXPRESSION2 and if that is true, it executes the code inside BLOCK2. (There can be more than one elseif statement in a row here.) Finally, if none of the expressions evaluate to true, the code inside BLOCK3 runs:


You can use a plain variable instead of an expression. Strings that have length with evaluate to try, and numbers that are not 0 will evaluate to true. Arrays that have objects in them evaluate to true, empty arrays evaluate to false.


The foreach control statement is a good way to apply the same code to each item in an array. The basic outline of the statement is this:


Each item takes a turn at becoming VARIABLE and running through the statements in BLOCK.

If the array is an associative array, the key of the array item becomes VARIABLE. If the expression being used is a string, each character will become VARIABLE.


In general, a function is given a list of variables (called arguments) runs a set of statements, and returns a variable. Some functions won't have any arguments, and some don't return a value.

Variables declared inside of a function are only available inside of that function. (This is called scope.)

You can use existing functions by calling them in a statement, or you can define your own functions.

Calling functions

You can call functions in statements. Examples:

# This statement calls a function with one argument and doesn't use
# any return value it may give back.  The arguments go
# inside of parentheses.
# This statement calls a function with no arguments.  Even though there 
# aren't any arguments, we still need the parentheses to call the function.
# This statement calls a function with three arguments; multiple 
# arguments are separated with commas.
my_function(2, "cows");
# You can call a function using variables as arguments, too!
my_function($greeting, $farewell);
# This statement calls a function with an argument and gets back a 
# value that it assigns to a variable
var int height = proportion(500);

Declaring and implementing functions

In order to declare a function, you'll need this information:

  • The name you want to give the function
  • The arguments the function takes, as well as the type of each argument
  • If the function returns a value, the type of that value

When you declare a function, you can also include a docstring after the rest of the declaration but before the ending semicolon of the statement. Doing this allows your function to be automatically documented when viewing information about a layer.

# This function doesn't return a value
function print_hello(string greeting);
# This function returns an integer
function get_height(int width) : int;
# This function is documented with a docstring
function print_image(string url, string alt, int width, int height)
  "This function prints out an image tag.";

However, you probably don't want to just declare a function, but also implement it! You can do that like this:

# This function returns a value
function get_height(int width) : int
"This function returns a height that is three times the given width."
    return 3 * $width;
# This function doesn't return a value
function greet(string greeting)
"This function prints out a greeting."
    print "Here is my greeting: $greeting";

If you're not dealing with a class function or built-in function (more on those later), you'll also want to implement your function when you declare it.

Built-in functions

Built-in functions aren't written in S2 but in Perl in the backend. They are then declared in a core layer using the builtin keyword. Example:

function builtin ehtml (string s) : string
"Escapes all HTML tags and entities from the text";


Declaring classes

class Mammal {
    var string voice;
    var int legs;

Using classes

Accessing class variables

If you're working inside of a class function and want to access the value stored in a variable belonging to the function, you can use $.classvar or $this.classvar.

If you have a variable whose type is of a certain class, and want to access a variable belonging to it, you can user $var.classvar.

Calling class functions

Extending classes

A class can be extended.

class Dog extends Mammal {
    var bool likes_cats;

Built-in classes