CrashCouse – 001 – Hello World!

In this series I shall be exploring the capabilities of Z2, giving a hopefully comprehensive tour of the language features and design implications, without going into the full depth of these features. Full details are reserved for documentation and the specification documents, while this series is a more casual approach to presenting the language to a new audience. In fact, in the first few parts of the series I will need to go so fast that some concepts warranting multiple posts will only be introduced using only a phrase or two, leaving further explanations for later. And during the first few posts, one might have difficulty in clearly identifying what Z2 is all about and what it brings new to the table. Z2 is not about introducing radical new ways to solve real world problems. It is also not about a few large “killer” features that can be easily summarized on a single PowerPoint slide. It is more about systematically improving upon existing features and programming styles in subtle ways. It is about the consistency of applying these tweaks to existing patterns and seeing what it all adds up to.

Z2 has a lot in common with C++. It tries to solve the same problems using a similar style, but it is an attempt at a more sanitized language, where every single design element is the result of years of real world experience with C++ and other programming languages, solving real world problems. In consequence it is a language designed to be practical, emphasizing features that are considered useful and de-emphasizing and sometimes downright eliminating undesirable features. Z2 is still a complicated language, but it is complicated because it has a lot of features, not because it has a lot of features with complicated rules, that have a lot of exceptions and idiosyncrasies and which sometimes interact poorly with each other. Z2 tries to have simple and consistent rules, with a focus on avoiding ambiguity, generally having one syntax to achieve a goal and it tries to minimize exceptions and caveats to rules.

Now that this brief introduction is done with, it is time to start with the traditional “hello world” snippet:

namespace org.z2legacy.ut;

class HelloWorld {
	def @main() {
		System.Out << "Hello World!\n";

The syntax highlighting does not fully understand Z2, but at least the text can be selected.


The problem with embedding Z2 code into posts is that WordPress’ syntax highlighters do no support it. The Z2 compiler can actually output properly syntax highlighted HTML code, but editing documents with huge embedded HTML snippets is kind of cumbersome, so for now I shall be using the default WordPress code highlighter.

In this particular sample, keywords and some identifiers are not properly highlighted, neither is the String constant. When editing code we use an IDE that supports Z2, called ZIDE. For comparison I will now show the same snippet as it is displayed in ZIDE:


The “hello world” sample is always a very simple one used as a quick introduction of the language features. We can use it to make some basic assumption about the language.

The “class” keyword introduces a class. Z2 is a pure object-oriented language, meaning that all entities one manipulates are objects, instances of a class. Classes must belong to namespaces. Our first class called HelloWorld belongs to the namespace called org.z2legacy.ut, thus the full name of the class is org.z2legacy.ut.HelloWorld. Namespaces are used to prevent name clashes between public symbols. There can be only one org.z2legacy.ut.HelloWorld and the compiler will complain if finding multiples of this class, but you can have as many classes named HelloWorld in the same project as you wish, as long as they are in different namespaces.


Earlier versions of Z2 had optional namespaces: you could declare classes outside of a namespace. After a while it became apparent that clashes were unavoidable even in medium sized projects and namespaces were made mandatory.

If you are upgrading from older versions of Z2 and find that your classes no longer compile, check to see if they are inside a namespace.

The “def” keyword introduces a member function. The function’s name is “@main”. The ‘@’ character can only be used as the first character of an identifier and acts pretty much as the underscore character (‘_’) found in most other programming languages. Members that start with ‘@’ called slots. They are normal class members, with no other special conditions and requirements, but the compiler can use them to achieve several goals. If the name and signature of such a member matches a certain goal, the compiler can and will use it. Operator overloading and out of the box marshalling of user classes are two examples of the compiler automatically using such methods. The official specification (once it is done) will of course include the full list existing slots and their use. One can add new slots too. Existing classes are always available to be “reopen”, so one can retroactively enhance the standard library with features using a third-party library. Using this approach it is possible to blur the line between a language feature and a library feature.

When Z2 compiles a file or a package, it needs to start the execution of the program somewhere: the main method. Since the language already has a mechanism of denoting members as having an additional use, the main method is called “@main”, not “main”. It was not an easy choice to change this, since traditionally this method has been called “main” for decades now. In the end out commitment to not having the language have unnecessary exceptions to rules won and we changed it to “@main”.

Imagine the scenario of someone teaching Z2 to somebody else:

Members starting with ‘@’ can be used as special meaning members by the compiler.
The compiler gives special meaning to one of the functions in a class and uses it as a start-up point of the execution.
This special function is called “main” (not “@main”).

Contradiction! Z2 is carefully designed to have as few contradictions and caveats to rules as possible.

Packages can contain multiple classes of course, and multiple classes might have a “@main” method. When invoking the compiler, you need to point to a start method, by either pointing it to the path of a source file containing a class with a “@main” method, or by directly giving it the name of the class, including the namespace.

Z2 uses a project package and project system to handle builds of arbitrary complexity, so you can store your start-up point the project options to not always have to supply it to the command line tool. The default project file will have a lot of defaults for many options and it will attempt to create an executable out of you choice of packages. Thus by default compilation will fail if the compiler is not pointed to a class with a “@main” method. The compiler will gracefully exit, telling you that you asked it to create an executable, but did not provide a start-up point. Then it will list all possible start-up points so that you can fix this problem. And naturally, when the project is set up in such a way to produce one or more static/dynamic libraries, no start-up point is needed.

I wanted to explain this feature a bit because Z2 is both a compiler and a quite complex build tool. It can build projects of arbitrary complexity. But for our simple example, supposing you are using ZIDE, our Z2 IDE that is included in all builds, we don’t need to worry about this. ZIDE will pass in the class in the currently opened file to the command line compiler, so if you have “HelloWorld.z2” open in ZIDE. All you need to do is press F5 and you executable will be build and ran.

Using the mechanism described above, a method called “@main” from a class (“Hello” in this case) will be used as a start-up point. This means that a new instance of said class is created using a constructor and the “@main” method is called. After the execution of the method, a destructor is called. Depending on compilation flags, several diagnostic steps can be run, especially in “debug” mode builds. A memory leak warning is turned on by default in all builds. Finally the program exists. The use of a constructor and destructor means that the start-up class must have a public default constructor and a destructor. Z2 is not in the habit of making you write code it can figure out on its own, so you do not need to write a constructor or a destructor. In this case the code generated for both is of course literary nonexistent. There are zero assembly instructions required to construct or destroy such a simple class as “HelloWorld”.

One thing that is not apparent from this sample is another set of the less than ideal features of C++ that Z2 tries to fix: the lack of a module support, the need of declarations and definitions, the need of forward declarations and finally the need for the dreaded pre-processor, all of these just so that the compiler can find the definitions it needs. Z2 has strong module support, together with text or binary modules. There is no such concept as a forward declaration and there are no problems with finding declarations. Z2 uses the following principle: if a person using formal dependency analysis with a pen and paper in hand can reach the conclusion that the definition of a given entity should be visible to another entity, so can the compiler, so it just works! You don’t need to take special care, use special orders and generally spend any time babysitting “include” files from various sources, as one does in C/C++. There is no pre-processor that is completely unaware of the rules of the language in Z2, but there is conditional compilation if needed.

Finally, we reach the statement that prints "Hello world!\n" to STDOUT and we see that some small parts of the standard library are available in all source files without the need to have their definition “imported” using the “using” keyword. The list of default classes that are visible is fairly short and mostly includes only the System class and the classes for fundamental types, like Int, Float, Vector, String and so on.

This concludes the first episode of the CrashCourse! I am sorry I had to use such a drive-by approach at introducing concepts, but there is much to say as an introduction and I would like to have each post reasonably short. I mentioned in passing the whole “pure OOP” design decision, so next time I shall talk more about the object model Z2 uses and detail some implications of this design.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s