# The Pearls of Raku, Issue 4: unit sub MAIN and command line, round and precision

Welcome to the next issues if The Pearls of Raku! Today, some interesting findings that I discovered while reviewing the previous weeks of The Perl Weekly Challenge and today when I added a new graph to The Coronavirus Observer.

Welcome to the next issues if The Pearls of Raku! Today, some interesting findings that I discovered while reviewing the previous weeks of The Perl Weekly Challenge and a thing that I used for the first ever time when I added a new graph to The Coronavirus Observer.

## unit sub MAIN

The `unit sub MAIN` construct makes the rest of the file the body of the `MAIN` function. In other words, it gives a handy way to declare parameters of your program and to restrict its values.

Imagine a command-line calculator that you run as:

`\$ ./calc.raku 42 + 5`

You want to make sure that the first and the third arguments are integers, and there is a sign of the operation in between.

Here is a possible solution in Raku (maybe a bit exaggerated just for the sake of demonstration).

```my Int \$a = +@*ARGS.shift;
subset OpStr of Str where /<[-+*/]>/;
my OpStr \$op = @*ARGS.shift;
my Int \$b = +@*ARGS.shift;

say (given \$op {
when '+' {\$a + \$b}
when '-' {\$a - \$b}
when '*' {\$a * \$b}
when '/' {\$a / \$b}
})```

The highlighted part is where you get the arguments and indirectly validate them.

If you convert the code to a function, you can use function’s signature to check the arguments for you. In the case of a simple script with the only function, use `unit sub MAIN`:

```unit sub MAIN(Int \$a, Str \$op where /<[-+*/]>/, Int \$b);

say (given \$op {
when '+' {\$a + \$b}
when '-' {\$a - \$b}
when '*' {\$a * \$b}
when '/' {\$a / \$b}
})```

Also notice the difference in error reporting between these two programs. In the first case, an exception happens:

```\$ raku calc1.raku 42 plus 3
Type check failed in assignment to \$op; expected OpStr but got Str ("plus")
in block <unit> at calc1.raku line 3```

In the second case, you get a usage message:

```\$ raku calc2.raku 42 plus 3
Usage:
calc2.raku <a> <op> <b>```

P. S. Note that you can only use the trick with `MAIN`. For other functions, you get an error:

```A unit-scoped sub definition is not allowed except on a MAIN sub;
Please use the block form. If you did not mean to declare a unit-scoped sub,
perhaps you accidentally placed a semicolon after routine's definition?```

## round

An interesting thing you may skip in the documentation is that the `round` routine takes an optional `scale` parameter. You can use it to set the number of digits after the decimal point, for example.

Round the value of π:

`say pi.round; # 3`

Now, print one, two, or three digits after the decimal point:

`say pi.round(0.1);   # 3.1say pi.round(0.01);  # 3.14say pi.round(0.001); # 3.142`

But that’s not all! Do you want to get only an odd number as a result? Round the value to a multiple of 2:

`say pi.round(2); # 4`

Set the scale to 5 or 10 and round it to a number which is a multiple of these numbers:

```say pi.round(5);  # 5
say pi.round(10); # 0```

You can work with big non-round numbers too. Say, let’s round the World population to see billions only:

```my \$population = 7_802_279_546;
say \$population.round(1_000_000_000); # 8000000000```

And that’s it for now. You can find the source codes of this issue on GitHub.