Updated Nim for Python Programmers (markdown)

This commit is contained in:
Federico Ceratto 2015-04-04 00:00:28 +01:00
parent bdaf9d0046
commit ed383baeb5
1 changed files with 279 additions and 1 deletions

View File

@ -22,4 +22,282 @@ That will return a compilation error, because the objects have different sizes.
# 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.
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.
-------
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 | Machine code via C*
Meta-programming | Dynamic language | Nim (const/when/template/macro)
Memory Management | Garbage-collected | Garbage-collected and manual
Types | Dynamic | Static
Dependent types | - | Partial support
Generics | - | Yes
int8/16/32/64 types | No | Yes
Unsigned ints | Yes (by default) | Yes (not by default)
Arrays | Yes | Yes
Bounds-checking | Yes | Yes
Type inference | - | Yes (extensive support)
Closures | Yes | Yes
Operator Overloading | Yes | Yes (on any types)
Custom Operators | No | Yes
Object-Oriented | Yes | Minimalistic**
Methods | Yes | Yes
Multi-Methods | No | Yes
Exceptions | Yes | Yes
### 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".
### Unsigned integers
Nim strongly discourages the use of unsigned integers, as it's considered unnecessary and somewhat unsafe* for most applications. The unsigned types uint, uint8/16/32/64 are available by default, but the arithmetic and binary functions are not defined. If you do need to do arithmetic on unsigned integers, you need to import the **unsigned** module.
*See: http://critical.eschertech.com/2010/04/07/danger-unsigned-types-used-here/
### 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:
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 from other languages (like C++,Java,etc. or Smalltalk,Obj-C,Ruby,etc.) through libraries, thanks to the extensive meta-programming features of Nim. These are at the moment mostly work-in-progress.
### Structs - Tuples and Objects
Tuples and Objects in Nim are kind of like structs in C, but not really.
### Cheat Sheet
WARNING: FIXME: this cheat sheet is for C, not Python.
Note: Code examples are not exactly one-to-one, there may be subtle differences in the semantics. See comments.
<table>
<tr>
<th>C</th><th>Nim</th><th>Comment</th>
</tr>
<tr>
<td>
<pre>
int x;
int y = 2;
</pre>
</td>
<td>
<pre>
var x : int
var y1 : int = 2
var y2 = 2
let z = 2
</pre>
</td>
<td><b>Define variable</b>. y2 uses type inference. z is single-assignment. In Nim, uninitialized variables is initialized to 0/nil or similar defaults.</i>
</td>
</tr>
<tr>
<td>
<pre>
char s[] = "Hello World.";
char s0 = s[0]; // 'H'
char *t = s; // Ptr to s
s[11] = '!';
// s, t == "Hello World!"
</pre>
</td>
<td>
<pre>
var s = "Hello World."
var s0: char = s[0] # 'H'
var t = s # Copy of s
s[11] = '!'
# s is "Hello World!"
# t is "Hello World."
</pre>
</td>
<td><b>Strings and char</b>. Strings are pass-by-value (copied on assignment) and strictly bounds-checked on access.</i>
</td>
</tr>
<tr>
<td>
<pre>
char a = '\n';
printf("byte %d\nA%cB\n",
a, a);
</pre>
</td>
<td>
<pre>
let a = '\L'
echo "byte ", $int(a),
"\nA" & $a & "B"
</pre>
</td>
<td><b>Newlines and chars</b>. In nim you can't use ``\n`` as a character literal, because on the Windows platform it expands to CR+LR. So you need to specify which char to use.</i>
</td>
</tr>
<tr>
<td>
<pre>
9 % 8 // 1
-9 % 8 // -1
(unsigned)(-9) %
(unsigned)(8) // 7
</pre>
</td>
<td>
<pre>
9 mod 8 # 1
-9 mod 8 # -1
-9 %% 8 # 7
</pre>
</td>
<td><b>Modulo operator</b>. <i>%% treats its argument as unsigned numbers. <a href="http://nim-lang.org/manual.html#pre-defined-integer-types">See</a></i></i>
</td>
</tr>
<tr>
<td>
<pre>
int x = foobar() ? 42 : 0;
</pre>
</td>
<td>
<pre>
var x = if foobar(): 42
else: 0
</pre>
</td>
<td>
<i>If-statements return the value of the expression they evaluate to, so Nim doesn't need a </i><b>ternary operator</b>.</i>
</td>
</tr>
<tr>
<td>
<pre>
void foo() {
printf("Hello World\n");
}
int bar() {
return 2;
}
int baz(int x) {
return x*2;
}
</pre>
</td>
<td>
<pre>
proc foo() =
echo "Hello World"
proc bar(): int =
2
proc baz(x: int) =
x*2
</pre>
</td>
<td><b>Function/Procedure.</b> </td>
</tr>
<tr>
<td>
<pre>
int a = 3
int *b = &a;
</pre>
</td>
<td>
<pre>
var a = 3
var b = addr(a)
</pre>
</td>
<td><b>Getting an address.</b> <i></i> </td>
</tr>
<tr>
<td>
<pre>
void foobar(person_t *a) {
person_t b;
b = *a;
b.name = "Bob";
*a = b;
}
</pre>
</td>
<td>
<pre>
proc foobar(a: ref TPerson) =
var b: TPerson
b = a[]
b.name = "Bob"
a[] = b
</pre>
</td>
<td><b>Dereference.</b> <i>In C, only the pointer to the strings in the struct is copied. In Nim, the string is also copied, but refs are not deep-copied.</i> </td>
</tr>
</table>