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:

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

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

Note
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:

01_01

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 can belong to namespaces, but for this sample I am not using a namespace. Z2 permits the declaration of classes outside of an explicit namespace and such classes are part of the implicit/default namespace. Declaring classes in the implicit namespace is no recommended because it can lead to class name clashes. Inside a given namespace, all class names must be unique.

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 ‘@’ 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 marshaling 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 of such members that are used for special purposes and third-party libraries can add new items to the list. 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 startup point of the execution”. “This special function is called “main” (not “@main”). Contradiction!

Additionally, packages can contain multiple classes of course, and multiple classes might have a “@main” method. If there is only one “@main”, that method is always picked. If there are multiple, you can specify the desired class to be used as a startup class as a command line parameter when using the command line compiler or using ZIDE (which simply forwards the option to the command line compiler). Project files can store this option so you do not need to specify it at each compilation. If the option is not specified in the command line for the compiler or it is not part of the project file, when running the executable, it will prompt you to choose the class you wish to use as startup. This prompt happens logically before the startup point, at a point in time when the classes in your project can be considered to not exist yet, so there is no risk of programs with multiple startup points behaving differently once an option is chosen at run time versus programs with an explicit startup point chosen at compile time. But the executable size will be bigger since multiple classes must be compiled and included into the executable.

Using the mechanism described above, a method called “@main” from a class (“Hello” in this case) will be used as a startup 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 startup 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 “Hello”.

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.

Advertisements

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s