Flexible is Nim's syntax, which allows you to write something you may never image that you can write freely in any programming language! And sometimes it even makes just wanna say "WoW".
And this time I'd show you something you can easily do to simplify the notation of multiplication in Nim, making your writing mathematics expression simpler and more comfortable.
The Multiplication Sign
Just think back: in the period of learning Elementary Mathematics, you were once told that "The multiplication sign can be omitted", e.g. a×b
is written as ab
.
From then on, ×
almost disappears between two numbers (you may come up with its usage of vector cross product
, but that's another story, and I'm going to introduce relative feature also supported by Nim in following post), it became very normal for you to omit the multiplication sign between numbers.
However, later you met programming languages like C/C++, Java, Go, Rust, etc. or smalltalk, Haskell, ... And you were told multiplication is done via *
, and you had to write a*b
over a b
, which is, not just with an additional character, and, for typing this character, *
,
I guess it's sometimes a strain on one's pinky finger due to keeping pressing the "Shift" key.
Can We Write Code just like Mathematics Expressions
So can you image there are such a language in which *
can just be omitted like in Mathematics?
Yes, you can make it done in Nim, via {.experimental: "callOperator".}
, mentioned above.
To clarify, Nim itself isn't a special language peculiar to the field of mathematics (also called DSL), and its original multiplication is also written as a*b
, like most Universal Programming Language. However, with great power provided by Nim, it's easy to make it.
Let's see how easy:
{.experimental: "callOperator".} # required for func `()`
func `()`[T](x, y: T): T = x*y
Then here you are:
let
a = 2
b = 3
c = 9
assert (a b c) == 54
And you may replace your code like (assuming a,b,c is all integer)
#include <math.h> // pow
// ...
static
int f(int a, int b, int c)
// in fact for parameter types,
// you shall write `const int` over `int` to express
// what Nim expresses below.
{
return a*(a+b)*(int)pow(a, c);
}
// ...
with
from std/math import `^`
# ...
func f(a, b, c: int): int = a (a+b) a^c
# ...
And with little speed loss (Nim's speed is almost the same as C)
Don't you like this?
In case you wonder what happened to code above,
I'd like to give some explain.
Explain
Thanks to Nim's command-invocation-syntax,
Routines can be invoked without the () if the call is syntactically a statement.
Therefore, in code above, (a b c)
is just the same as (a(b(c)))
.
What Else We Can Do with These Features of Nim
Command Invocation Syntax
Also thanks to the feature of command-invocation-syntax, life is simpler with Nim:
Code like:
echo 1
stdout.write 1
can be written.
And quite a few parentheses can be omitted, saving your pinky finger from pain of keeping pressing shift key, again.
Call Operator
For {.experimental: "callOperator".}
,
not sure if you recall, but it's Nim's equivalent as of Python's __call__
, though more powerful.
It allows you to make a object callable.
But in Nim, not only for object (instance of one class), but for any type! Such a feature that allows programmers bind routines to any type beyond such a type's original definition is often called "extension methods", which is supported in various forms by C#, Kotlin, Swift, Ruby, etc. (though in Nim this feature is subtly different from other languages, but introduce it is beyond topic, and I may mention this in later post)
Therefore, you can just make primitive types like int
callable, not only custom defined types.
EOF
Thanks for reading till EOF.
I'm going to write about Nim's powerful syntax and macros as a serials, but may lack time.
The following are some relative resources for you to preview if interested:
Top comments (0)