Tutorial #1. Fizz-Buzz.

Code updated to v0.0.2: added module imports.

Preparations

Setup VSCode environment as shown here: how-to-play-with-argentum-in-vscode.

Right-click on src folder and select new file:

Type fizz_buzz.ag

Question

Fizz-buzz is a famous coding interview question. Usually it sounds as follows:

Write to the console N lines for numbers from 1 to N.

If a number is divisible by 3 write the word "fizz" instead of the number.
If the number is divisible by 5 write the word "buzz" instead.
If the number is divisible by both 3 and 5 (like 15) write both words "fizz buzz".
Overwise write the number itself.

(One of possible forms of the fizz-buzz question).

Solution

We'll need to loop by the range of numbers and perform some string manipulations. Let's import this dependencies from other moodules:

using sys { String, StrBuilder, log }
using string;
using utils{ forRange }

Line "using sys { String; StrBuilder; log; }" declares a dependency on module sys and imports String and StrBuilder classes and the log function from this module.

So far Argentum has one built-in loop and a number of functions in utils module that makes more specialized loops.

forRange(1, 101, (i){
   log("fizz");
});

(BTW you can press Ctrl+Shift+B to build and run this example).

forRange is a function that takes:

  • The range boundaries (left - inclusive, right - exclusive)
  • A lambda that will be called for each integer in range.

Syntax (names){ code } defines lambdas.

There are other ways to define lambda:

names \ expression
names { expression }

If lambda is the last parameter of the function call, it can be passed outside ()

forRange(1, 101) i {
   log("fizz")
}
// or
forRange(1, 101) i \ log("fizz");
// or
forRange(1, 101, i \ log("fizz"));

All the above code just prints "fizz" 100 times.
Not what we needed, so let's add some more logic.

The sys module defines a StrBuilder class (and string module extends it). StrBuilder concatenates strings, characters, numbers, adds new lines, operates with text positions, and converts everything to the immutable string:

s = StrBuilder.putStr("Hello").putInt(42).putCh('!').newLine().toStr();
sys_log(s);

In this example:

  • Expression StrBuilder - creates a sys_StrBuilder instance,
  • put* methods and newLine method populate this string builder with different fragments,
  • toStr - resets builder and extracts its contents as a string.

Let's make use of the string builder in our fizz-buzz example:

b = StrBuilder;

forRange(1, 101) i {
   i % 3 == 0 ? b.putStr("fizz") : b.putInt(i);
   log(b.newLine().toStr());
}

This example shows the construction that looks and works like a ternary operator: A ? B : C;
But it is a little bit more than just a ternary operator. It is a pair of two binary operators: (A ? B) : C;

We'll look at these constructions deeper in a separate tutorial, and for now, let's just rewrite it this way:

b = StrBuilder;

forRange(1, 101) i {
   i % 3 == 0 ? b.putStr("fizz");
   b.putInt(i);
   log(b.newLine().toStr());
}

Construction A ? B executes B only if A is true.
So in this example we print fizz conditionally and append the number unconditionally.
At this point we know everything we need to write the correct code:

using sys { String, StrBuilder, log }
using string;
using utils{ forRange }

b = StrBuilder;

forRange(1, 101) i {
   i % 3 == 0 ? b.putStr("fizz");
   i % 5 == 0 ? b.putStr("buzz");
   b.pos == 0 ? b.putInt(i);     // if builder is empty, add a number
   log(b.newLine().toStr());
};

There are many other equally reasonable ways to solve this question:

using string;
using utils;

utils_forRange(1, 101, (i){
    b = sys_StrBuilder;
    i % 5 == 0
        ? b.putStr(i % 3 == 0 ? "fizzbuzz" : "fizz")
        : (i % 3 == 0 ? b.putStr("bazz") : b.putInt(i));
    sys_log(b.newLine().toStr());
});

Alternatively this can be done with itos function.
Right now Argentum stdlib doesn't have such function, let's define one:

fn itos(i int) String {
    StrBuilder.putInt(i).toStr()
}

This function takes an integer argument and returns a sys_String object (this is the same string type as "Quoted" string literals).

Please pay attention to the absence of ; at the end of the function body. The last expression in the function body generates the function result. And ; creates an empty expression returning void. So if ; were added here, compilation would fail with "expected String, not void" error message.

The fizz-buzz solution could be rewritten using this itos function:

using sys { String, StrBuilder, log }
using string;
using utils{ forRange }

fn itos(i int) String {
    Builder.putInt(i).newLine().toStr()
}

forRange(1, 101) i {
    log(i % 5 == 0
        ? (i % 3 == 0 ? "fizzbuzz\n" : "fizz\n")
        : (i % 3 == 0 ? "buzz\n"     : itos(i)));
}

So this is it for now. See ya in the next tutorials.

3 Comments

  1. Good, this language can do loops and conditions.
    What about data structures, especially ones that are not trees?
    What about pathfinding in a graph with loops?

Leave a Reply

Your email address will not be published. Required fields are marked *