Improvements Over MiniCalc
Tusk offers many improvements over MiniCalc.
Overall, Tusk is much more similar to Delphi
than MiniCalc is,
as discussed in many of the following sections.
Perhaps the single most important difference
between Tusk and MiniCalc is that Tusk offers
parse-time checking of numerous issues that MiniCalc
checks only at runtime.
For example, if an identifier is misspelled,
or a function is called with the wrong number
of arguments, Tusk catches these problems before
running any code.
MiniCalc finds these issues only if/when the
program attempts to execute the deficient
statement.
In MiniCalc, everything is a Variant.
In Tusk, this is also true, at least at runtime.
However, at parse time, Tusk has a robust type
system…
- Functions declare their return type.
- Procedure / function arguments specify a data type.
- Constants and variables are of a declared data type.
- Implicit type casts are safe (such as Char to string or Integer to Int64), while unsafe conversions require an explicit function call (such as string to TDateTime or Double to Byte).
MiniCalc uses dynamic scoping,
while Tusk and Delphi use static (lexical) scoping.
For example, consider this MiniCalc code…
const
a = 10;
function f;
begin
@Writeln(a);
end;
function Demo;
const
a = 99;
begin
f();
end;
Demo();
The above code prints 99.
In contrast, the following (nearly identical)
Delphi code prints 10…
const
a = 10;
procedure f;
begin
Writeln(a);
end;
procedure Demo;
const
a = 99;
begin
f;
end;
Demo;
The above Delphi code also works unchanged in Tusk,
and prints the same value.
Tusk offers a dedicated operator, unary /,
for accessing global identifiers.
MiniCalc has no such facility,
but uses a convention of naming global
functions and constants with a prefix of @.
This is rather messy, as it makes MiniCalc code
look different from Delphi code…
x := @Sqrt(@Abs(x) - @Ln(y) * @Pi);
x := Sqrt(Abs(x) - Ln(y) * Pi);
If the global Pi was hidden, MiniCalc has no solution…
const Pi = '...';
x := @Sqrt(@Abs(x) - @Ln(y) * @Pi); // can't access the real @Pi
Meanwhile, Delphi code could do this…
const Pi = '...';
x := Sqrt(Abs(x) - Ln(y) * System.Pi);
In Tusk, the / operator is used to access globals…
const Pi = '...';
x := Sqrt(Abs(x) - Ln(y) * /Pi);
This symbol was chosen, among other reasons,
because it often denotes "top level" or "root".
MiniCalc uses the & operator to take the address
of an expression.
Tusk and Delphi use the @ operator.
All three languages use the ^ operator to dereference
a pointer.
However, in MiniCalc this is a prefix operator;
in Tusk and Delphi, it is postfix.
Tusk, like Delphi, does not require an empty
pair of parentheses to call a procedure or function
with zero arguments.
MiniCalc does require the empty parentheses
for global functions, but not for methods.
Tusk distinguishes between functions
(which return a value) and procedures
(which do not);
MiniCalc does not make this distinction.
Tusk supports more Delphi data types than MiniCalc…
- Enums – Tusk supports enums (scoped and non-scoped) the way Delphi does: they are integers when stored in a Variant. In contrast, MiniCalc stores enums as strings. Tusk supports enums in common RTL functions, including Ord, Inc, Dec, Succ, Pred, etc.
- Sets – Tusk supports Dephi's native set type (sets of enum, Byte, Int8, and AnsiChar). Tusk supports the familiar set operators: +, -, *, in, as well as the Include and Exclude routines. Naturally, the for…in loop supports sets.
- Dynamic Arrays – Tusk directly supports Delphi's dynamic arrays. In contrast, MiniCalc arrays are variant arrays, which are less efficient and don't have the same semantics. For example, Variant arrays are copied by value, but Delphi and Tusk dynamic arrays are copied by reference.
⏱ Last Modified: Sat 6:13:57 pm