nim-wiki/Nim-for-C-programmers.md

389 lines
10 KiB
Markdown
Raw Normal View History

2014-01-10 21:50:08 +00:00
****
**DISCLAIMER!**
Unofficial, work in progress!
There may be inaccuracies in this guide.
***
2013-12-19 09:28:28 +00:00
This is a guide for people with experience in C or a similar language. The guide assumes some intermediate knowledge, for instance of how stacks and heaps works.
2013-12-19 09:28:28 +00:00
The general tutorials can be found here:
http://nim-lang.org/tut1.html
http://nim-lang.org/tut2.html
2013-12-19 09:28:28 +00:00
The manual provides a more or less complete overview of the language:
http://nim-lang.org/manual.html
2013-12-19 09:28:28 +00:00
### At a glance
2014-04-28 21:10:12 +00:00
Similarities and differences.
Feature | C | Nim
2014-04-28 21:10:12 +00:00
---------------------|-----------------------------------|-----------------------------------------
Compilation | Machine code | Machine code via C*
Meta-programming | C Preprocessor | Nim (const/when/template/macro)
2014-04-28 21:10:12 +00:00
Memory Management | Manual (GC w/ libraries or obj-C) | Garbage-collected and manual
Types | Static | Static
Dependent types | No | Partial support
Generics | No (Templates w/ C++) | Yes
int8/16/32/64 types | Yes | Yes
Unsigned ints | Yes | Yes
2014-04-28 21:10:12 +00:00
Arrays | Yes | Yes
Bounds-checking | No | Yes
Type inference | No (some w/ C++11) | Yes (extensive support)
Closures | No (Yes w/ obj-C or C++11) | Yes
Operator Overloading | No (Yes w/ C++) | Yes (on any types)
Custom Operators | No | Yes
Object-Oriented | No (Yes w/C++ or obj-C) | Minimalistic**
Methods | No (Yes w/C++) | Yes
Multi-Methods | No | Yes
Exceptions | No (Yes w/C++) | Yes
2015-03-08 20:35:24 +00:00
\*Other backends supported and/or planned
\**See section below. Also: it's arguably possible to write OOP-style in pure C
2013-12-26 21:43:12 +00:00
### Philosophy
2015-02-03 08:07:13 +00:00
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. For example, in C you are required to use a pointer for most of your everyday programming needs. 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. In other words, C gives you a combined hammer and gun, while Nim gives you a separate gun and hammer.
The other important thing to know is that while C uses a separate language to do meta-programming (the preprocessor), Nim meta-programming is done with the Nim language itself. That means that most Nim code can be executed at compile time, and Nim's ability to generate Nim-code at compile time is much more sophisticated.
2013-12-26 21:43:12 +00:00
### Arrays
In C an array is more or less syntactic sugar for pointers. In Nim, arrays are much more strict and safe to use. 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:
2013-12-26 21:43:12 +00:00
**C:**
```C
2013-12-26 21:43:12 +00:00
void foobar(int z[4]) {
z[5] = 5;
printf("%d\n",z[5]);
}
int main() {
int x[4] = {1, 2, 3, 4};
foobar(x);
printf("%d\n", x[1]);
return 0;
}
```
**Nim:**
```nim
2013-12-26 21:43:12 +00:00
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 C-code will compile, it may or may not crash. 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.
2013-12-26 21:43:12 +00:00
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.
2013-12-26 21:43:12 +00:00
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.
2013-12-26 21:43:12 +00:00
In C, there's nothing that stops you from keeping a pointer to a stack-allocated array after the function that declared it has returned (and the stack is invalidated). In Nim, this is true as well, but 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".
2014-04-28 20:38:26 +00:00
### Unsigned integers
Nim strongly discourages the use of unsigned integers, as it's considered unnecessary and somewhat unsafe* for most applications.
2014-04-28 20:38:26 +00:00
*See: http://critical.eschertech.com/2010/04/07/danger-unsigned-types-used-here/
2014-04-28 21:10:12 +00:00
### Object-Orientation
Objects in Nim have more features than structs in C, but behave quite differently from classes in C++. Objects support inheritance (not multiple inheritance). But otherwise most of the features that apply to objects simply apply to all types in Nim.
2014-04-28 21:10:12 +00:00
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 _this_/_self_.
2014-04-28 21:10:12 +00:00
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.
2014-04-28 21:10:12 +00:00
2013-12-19 09:28:28 +00:00
### Structs - Tuples and Objects
Tuples and Objects in Nim are kind of like structs in C, but not really.
2013-12-19 09:28:28 +00:00
### Interfacing C and Nim
2013-12-19 09:28:28 +00:00
See [Foreign Function Interface](http://nim-lang.org/docs/manual.html#foreign-function-interface)
2013-12-19 09:28:28 +00:00
### Converting C code to Nim
See [c2nim](https://github.com/nim-lang/c2nim/blob/master/doc/c2nim.rst)
2013-12-19 09:28:28 +00:00
### Cheat Sheet
Note: Code examples are not exactly one-to-one, there may be subtle differences in the semantics. See comments.
2013-12-19 09:28:28 +00:00
<table>
<tr>
<th>C</th><th>Nim</th><th>Comment</th>
2013-12-19 09:28:28 +00:00
</tr>
<tr>
<td>
<pre>
2016-09-05 11:45:35 +00:00
/* A single-line comment */
int x = 3; // more comment
// So is this
</pre>
<pre>
/*
a multi-line comment
*/
//
// or maybe this way?
//
#if 0
2016-09-05 11:45:35 +00:00
some code
including comments
to be ignored
#endif
</pre>
</td>
<td>
<pre>
2016-09-05 11:45:35 +00:00
# A single-line comment
var x = 3 # more comment
</pre>
<pre>
#[
a multi-line comment. #[ may be nested ]#
]#
#
# or maybe this way?
#
when false:
a multi-line comment
2016-09-05 11:45:35 +00:00
(but must be indented
to be included)
</pre>
</td>
<td>
<b>Single line comments</b>. Use the hash char (#).
<br>
<br>
<b>Multi-line comments</b>. Readability vs easy of use?
</td>
</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>
2015-02-03 08:07:13 +00:00
<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>
2014-08-30 18:48:02 +00:00
char s[] = "Hello World.";
2013-12-26 21:51:01 +00:00
char s0 = s[0]; // 'H'
2014-05-04 19:27:22 +00:00
char *t = s; // Ptr to s
2013-12-26 21:51:01 +00:00
s[11] = '!';
2014-05-04 19:27:22 +00:00
// s, t == "Hello World!"
</pre>
2013-12-26 21:51:01 +00:00
</td>
<td>
<pre>
2014-05-04 19:28:36 +00:00
var s = "Hello World."
2013-12-26 21:51:01 +00:00
var s0: char = s[0] # 'H'
var t = s # Copy of s
s[11] = '!'
2014-05-04 19:23:13 +00:00
# s is "Hello World!"
# t is "Hello World."
</pre>
2013-12-26 21:51:01 +00:00
</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>
2014-01-12 17:18:35 +00:00
char a = '\n';
2014-05-04 19:25:38 +00:00
printf("byte %d\nA%cB\n",
a, a);
</pre>
2014-01-12 17:18:35 +00:00
</td>
<td>
<pre>
2014-01-12 17:18:35 +00:00
let a = '\L'
2014-05-04 19:25:38 +00:00
echo "byte ", $int(a),
"\nA" & $a & "B"
</pre>
2014-01-12 17:18:35 +00:00
</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>
2014-01-12 17:18:35 +00:00
</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>
2013-12-19 09:28:28 +00:00
<tr>
<td>
<pre>
2013-12-19 09:28:28 +00:00
int x = foobar() ? 42 : 0;
</pre>
2013-12-19 09:28:28 +00:00
</td>
<td>
<pre>
var x = if foobar(): 42
else: 0
</pre>
2013-12-19 09:28:28 +00:00
</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>
2013-12-19 09:28:28 +00:00
</td>
</tr>
<tr>
<td>
<pre>
void foo() {
printf("Hello World\n");
}
int bar() {
return 2;
}
int baz(int x) {
return x*2;
}
int foobar(int *x) {
return (++*x)*2;
}
</pre>
</td>
<td>
<pre>
proc foo() =
echo "Hello World"
proc bar(): int =
2
proc baz(x: int): int =
x*2
proc foobar(x: var int): int =
inc(x)
result = x*2
</pre>
</td>
<td><b>Function/Procedure.</b> </td>
</tr>
2013-12-19 09:28:28 +00:00
<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>
2013-12-19 09:28:28 +00:00
void foobar(person_t *a) {
person_t b;
b = *a;
b.name = "Bob";
*a = b;
}
</pre>
2013-12-19 09:28:28 +00:00
</td>
<td>
<pre>
proc foobar(a: ref Person) =
var b: Person
2013-12-19 09:28:28 +00:00
b = a[]
b.name = "Bob"
a[] = b
</pre>
2013-12-19 09:28:28 +00:00
</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>
2013-12-19 09:28:28 +00:00
</tr>
<tr>
<td>
<pre>
double d = 3.1415926;
int i = (int) d;
d = (double) i;
2017-03-10 10:04:57 +00:00
printf("%d, %g\n", i, d);
</pre>
<pre>
int x = 42;
void *p = &x;
int y = (int) *p;
printf("%d, %d, %p\n", x, y, p);
</pre>
</td>
<td>
<pre>
var d = 3.1415926
var i = d.int
d = i.float
echo i, " ",d
</pre>
<pre>
var
x = 42
p: pointer = x.addr
y = cast[ptr int](p)[]
echo x, " ", y, " ", repr(p)
</pre>
</td>
<td>
<b>Simple casting</b> Considered unsafe in Nim (and that you know what you are doing).
<br>
cast is NOT for numeric type conversion.
</td>
</tr>
2013-12-19 09:28:28 +00:00
</table>