Tuesday 17 April 2018

egg "For" Statements

Recently, I got my first egg script running. Here it is:

  var s = 0;
  for (var i = 0; i < 100; ++i) {
    s += i;
  }
  print(s);

You'll be unsurprised to hear that this printed out "4950" (it was a pleasant surprise to me when it first happened, though, I can tell you!)

There are three things worth mentioning in this script.

Firstly, the "var" keyword initiates type inference for variables "s" and "i". In both cases, "int" is inferred (there are no unsigned integers in egg).

Secondly, the "print" function is a built-in method that will probably be removed, but is useful for testing, at the moment.

Finally, the syntax of "for" statements turns out to be non-trivial. Like C++, I adopted two forms:

  for (before ; condition ; step) { ... }
  for (iterator : collection) { ... }

The latter form is for iterating around collections, which we won't discuss here.

My main concern with the former form of the "for" loop is:
Which syntactic elements are valid for "before", "condition" and "step"?
The easiest of the three clauses is "condition". It's optional, but I only allow expressions that evaluate to Boolean values. This is similar to all the main curly-brace languages (C/C++/Java/JavaScript).

The "before" statement is also optional, but it must be a statement. This includes variable declarations: the scope of such variables is limited to the "for" statement, including the "condition" and "step" clauses. Again this is similar to the other languages (if we ignore JavaScript's problematic scoping rules).

The "step" statement is optional too, but cannot be a declaration. As mentioned previously, the increment and decrement operators are supported in egg purely to allow the classic for-loop idiom seen in this example.

But then I got a bit confused with which egg statements should be valid for "before" and "step". Can you use "break" and "continue"? If so, what do they do?

So I asked my C++ compiler, and it says that I cannot use "break" or "continue", but I can "throw" exceptions. The reason you cannot "break" or "continue" in "before" and "step" clauses is because those statements are just that: statements. The "before" and "step" clauses in C++ expect C++ expressions.

But why can you "throw" exceptions in those clauses in C++?

  for (auto i = 0; i < 100; throw "Bang!") {} // Valid C++

Well, it turns out that what I think of as throw statements are actually throw expressions (of type "void") in the formal syntax. It's a cul-de-sac that others have found themselves in too!

As egg is meant to be an easy-to-learn language, with few surprises, I decided to classify "throw" as a statement and explicitly forbid it in expressions and "before" and "step" clauses of "for" statements.

No comments:

Post a Comment