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

5.2 KiB

(Work in progress)

This is a guide for people with experience in C or a similar language. The guide assumes knowledge of how stacks and heaps works.

The general tutorials can be found here:
http://nimrod-lang.org/tut1.html
http://nimrod-lang.org/tut2.html

The manual provides a more or less complete overview of the language: http://nimrod-lang.org/manual.html

At a glance

FeatureCNimrod
Memory ManagementManual (GC w/ libraries or obj-C)Garbage-collected and manual
TypesStaticStatic
CompilationMachine codeMachine code via C
(other backends in progress/planned)
Meta-programmingC PreprocessorNimrod (const/when/template/macro)
Type inferenceNo (some w/ C++11)Yes (extensive support)
ClosuresNo (Yes w/ obj-C or C++11)Yes
Operator OverloadingNo (Yes w/ C++)Yes
Custom OperatorsNoYes

Arrays

In C an array is more or less syntactic sugar for pointers. In Nimrod, 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 Nimrod, the argument is a read-only reference, meaning it can't be assigned to. Take the following example:

C:

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;
}

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 C-code will compile, it may or may not crash. The Nimrod 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, Nimrod 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 Nimrod 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.

Nimrod 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 C, there's nothing that keeps you from keeping a pointer to a stack-allocated array

Structs - Tuples and Objects

Tuples and Objects in Nimrod are kind of like structs in C, but not really.

Interfacing C and Nimrod

See Foreign Function Interface

Converting C code to Nimrod

See c2nim

Cheat Sheet

Note: Code examples are not exactly one-to-one, there may be subtle differences in the semantics. See comments.

CNimrodComment
```C int x; int y = 2; ``` ```Nimrod var x : int var y1 : int = 2 var y2 = 2 let z = 2 ``` Define variable. y2 uses type inference. z is single-assignment. In nimrod, uninitialized variables is initialized to 0/nil or similar defaults.
```C char* s = "Hello World."; char s0 = s[0]; // 'H' char *t = s; // Pointer to s s[11] = '!'; // s and t are both "Hello World." ``` ```Nimrod var s: string = "Hello World." var s0: char = s[0] # 'H' var t = s # Copy of s s[11] = '!' # s is "Hello World!", t is "Hello World." ``` Strings and char. Strings are pass-by-value (copied on assignment) and strictly bounds-checked on access.
```C 9 % 8 // 1 -9 % 8 // -1 (unsigned)(-9) % (unsigned)(8) // 7 ``` ```Nimrod 9 mod 8 # 1 -9 mod 8 # -1 -9 %% 8 # 7 ``` Modulo operator. %% treats its argument as unsigned numbers. See
```C int x = foobar() ? 42 : 0; ``` ```Nimrod var x = if foobar(): 42 else: 0 ``` If-statements return the value of the expression they evaluate to, so Nimrod doesn't need a ternary operator.
```C void foo() { printf("Hello World\n"); } int bar() { return 2; } int baz(int x) { return x*2; } ``` ```Nimrod proc foo() = echo "Hello World"

proc bar() : int = 2

proc baz(x : int) = x*2

</td>
<td><b>Function/Procedure.</b>  </td>
  </tr>

  <tr>
<td>
```C
void foobar(person_t *a) {
  person_t b;
  b = *a;
  b.name = "Bob";
  *a = b;
}
```Nimrod proc foobar(a: ref TPerson) = var b: TPerson b = a[] b.name = "Bob" a[] = b ``` Dereference. In C, only the pointer to the strings in the struct is copied. In Nimrod, the string is also copied, but refs are not deep-copied.