I started to play around with the Mono C# compiler. Since all my previous experience with C# has been just passive (i.e. reading tutorials), I started with something very simple: a class implementing a generic doubly linked list. (It's completely brain dead, but should be sufficient for this example.)
I thought it would be fun to convert it to an alternative syntax, so here it is. Note for example the syntax for type parameters. I also added some more specific ideas, like translatable strings with annotations, Python-like for loop, or the with-except-finally statement. The snippet is rather long, which is good, as it should deliver a more authentic experience. For the most part, this a transcription of real C# code, while some of it is completely constructed. If you don't know C# please be careful not to credit me with its inventions.
What I like about this syntactic style is that it avoid C#'s sort of 'German' word order. Public static override void ... wait, where was I? Here, the name of the object being declared is reasonably close to the beginning (just the second word). Also the first word let's us know what kind of object we are dealing with (function, variable, class, etc.).
My fingers didn't really object. Even though '
end' has three characters while '
}' has one, short keywords are actually easier to write than special symbols which require Shift to type. My eyes were O.K with it, too -- each declaration is visibly anchored and appears to be balanced. So I am reasonably happy with this creation.
What about
you? Do you like it?
## Generic list type.
#
# Really just an example of program syntax style. This list can be
# appended to or prepended. It implements an enumerator and an
# indexer. Backwards or random-direction iteration is not possible.
#
# This class has one generic parameter (t), implements the
# IEnumerable interface. t is subject to the constraint t : class
# (t is a reference type) and the class MyList't is public.
#
# Note that this is meant only to demonstrate syntax style and
# it's almost 1-1 translation of a C# program. (But some special
# syntactic ideas are also demonstrated.
#
class MyList't : IEnumerable, where t : class, public is
class Node, protected is
var prev, next : Node, public;
var data : t, public;
constructor(new_data : t), public is
data = new_data;
end
fun insertBetween(a, b : Node), public is
prev = a; next = b;
a.next = this; b.prev = this;
end
end
var head : Node, public;
constructor(), public is
head = new Node(null);
head.prev = head;
head.next = next;
end
fun append(data : t), public is
var e : Node;
e = new Node(data);
e.insertBetween(head.prev, head);
end
fun prepend(data: t), public is
var e : Node = new Node(data);
e.insertBetween(head, head.next);
end
fun printNodes(), public is
for data : t in this do
Console.writeLine(data.toString());
end
end
fun getLength() : int, protected is
var len : int;
len = 0;
for data : t in this do
len += 1;
end
end
## Get the node at the specified index.
#
# @param pos Index (0 = first, 1 = second, etc)
# @return Node at the specified position.
#
fun getNodeAt(pos : int) : Node, protected is
var e : Node;
var i : int;
i = 0;
e = head.next;
while true do
if e == head then
raise new Exception();
end
if i == pos then
break;
end
i += 1;
e = e.next;
end
return e;
end
## Number of nodes in the list.
#
# Property - looks like a member variable, but assigning
# to it or reading from it can have side effects.
#
prop length : int, public is
get is
return getLength();
end
end
## Indexer
#
# This a simpler variant of [] operator overloading. Here
# we can define the effects of reading from / writing to
# an object of this class with index (e.g. list[3]).
#
prop this[pos : int], public is
get is
return getNodeAt(pos).data;
end
set is
getNodeAt(pos).data = value;
end
end
fun toString() : string, public, override is
var s, sep : string;
s = ""; sep = "";
for data : t in this do
s = s + sep + data.toString();
sep = ",";
end
return "[" + s + "]";
end
generator is
var e : Node;
e = head.next;
while e != head do
yield e.data;
end
end
end
#
# An example how a variadic function might be declared (var
# attribute). The + means that the argument must not be null.
# The whole piece of code is disabled using a multi-line 'comment'
# block. Only single-line comments are meant to be used for comments
# per se, while multi-line blocks are meant for disabling sections
# of code quickly.
#
#{
class PrintFormatted, public is
fun format(fmt : +string; args : (+object)[], var) : string is
...
end
end
#}
class Test is
fun Main(args : string[]), public, static is
# Using a generic class
var list : MyList'string;
# Translatable string literal.
Console.writeLine("Hello World!"@);
# Translatable strings with annotations (these
# are used when have equal strings which are to
# be translated differently.
Console.writeLine("bug"@software);
Console.writeLine("bug"@insect);
list = new MyList'string();
list.append(1.toString());
list.append("hello"@greeting);
Console.writeLine("Objects in list:"@);
# It's really better always to iterate over some
# list. We don't need a C-style for(;;) so no need
# to call this foreach.
for o : string in list do
Console.writeLine("Node " + o);
end
# Instead of for (i = 0; i < 10; ++i)
for i : int in range(0, 9) do
Console.writeLine(i);
end
#
# It would be possible to combine a context-
# management statement with a try block. So,
# try/except/finally can be thought of as a special
# case where we do not need to guard any resources
# with the 'with' statement.
#
with f : TextFile = TextFile.OpenFile("test.txt") do
# If any exception happens here, f is cleaned up
# gracefully via f.dispose() (or similar)
var line : string = f.readLine();
Console.writeLine(line);
except e : Exception do
# And likely we also want to handle the exception
Console.writeLine("Error reading file.");
finally
Console.writeLine("Done");
end
end
end