Learn

Introduction

Learning how to code applications with Snap is easy, particularly if you have experience with Java, Javascript, or a similar language. Below you will find various sections illustrating the basics, where you will learn about types, functions, and the various statements and expressions that can be used. For a more in depth understanding feel free to have a look at the assortment of games, applications, and tests that have been written in the language here. To play with these examples you can download the IDE from here and run them.


Basic Types

For programs to be useful, we need to be able to work with some of the simplest units of data such as numbers, strings, structures, boolean values, and the like. Support for these basic types is much the same as you would expected for Java, with some additional features such as string templates, map, set, and list literals.

In order to reference values they must be associated with a variable. Variables are declared with the keyword var or const. A variable can have an optional constraint by declaring a type. If constrained a variable can only reference values of the declared type.

var v = 22; // v can reference any type
var i: Integer = 22; // i can only reference integers
var d: Double = 22.0; // d can only reference doubles
const c = 1.23; // c is constant, it cannot change

Booleans

The most basic type is the simple true or false value, which is called a boolean value.

var a = true; // value a is true
var b = false; // false
var c = Boolean.FALSE; // type constraint of Boolean
var d: Boolean = Boolean.TRUE; // like Boolean d = Boolean.TRUE
var e = Boolean.FALSE; // like Object e = Boolean.FALSE

Numbers

The most basic type is the simple true or false value, which is called a 'boolean' value.

var binary = 0b0111011; // binary literal
var hex = 0xffe16; // hexidecimal literal
var int = 11;
var long = 11L;
var double = 0.5d;
var float = 12.9f;
var typed: Integer = 22; // integer value 22
var coercion: Double = "1.234e2"; // coercion of string to double

Strings

A fundamental part of creating programs is working with textual data. As in other languages, we use the type string to refer to these textual types. Strings are represented by characters between either a single quote or a double quote. When characters are between double quotes they are interpolated, meaning they have expressions evaluated within them. These expressions start with the dollar character. All strings can span multiple lines.

var string = 'Hello World!'; // literal string
var template = "The sum of 1 and 2 is ${1 + 2}"; // interpolated string
var concat = "The sum of 1 and 2 is " + (1 + 2); // concatenation

Arrays

The most basic type is the simple true or false value, which is called a 'boolean' value.

var array = new String[10]; // array of strings
var bytes = new Byte[11]; // primitive byte[11]
var byte = array[1]; // reference element in array
var matrix = new Long[10][22]; // multidimensional long[10][22];
var long = matrix[2][3]; // reference multidimensional

Collections

Complex data structures can be represented with a simple and straight forward syntax. Collection types found in Java such as maps, sets, and lists can be represented as follows.

var set = {1, 2, "x", "y"}; // creates a LinkedHashSet
var list = [1, 2, 3]; // creates an ArrayList
var map = {"a": 1, "b": 2}; // creates a LinkedHashSet
var empty = {:}; // creates an empty map
var mix = [1, 2, {"a": {"a", "b", [55, 66]}}]; // mix collection types

Operators

Operators are special symbols that perform specific operations on one, two, or three operands, and then return a result. They are typically used to manipulate or compare values.


Arithmetic Operators

Arithmetic operators are used in mathematical expressions in the same way that they are used in algebra.

var a = 10;
var b = 20;
var c = a + b; // add is 30
var d = b - a; // subtract is 10
var e = b / a; // divide is 2
var f = a * b; // multiply is 200
var g = b % a; // modulus is 0
var h = a++; // a is 11 and h is 10
var i = b--// b is 19 and i is 20
var j = --a; // a is 10 and j is 10
var k = ++b; // b is 20 as is k

Relational Operators

Relational operators are used to make comparisons, such as equal to, not equal to, greater than, less than.

var a = 10;
var b = 20;
var c = a == b // equal operator, c is false
var d = a != b; // not equal operator, d is true
var e = a > b; // greater than operator, e is false
var f = a < b; // less than operator, f is true
var g = a <= b; // g is false
var h = a >= b; // h is true

Bitwise Operators

Bitwise operators are used to manipulate numbers, typically integers, at the byte level. They do so by change the binary representation of the value.

var a = 0b00111100;
var b = 0b00001101;
var c = a & b; // bitwise and, c is 00001100
var d = a | b; // bitwise or, d is 00111101
var e = a & b; // bitwise xor, e is 00110001
var f = ~a; // f is 11000011
var g = f >> 2; // f is 00110000
var h = f << 2; // h is 11000000
var i = f >>> 2; // unsigned shift, i is 00110000


Logical Operators

Logical operators are typically used to combine multiple relational operations in to a single boolean result.

var a = 1;
var b = 3;
var c = true;
var d = false;
var e = a && b; // e is false
var f = a || b; // f is true
var g = !d; // not operator, g is true
var h = b > a && a == 1; // logical and of, h is true
var i = b > a && a != 1; // i is false

Conditions

Conditional statements are used to perform different actions based on different conditions.


If Statement

The if statement is used to specify a group of statements to execute if a statement is true.

var a = 2;
var b = 3;

if(a < b) { // true
   println("a > b"); // prints as a < b
}

Else Statement

The else statement is used to specify a group of statements to execute if a statement is false.

var a = 2;
var b = 3;

if(a >= b) { // false
   println("a >= b");
} else {
   println("a < b"); // prints as a < b
}

Conditional Operator

To make statements more concise there is a conditional operator.

var a = 2;
var b = 3;

println(a >= b ? "a >= b" : "a < b"); // prints a < b

Loops

Loops are used to perform a group of statements a number of times until a condition has been satisfied.


While Statement

The while statement is the simplest conditional statement. It repeats a group of statements while the condition it evaluates is false.

var n = 0;

while(n < 10) { // conditional loop
   n++;
}

For Statement

The for statement is typically used to count over a range of numeric values. It contains three parts, a declaration, a condition, and an optional statement which is evaluated at the end of the loop.

for(var i = 0; i < 10; i++){ // loops from 1 to 10
   if(i % 2 == 0) {
      continue; // continue loop
   }
   println(i);  // prints only odd numbers
}

For In Statement

The for in statement offers a simpler way to iterate over a range of values, a collection, or an array.

var list = [35, 22, 13, 64, 53];

for(var e in list){ // iterates over the list
   println(e);
}

for(var e in 0..9) { // iterates from 0 to 9
   if(e == 7) {
      break; // exit loop when e is 7
   }
   println(e); // prints from 0 to 6
}

Loop Statement

The loop statement offers a way to specify an infinite loop, it does not evaluate any condition.

var n = 0;

loop { // infinite loop
   if(n++ > 100) {
      break;
   }
}

Exceptions

Exceptions are used to indicate an error has occurred. It offers a simple means to return control to a calling function, which can then handle the error. Typically an exception object is thrown, however it is possible to throw any type.


Catch Statement

In order to catch an exception the throwing statement needs to be wrapped in a try catch statement. This statement basically allows the program to try to execute a statement or group of statements, if during execution an exception is thrown then an error handling block is executed.

try {
   throw new IllegalStateException("some error");
} catch(e: IllegalStateException) {
   e.printStackTrace();
}

Finally Statement

The finally statement is a group of statements that are always executed regardless of whether an exception is thrown..

try {
   throw "throw a string value";
} catch(e) {
   println(e);
} finally {
   println("finally always runs");
}

Functions

Functions group together control structures, operations, and method calls. These functions can then be called when needed, and the code contained within them will be run. This makes it very easy to reuse code without having to repeat it within your script.


Declaration

The most basic type of function is declared with a name and a specific number of parameters. Such a method can then be called using the declared name by passing in a right number of arguments.

var r = max(11, 3, 67); // r is 67

function max(a, b) {
   return a > b ? a : b;
}

function max(a, b, c) { // function overloading
   return a < b ? max(a, c) : max(b, c);
}

Type Constraints

In order to bind invocations to the correct function implementation it can be declared with optional type constraints. These type constraints will ensure that variables of a specific type will be bound to the correct implementation.

var x: Double = 11.2;
var y: Integer = 11;
var z: String = "11";

f(x); // prints double 11.2
f(y); // prints integer 11
f(z); // prints string 11
f(true); // type coercion to string, prints string true

function f(x: Integer) {
   println("integer ${x}");
}

function f(x: Double) {
   println("double ${x}");
}

function f(x: String) {
   println("string ${x}");
}

Variable Arguments

At times it can be useful to provide a large number of arguments to a function. To achieve this the last parameter can be declared with a variable argument modifier.

var result = sum(0, 13, 44, 234, 1, 3); 

function sum(offset, numbers...){ // variable arguments
   var size = numbers.size();
   var sum = 0;
   
   for(var i = offset; i < size; i++){
      sum += number;
   }
   return sum;
}

Closures

A closure is an anonymous function that captures the current scope and can be assigned to a variable. This variable can then act as a function and can be called in the same manner.

var square = (x) -> x * x;
var cube = (x) -> square(x) * x;

cube(2); // result is 8

var printAll = (values...) -> {
   for(var e in values) {
      println(e);
   }
}

printAll(1, 2, 3, 4); // print all values

Types

In any substantial application types are required. A type is basically a way to define an encapsulate variables and functions within a named scope.


Class

A class is the most basic type. It contains variables and functions that can operate on those variables. Once declared a type can be instantiated by calling a special function called a constructor.

class Circle {
   
   private static const PI = 3.14; // enclosed variables
   private var radius;
   
   new(radius) { // constructor
      this.radius = radius;
   }
   
   area() {
      return PI * r * r;
   }
   
   diameter() {
      return 2 * r;
   }
}

var circle = new Circle(10);

circle.area(); // calculate area


Enumerations

An enumeration is a type that specifies a list of constant values. This values are constant and are instances of the enum they are declared in.

enum Color {
   RED("#ff0000"),
   BLUE("#0000ff"),
   GREEN("#00ff00");
   
   var rgb;
   
   new(rgb) {
      this.rgb = rgb;
   }
}

var red = Color.RED;
var blue = Color.BLUE;


Traits

A trait is similar to a class in that is specifies a list of functions. However, unlike a class a trait does not declare any variables and does not have a constructor. It can be used to add functions to a class.

trait Format
   format(a);
}

class BoldFormat with Format{
   
   override format(a) {
      return "<b>${a}</b>";
   }
}

class ItalicFormat with Format {
   
   override format(a) {
      return "<i>${a}</i>";
   }
}

Integration

To leverage the large array of frameworks and services available on the Java platform any Java type can be instantiated, and any Java interface can be implemented.

class DoubleComparator with Comparator{

   override compare(a,b){
      return Double.compare(a,b);
   }
}

var comparator = new DoubleComparator();
var set = new TreeSet(comparator);

set.add(1.2);
set.add(2.3);
set.add(33.4);
set.add(4.55);
set.add(2);

for(var entry in set){
   println(entry);
}

Coercion

For interfaces that have only a single method a closure can be coerced to that interface type. This makes for a much simpler and concise syntax similar to that offered by Java closures.

var set = new TreeSet((a,b)->Double.compare(a,b));

set.add(1.2);
set.add(2.3);
set.add(33.4);
set.add(4.55);
set.add(2);

for(var entry in set){
   println(entry);
}

Import

In order to access the Java types available they can be imported by name. Once imported the type can be instantiated and used as if it was a script object. In addition to importing types, functions can also be imported by using a static import.

import static lang.Math.*; // import static functions
import security.SecureRandom;

var random = new SecureRandom(); // create a java type
var a = random.nextInt(40);
var b = random.nextInt(40);
var c = max(a, b); // Math.max(a, b)

println(c); // prints the maximum random

Module

A module is collection of types, functions, and variables. It is similar to enclosing a script within a named type. Modules are useful in providing constructs such as singletons.

module ImageStore {

   private const cache = {:};
   
   public find(name) {
      return cache.get(name);
   }
   
   private cache(name, image) {
      cache.put(name, image);
   }
}