This manual describes how to get the most from Paja programming in a minimum amount of time.
In Paja, genericity is provided through parametric classes.
Suppose you have to write a parameterized (generic) version of a Stack class. Below lies the Paja code of a straightforward implementation of such a class. The type of contained objects, Elem, is found right after the class name, enclosed in =< >= 'braces'.
public class Stack=<Elem>= {
private Elem[] v = new Elem[100]; // static vector containing the elements
private int top=0; // top of stack
public void push(Elem e) {
v[top++] = e;
}
Elem pop() {
return v[--top];
}
}
In order to use specific instances of the parametric stack we have created, one has just to give the effectives parameters of the class (types!). Here is an example of such a use:
...
Stack=<String>= s;
s = new Stack=<String>=();
s.push("one");
s.push("two");
System.out.println(s.pop()); // prints two
System.out.println(s.pop()); // prints one
...
This can be done by specifying a bound to those parameters. In the piece of code below, the elements of HashingSet are required to implement Hashable.
interface Hashable {
long getHashValue();
}
class HashingSet=<Elem extends Hashable>= {
...
put(Elem e) {
long key=e.getHashValue();
...
}
...
}
Knowing that Elem implements Hashable somehow, the compiler is able to valid theThe features introduced above should suffice for daily use of genericity.
However, Paja has a few neat features giving the full power of genericty
to java users.
Coming directly from the YAFL world, this feature allow to write most of the
methods
working on a range of parametric type without parameterizing themselves.
As an example, imagine that you need a method that swaps the two elements on
top of a stack.
You'll notice that there is absolutely no need to know their exact type to do
that.
The clean way would be to include the method in the generic stack class.
However, this might not
always be possible, so Paja proposes to "omit" the parameter, as shows
the following example.
class Main {
...
void swap(Stack s) {
s.Elem e1, e2;
e1 = s.pop();
e2 = s.pop();
s.push(e1);
s.push(e2);
}
}
Please note the way we can reference the type of the elements of the stack s.When the above mechanism is not sufficient, something more pedantic is
needed.
Imagine we need to swap the top elements of two stacks. Of course, it is
required that the two stacks have the same element type.
This is written as such:
class Main {
class Stacks=<Elem>= {
static void swapTops(Stack=<Elem>= s1, Stack=<Elem>= s2) {
Elem e1, e2;
e1 = s1.pop();
e2 = s2.pop();
s1.push(e1);
s2.push(e2);
}
}
...
void f() {
Stack=<String>= s1, s2;
Stacks=<String>=.swapTops(s1, s2);
...
}
}
Note that, even if use of type parameters is allowed in static methods, it is
NOT allowed
it static fields!
This is the natural extension of bounded parameters, where bounds can be
functions of the
parameters.
A useful example follows.
interface Comparable=<T>= {
bool isGreaterThan(T t);
}
class Vector=<T>= {
...
}
MyString implements Comparable=<MyString>= {
...
}
class OrderedVector=<T extends Comparable =<T>=>= // F-bound!
{
void sort() {
T t1,t2;
...
bool b = t1.isGreaterThan(t2); // ok, because T extends Comparable=<T>=
...
}
}
class Main {
...
OrderedVector=<MyString>= v; // ok, because MyString implements Comparable=<MyString>=
...
v.sort();
...
}
The distribution constains a paja.util package, which implements a parametric Collection library. That collection library is closely designed after java.util collections suite, so you should have no problem with it once you are familiar with the non-parametric library.
The thing you want to know is that the actual implemented classes and interfaces are
Please note that those classes are not serializable (yet).