Examples

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

This page collects (in an unorganized manner) a number of mantra examples. See Examples tar for more.

The obligatory "hello world":

Code Block
println("hello, world!");

Iterate over and print the characters of a string:

Code Block
"abc":{char c|println(c);};

Define a dict and look up a value:

Code Block
dict phones = ["Ter"="x5707"];
println(phones["Ter"]);

You can iterate over ranges of a list or a subset of indexes without making a list copy:

Code Block
1..10:{int x|println(x);}; // or 1..10:println;
list a = ["a", "b", "c", "d", "e"];
a[1..3]:println;
list select=[1,4];
a[select]:println;

emits:

Code Block
1
2
3
4
5
6
7
8
9
10
b
c
d
b
e

List filtering:

Code Block
list a = ["Tom", "Ter", "Tim"];
a:{string n where n!="Ter" | return n;}:println;

List comprehension that does same thing:

Code Block
list a = ["Tom", "Ter", "Tim"];
list b = a:{string n where n!="Ter" | return n;};
b:println;

Define a field:

Code Block
class I {
   int a = 0;
}

and some overloaded methods

Code Block
class J {
        int foo() { return 34; }
        foo(int a) { ; } // no return type implies void
        foo(int a, char b) { ; }
}

Static methods and fields and constants (U.x, U.HEIGHT, and U.bar() are all statically resolvable--useful and efficient):

Code Block
class U {
    static int x = 3;
    int y = 0;
    const int HEIGHT = 100;

    foo() { y = -1; }
    static bar() { bar(4); }
    static bar(int a) { x = a; }
}

Here's an actor that reads from stdin and writes lines (minus \n) to stdout.

Code Block
package mantra::io;
class Lines implements Actor {
    main() {
        char c = read();
        while ( c isnt EOF ) {
            string s = mustring("");
            while ( c != '\n' && c isnt EOF ) {
                s += c;
                c = read();
            }
            write(s);
            c = read(); // read next char after \n
        }
    }
}

Then you can launch an instance of Lines as an actor (in a separate thread) and pipe to another actor implicitly created from a closure. The input to the actor gets passed as the parameter and the output is the return value:

Code Block
File("coffee") => Lines() => {string line | return line.split();};

Given file:

Code Block
3 parrt
2 jcoker
8 tombu

the code emits:

Code Block
[3, parrt][2, jcoker][8, tombu]

because all actors read from in and write to out, whatever they are set to. They start as stdin and stdout, but the pipeline overrides them temporarily. The last actor still has out==stdout.

The Actor entity is a "mixin" that acts like an abstract base class:

Code Block
mixin Actor {
    InputStream input = stdin;
    OutputStream output = stdout;

    object read() { return input.read(); }
    write(object o) { output.write(o); }

    /** To launch this object as an actor, create a thread and call this
     *  method.  By default, objects are not actors since this method does
     *  nothing.  It's like the main method for a shell program.  When
     *  main() returns, actor deactives again.
      */
    main() {;}
}

You can also redirect the stream to a list:

Code Block
list a = [];
File("coffee") => lines() => {string line | return line.split();} => a;
println(a);

emits:

Code Block
[[3, parrt], [2, jcoker], [8, tombu]]

A simple grep actor:

Code Block
/** Read object stream, convert to string, grep, pass along those objects */
class grep implements Actor {
    string regex = "";
    grep(string regex) { this.regex = regex; }
    main() {
        object o = read();
        while ( o isnt EOF ) {
            string s = o.toString();
            if ( s.matches(regex) ) {
                write(o);
            }
            o = read();
        }
    }
}

Sample usage: find parrt's consumption and split before grep showing it's still an object after passing through grep:

Code Block
File("coffee")
  => Lines()
  => {string line | return line.split();}
  => grep(".*parrt.*")
  => {list r | return r[0];} // get first column
  => println;

emits 3.

Some rudimentary OS support. Default stream is stdout from OS.system():

Code Block
mustring s = mustring("");
OS.system("pwd") => s; // store stdout into s
println(s);
Process p = OS.system("ps"); // system blocks until process terminates
println(p.getStdout());
println(p.getStderr());

Document word frequency histogram:

Code Block
// for each filename, generate a histogram
dict wfreq = dict();

for (string filename in args) {
    File f = File(filename);
    f => Words() => { string w |
    mutint c=wfreq[w];
    if ( c is null ) wfreq[w]=mutint(1);
    else c++;
    };
}

list pairs = wfreq.items(); // return list of 2-tuples (key/value pairs)
pairs.sort({int x, int y | return x[1].compareTo(y[1]);});
pairs.backwards():{list p | print(p[1]); print(" "); println(p[0]);};

An alternative way:

Code Block
dict wfreq = dict();

for (string filename in args) {
    File f = File(filename);
    list a = [];
    // f.lines() is not as interesting as f => lines because lines works
    // with anything that emits text.  f.lines() requires f to have a
    // lines method.  Better component-based programming.
    f.lines() => a;
    for (string line in a) {
        for (string w in line.split()) {
            mutint c=wfreq[w];
            if ( c is null ) wfreq[w]=mutint(1);
            else c++;
        }
    }
}

list pairs = wfreq.items(); // return list of 2-tuples (key/value pairs)
pairs.sort({int x, int y | return x[1].compareTo(y[1]);});
pairs.backwards():{list p | print(p[1]); print(" "); println(p[0]);};

Closures are amazing. Here is the string.trim() method:

Code Block
string trim() {
    // find first non whitespace from left edge
    func findFirstNonWhiteSpace =
        {char c where !(c==' '||c=='\n'||c=='\t'||c=='\r') | break i;};
    list r = this:findFirstNonWhiteSpace;
    int left = r[0];
    r = this.reverse():findFirstNonWhiteSpace;
    int right = size()-r[0]-1;
    return this[left..right].toString();
}

The same closure is used to get the index of first non whitespace moving from left to right and right to left. awesome. The closure precondition only executes "break i" when it sees a non whitespace char. The i variable is the implicitly-defined loop variable.

Accessing POJOs

It's easy to access any plain old Java object (POJO) using mantra. Just import the class using import java xxx; and then refer to it like any mantra class:

Code Block
import java javax.swing.JFrame;

JFrame f = JFrame();
f.pack();
f.setVisible(true); 

or

Code Block
import java java.util.Vector;

Vector v = Vector();
v.add("hi");
v.add(34);
println(v.toString());
println(v.get(0));
println(v.get(1));

Here is a POJO:

Code Block
import java.util.*;

/** testing the integration with Java; here is a class
 *  with fields and overloaded methods.
 */
public class POJO {
    public boolean b;
    public int i = 3;
    public String name = "Ter";
    public List names = new ArrayList() {{add("Frank"); add("Mary");}};

    public POJO() { ; }
    public POJO(int i) { this.i = i; }
    public POJO(String s) { this.name = s; }

    public void foo() { i=99; }
    public void foo(int i) { this.i = i; }
    public void foo(boolean b) { this.b = b; }
    public void foo(String s) { this.name = s; }

    public String toString() {
        return "[b="+b+", i="+i+", name="+name+", names="+names.toString()+"]";
    }
}

To access all of this, check out the following capabilities:

Code Block
import java POJO;

POJO p = POJO();
println(p);
p.foo();
println(p);
p.foo(1111);
println(p);
p.foo(true);
println(p);
p.foo("George");
println(p);

POJO p2 = POJO("Jim");
println(p2);

p.i = 18;
println(p.i);
println(p2);

p.names.add("Jimi");
println(p.names);