Learning Nim
I have been using nim-lang or nim off and on for about 6 mo. I really like the language and its fun to program in , but I have no patience to actually learn nim the correct way. I mean instead of just throwing shit together and thinking (I am cool). So I bought the books Nim In Action and Mastering Nim and I am going to go through both the books to understand better about programming.
This blog platform supports markdown language so I should be able to use code injection
. Great it works now I can write code examples. I usually use Joplin App for all my notes but I decided to actually post this online for others to see.
For those whom have never heard of the Nim language take a look and see for yourself. Its very easy to get started and learn.
Nim In Action:
- Book details and how to buy can be found here: Nim in action
Starting Mastering Nim:
- Book details can be found here: Master Nim - from Nim Blog
- Can be bought on Amazon here: Mastering nim
Example's will be from both books
[WARNING] you need to install libsdl or SDL and Fira-sans.ttf font. On Archlinux based distros you can install via.
sudo pacman -S sdl ttf-fira-sans
Drawing Horizontal and Vertical lines
import pixels
type
Point = object
x: int
y: int
var p = Point(x: 5, y: 7)
putPixel(p.x, p.y)
Now we want to run the command on a terminal or command line like this:
nim c pixel1.ex
So lets talk about this example. import pixels is nim's way of importing a library, Type is for static types , one of the many reason's why Nim is such a powerful and flexible language. We create a type called Point and we make Point an object. The Point object has x and y which are both integers. We then want to create a variable to that is in instance or Point called p , p will hold our coordinates of x and y. We call putPixel with p.x and p.y,
[IMG1 - output of compiled nim program]
It doesn't look like much but shows us that we have a point using x, y plain.
This next example will actually show us how to draw a horizontal and vertical line
import pixels
type
x: int
y: int
# Create a proc to draw a horizontal line
proc drawHorizontalLine(start: Point, length: Positive) =
for delta in 0 .. length:
putPixel(start.x + delta, start.y)
# Create a proc to draw a vertical line
proc drawVerticalLine(start: Point, length: Positive) =
for delta in 0 .. length:
putPixel(start.x, start.y + delta)
# crate a point with coordinates x: 60, y: 40
let a = Point(x: 60, y: 40)
# call the two procs (drawHorizontalLine and drawVerticalLine)
drawHorizontalLine(a, 50)
drawVerticalLine(a, 30)
nim c pixel2.nim
[IMG2 - output of compiled nim program]
So we can see from the image you have two points a horizontal and vertical one using x and y plain. Those points then show up graphically on the screen.
So how does this work? Let's break this program down list style.
-
import the pixels library (import pixels)
-
create a type called Point and create and x and y integer
-
create a proc or (procedure) called drawHorizontalLIne
- using a starting Point object as a starting point and using length as a Positive integer only.
- create a for loop of the delta (This actually could be any variable name)
- and iterate or loop through 0 - length (remember length is a positive integer so it would be for x in 0 through and up to the positive number.
- create a proc or (procedure) called drawVerticalLine
- using a starting Point object as a starting point and using lenght as a Positive integer only.
- create a for loop of the delta (This actually could be any variable name)
- and iterate or loop through 0 - length (remember length is a positive integer so it would be for x in 0 through and up to the positive number.
- Create a variable called "a" and assign it to Point then use x and y to create points i.e. x: 60 , y: 40.
- call the two procs to draw the horizontal and vertical lines.
- and use a as a parameter and the "Positive" number.
We can even extend this example
import pixels
type
x: int
y: int
type
Direction = enum
Horizontal
Vertical
# Create a proc to draw a horizontal line
proc drawHorizontalLine(start: Point, length: Positive) =
for delta in 0 .. length:
putPixel(start.x + delta, start.y)
# Create a proc to draw a vertical line
proc drawVerticalLine(start: Point, length: Positive) =
for delta in 0 .. length:
putPixel(start.x, start.y + delta)
# Create a proc that will combine both drawHorizontal and drawVertical
proc drawLine(start: Point, length: Positive, direction: Direction) =
case direction
of Horizontal:
drawHorizontalLine(start, length)
of Vertical:
drawVerticalLine(start, length)
# crate a point with coordinates x: 60, y: 40
let a = Point(x: 60, y: 40)
# Call drawLine
drawLine(a, 50, Horizontal)
drawLine(a, 30, Vertical)
[IMG3 - output of compiled nim program]
Our image hasn't changed , it now just easier to call one procedure instead of many
So we have extended our pixel program so that we don't have to call drawHorizontal and drawVertical over and over to create lines. We can combine both of them with a new procedure.
There are a couple of new terms we are using here: - enum: which stands for enumeration - case: which is nim's switch statement
Enum
type
Colors = enum
blue, red, green
var b = Colors.blue
echo b (answ: blue)
echo Color.blue
enumerated type defines a collection of identifiers have some some type of meaning attached to them.
Case
case myVar
of "pet1", "pet2", "pet3":
echo "Great pet"
else:
echo "Misunderstood pet"
case which is nim's "Switch statement".
Rendering Text
The pixels library is very simple but it does support text rendering. [WARNING] you need to install Mozilla's Fira-sans.ttf font otherwise this won't render to the SDL canvas
import pixels
drawText 100, 30, "You should be on Mastodon", 34, Blue
[IMG3] Render Text
Nim variables
There are 3 types of keywords that nim uses for storage variables:
- const - Immutable value and executed at compile time
- var - Mutable value (The value can be changed)
- let - Immutable value (The value cannot be changed)
Install inim
inim is a program written in nim and is a REPL (Read-Eval-Print Loop). This allows us to practice on a terminal / command line
nim> const PI = 3.14159
nim> var pi: float
nim> pi = 3.14159
nim> let pi = 3.14159
Error: redefinition of 'pi'; previous declaration here: /tmp/inim_1669002625.nim(20, 5)
the variable "pi" is already assigned.
nim> PI
3.14159 == type float64
nim> pi
3.14159 == type float
nim> let thisPI = 3.14159 # We assign "thisPI" to 3.14159
nim> thisPi
3.14159 == type float64
nim> thisPI
3.14159 == type float64
Let's use inim to print out (var, let and const)
nim> var a = 10
nim> let b = 20
nim> const c = 100
Lets print out the result on one line.
nim> echo "var a = ", $a & " ", "var b = ", $b & " " , "var c = ", $c
var a = 10 var b = 20 var c = 100
The "&" is to concatenate and " " is for spaces.
Find the index of a string starting at 0
proc find(haystack: string; needle: char): int =
for i in 0 ..< haystack.len: # this will always be true (if i is less than the string.len)
# meaning a string is counted starting at 1 .. n , and an index
# starts at 0 , so therefore 0 is the start but string starts at 1
# so this will always be true
if haystack[i] == needle: return i # if the string[index i which starts at 0] is equal to the needle
# which is our "char" character ' ' then return the index of i
# which if we had "abcdefghi" for our haystack string and we choose
# 'g' then the index of g - -remember starting with 0 is 6
# let try
return -1
let index = find("l;kasdf", 's')
echo index
echo "l;kasdf".len
Here is our results:
nim c -r --verbosity\:0 --hint\[Processing\]\:off --excessiveStackTrace\:on /home/nixfreak/lang/nim/practice/mn/hackstack.nim
4
7
The index of 'g' is: 6
Find the length of the string abcdefghi
7
Nixfreak public key
nixfreak dot protonmail.ch
Fingerprint: B19B C26C 80AE 32D2 46C6 FBF1 AA2F 0EBC D327 6BF1