213 lines
8.0 KiB
Markdown
213 lines
8.0 KiB
Markdown
****
|
|
|
|
**DISCLAIMER!**
|
|
Unofficial, work in progress! This is still a stub. Please help extending it.
|
|
There may be inaccuracies in this guide.
|
|
|
|
***
|
|
|
|
This is a guide for people with experience in Python or a similar language.
|
|
The guide assumes some intermediate knowledge.
|
|
|
|
The general tutorials can be found here:
|
|
http://nim-lang.org/tut1.html
|
|
http://nim-lang.org/tut2.html
|
|
|
|
The manual provides a more or less complete overview of the language:
|
|
http://nim-lang.org/manual.html
|
|
|
|
### At a glance
|
|
|
|
Similarities and differences.
|
|
|
|
Feature | Python | Nim
|
|
---------------------|-----------------------------------|-----------------------------------------
|
|
Execution model | Virtual Machine, JIT | Machine code via C*
|
|
Meta-programming | Python (decorators/metaclasses/eval) | Nim (const/when/template/macro)
|
|
Memory Management | Garbage-collected | Garbage-collected and manual
|
|
Types | Dynamic | Static
|
|
Dependent types | - | Partial support
|
|
Generics | Duck typing | Yes
|
|
int8/16/32/64 types | No | Yes
|
|
Bigints (arbitrary size) | Yes (transparently) | Yes (via nimble package)
|
|
Arrays | Yes | Yes
|
|
Bounds-checking | Yes | Yes
|
|
Type inference | Duck typing | Yes (extensive support)
|
|
Closures | Yes | Yes
|
|
Operator Overloading | Yes | Yes (on any type)
|
|
Custom Operators | No | Yes
|
|
Object-Oriented | Yes | Minimalistic**
|
|
Methods | Yes | Yes
|
|
Multi-Methods | No | Yes
|
|
Exceptions | Yes | Yes
|
|
|
|
\*Other backends supported and/or planned
|
|
\**See section below.
|
|
|
|
### Philosophy
|
|
|
|
The key to understanding Nim is that Nim was designed to be as fast as C, but to be much safer. Many of the design-decisions are based on making it harder to shoot yourself in the foot.
|
|
In Python there are no pointers (everything is treated as a reference).
|
|
While Nim does give you pointers, Nim gives you other, safer tools for your everyday needs, while pointers are mostly reserved for interfacing with C and doing low-level system programming.
|
|
|
|
Contrarily to Python, most Nim code can be executed at compile time to perform meta-programming.
|
|
|
|
### Arrays
|
|
|
|
In Nim, arrays are much more strict. They are pass-by-value (meaning they're copied at assignment). When passing an array to a proc in Nim, the argument is a read-only reference, meaning it can't be assigned to. Take the following example:
|
|
|
|
**Nim:**
|
|
|
|
```Nimrod
|
|
proc foobar(z: array[0..3, int]) =
|
|
z[5] = 5 # Error: Cannot assign to z
|
|
echo z[5] # Error: Index out of bounds.
|
|
|
|
var x = [1, 2, 3, 4]
|
|
|
|
foobar(x)
|
|
```
|
|
|
|
The Nim code will not compile. If you mean to change the array that was passed to the procedure, you can change the the signature of the procedure to ```proc foobar(z: var array[0..3, int])```. Now you will only get index out of bounds error. If you change the index in both lines to 1, the code will compile. If the index is a variable, Nim will include run-time checks on the bounds of the array.
|
|
|
|
In C, you can pass an ``int[3]`` to the foobar function, and the compiler will not complain. In this case Nim would not compile. You can use an openarray to accept an array of any size, and you can use low(z) and high(z) to query the bounds of the array.
|
|
|
|
Nim arrays can also be indexed from any number. That is, ``z: array[1..4, int]`` is an array of int indexed from 1 to 4. Trying to access ``z[0]`` would throw an index out bounds error.
|
|
|
|
In Nim you are strongly discouraged from using pointers in Nim, and you can accomplish almost everything you'd otherwise use pointers for with normal arguments, "var" arguments, variables, and "ref".
|
|
|
|
|
|
### Object-Orientation
|
|
|
|
Objects in Nim behave quite differently from classes in Python. Objects support inheritance (not multiple inheritance).
|
|
Python-like object methods do not exist: procs are not bound to objects (however, you can use them in ways very similar to Python, see the example below)
|
|
|
|
You can call a proc on objects with the ```anObject.foobar()```, but you can do that on any type (e.g. ints and arrays) as well. You can have methods on object, but you can have methods on any types, and for all the arguments, not just the first (in C++, implicit) one.
|
|
|
|
Nim does not have an implicit _self_.
|
|
|
|
It is possible to implement object-orientation features through libraries, thanks to the extensive meta-programming features of Nim. These are at the moment mostly work-in-progress.
|
|
|
|
Python-like object orientation example:
|
|
|
|
```Nim
|
|
type Animal = ref object of RootObj
|
|
age: int
|
|
name: string
|
|
|
|
type Cat = ref object of Animal
|
|
playfulness: float
|
|
|
|
# A proc that can access and *modify* the object
|
|
proc increase_age(self: var Cat) =
|
|
self.age.inc()
|
|
|
|
var c = Cat(name: "Tom")
|
|
c.increase_age()
|
|
echo c.name, " ", c.age
|
|
```
|
|
Tip: use objects by reference
|
|
|
|
### Inheritance
|
|
|
|
A Python programmer when first trying Nim can try to write something like this:
|
|
|
|
``` Nim
|
|
# TODO: extend this example with the declaration of the objects w/o ref
|
|
var heterogeneousArray: seq[ParentObjectType] = @[]
|
|
# TODO: Add an object inheriting from ParentObjectType to the seq
|
|
```
|
|
|
|
That will return a compilation error, because the objects have different sizes. Like in C, you can't make an array of structs with disparate types and sizes. What one can do is an array of references to the objects, all references having the same size but pointing to heterogeneous objects. This is what Python does by default.
|
|
|
|
``` Nim
|
|
# TODO: Show the proper way to do things, with emphasis on what changed
|
|
```
|
|
|
|
So, when using inheritance, be sure to inherit using refs, unless you know what you are doing. Also, check out Nim's generic programming capabilities as an alternative to OOP and inheritance.
|
|
|
|
## From Python to Nim
|
|
|
|
### Ranges
|
|
|
|
The syntax for ranges is different. a[x:y] becomes a[x..<y]
|
|
Also, a[x..y] is inclusive.
|
|
``` Nim
|
|
let a = @[1,2,3,4]
|
|
a[0..0] # returns @[1]
|
|
a[0..1] # returns @[1, 2]
|
|
a[0..<2] # returns @[1, 2]
|
|
a[0..3] # returns @[1, 2, 3, 4]
|
|
```
|
|
|
|
### Python strings
|
|
|
|
Use double quotes: "foo" or """foo""", not 'foo'
|
|
|
|
Strings are always unicode. Remember to use runes() to iterate over unicode characters instead of bytes.
|
|
|
|
``` Nim
|
|
var a = "hello"
|
|
echo a[0..1] # returns "he": ranges are inclusive! See the "Ranges" paragraph
|
|
```
|
|
|
|
### Python tuples
|
|
|
|
Nim Tuples are close to Python nametuples, see [manual](http://nim-lang.org/manual.html#tuples-and-object-types).
|
|
Use Nim arrays:
|
|
``` Nim
|
|
var a = ["hi", "there"]
|
|
var b = [1, 2, 3]
|
|
echo b[1]
|
|
var c = ["hi", 1] # no mixed types please
|
|
```
|
|
|
|
### Python lists
|
|
|
|
Use [Nim sequences](http://nim-lang.org/tut1.html#sequences)
|
|
|
|
Nim arrays and sequences can hold only items of the same type.
|
|
|
|
#### List Comprehensions
|
|
```
|
|
import future # required for the list comprehension syntactical sugar
|
|
|
|
let x = @[1, 2, 3, 4, 5, 8, 8, 8, 10] # create a Nim sequence
|
|
|
|
# syntax: lc[ item | ( item <- seq, (optional condition) ), type ]
|
|
# equivalent to python [ y for y in x if y > 5 ]
|
|
echo lc[ y | ( y <- x, y > 5 ), int ]
|
|
# Can also perform operations on item, e.g. y*2 as shown here
|
|
echo lc[ y*2 | ( y <- x ), int ]
|
|
```
|
|
|
|
### Python sets
|
|
|
|
Python sets are not like [Nim set type](http://nim-lang.org/manual.html#set-type).
|
|
If the values that will go in the set are known beforehand and finite, you can create an Enum for them.
|
|
Otherwise you can emulate a Python set using a [HashSet](http://nim-lang.org/sets.html).
|
|
The Nim set type is faster and memory-efficient.
|
|
|
|
### Dictionaries
|
|
|
|
Use [Tables](http://nim-lang.org/tables.html) for Python dicts,
|
|
OrderedTable for Python ordered dicts, and CountTable for Python's Counter.
|
|
|
|
``` Nim
|
|
var a = {"hi": 1, "there": 2}.toTable
|
|
echo a["hi"], " ", a.len
|
|
assert a.hasKey("hi")
|
|
```
|
|
|
|
### ABC
|
|
|
|
See [this](http://rosettacode.org/wiki/Abstract_type#Nim)
|
|
|
|
### Ternary operator
|
|
|
|
``` Nim
|
|
var is_happy = if has_cat(): "quite" else: "not much"
|
|
```
|
|
|
|
|