-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Tips and tricks
A mix of bits of code, cookbook recipes, deep knowledge, tips and tricks about Nim programming.
Use nim check myfile.nim
to check your program for errors, without code generation. This makes the process quicker.
You can use the slanted quote string syntax (stropping) if you need to use a reserved word as an identifier.
var `type`: int
You want to define useSomeFeature
at compilation time and use it in the code.
- Do it when you compile:
$ nim c -d:useSomeFeature myApp
- Put it in the
yourfilename.nims
file located in the same directory as your source fileyourfilename.nim
asswitch("define", "useSomeFeature")
- Put it in the
nim.cfg
file located in the same directory as source file and writedefine:useSomeFeature
when defined(useSomeFeature):
const someSubFeature = true
type idType = int32
var defaultUserName = "Frank"
else:
type idType = int16
var defaultUserName = "Molly"
# `when` does not open a new scope, so `idType` and `defaultUserName` are available here.
when isMainModule:
# this code is ran only when this module is the main compilation module
echo "This module was compiled on ", CompileDate, " at ", CompileTime
Nim likes spaces. This is a quirk of the command syntax where a +b
is evaluated as a(+(b))
.
Use spaces, preferably, like a + b
or else a+b
, but don't mix space and no-spaces usage.
- Have you tried to
discard
the value from a proc that does not return any value?
proc noReturnValue =
echo "Foo!"
discard noReturnValue()
- A inner proc "inherits" the including proc generics declaration and you don't need to re-define them.
proc foo[T](x: T) =
proc bar[T](y: T) = <== Error is here
echo "In bar"
echo "In foo"
You must write:
proc foo[T](x: T) =
proc bar(y: T) = # Generic type T is defined by englobing proc
echo "In bar"
echo "In foo"
Use compiles.
import unittest
suite "valid syntax":
test "syntax errors":
let a = "foo"
let b = 5
assert not compiles(let c = a + b), "Can't mix string and int"
You can provide examples of in your documentation, with runnableExamples.
When the documentation is extracted from the source with $ nim doc myfile.nim
, these examples are extracted and put in a temporary
file, compiled and tested. This is a good way to provide examples for your API and check that they are still valid.
proc isOdd(i: int): bool =
## Test if its argument is odd.
runnableExamples:
assert 5.isOdd, "5 is an odd number"
assert not isOdd(3 * 2), "6 is not an odd number"
result = i mod 2 == 1
Like proc or funct, template follow overloading rules. You can use normal types for parameters but they can have meta-types too: typed
, untyped
and typedesc
.
There are lazy type resolution rules for untyped
parameters.
For typed
parameters, you can use parameter constraints to reduce the scope of the parameters.
template foo(x: typed{lit}) =
echo "foo matched the literal '", x, "'"
template foo(x: typed{ident}) =
echo "foo matched the identifier '", x, "'"
You have defined a dsl:
and you want to define an options:
template that can be used only within dsl:
. How do you do this? Use template scopes and define options
within dsl
, like following:
template dsl*(body: untyped) =
template options(body: untyped) =
# Here define the options code...
# Here define the dsl code...
Note that you only need to make the englobing template public with the *
.
expandMacros shows how a macro call is expanded at compilation time. It's very useful for debugging macros...
dumpTree can also be used to print how a block of code is parsed at compile time.
import macros
let x, y = (4, 8)
expandMacros:
echo "x > y is expanded to ", x > y
dumpTree:
echo "x > y is expanded to ", x > y
echo
writes to stdout
. If you want to print to stderr
use write and writeLine
writeLine(stderr, "Write to stderr")
You can use debugEcho for this.
Strings can be converted to enum using parseEnum from strutils. Beware that a ValueError
is raised if the enum is not found. If you don't want to manage
the exception, provide a default with parseEnum.
import strutils
type
Fruit = enum
Apple,
Banana,
Cherry
let fruit = parseEnum[Fruit]("cherry")
let pineapple = parseEnum[Fruit]("pineapple", Banana)
fields and fieldPairs will help you discover the fields and values of a tuple or object. But as Nim is strongly type, you can't build a result mixing types. Either use conditional compilation for different code paths or use overloading.
type
Custom = object
foo: string
bar: bool
proc `$`(x: Custom): string =
result = "Custom:"
for name, value in x.fieldPairs:
when value is bool:
result.add("\n\t" & name & " is " & $value)
else:
result.add("\n\t" & name & " \'" & value & "\'")
proc `$1`(x: string): string = $x
proc `$1`(x: bool): string = $x
proc `$1`(x: Custom): string =
result = "Custom:"
for name, value in x.fieldPairs:
result.add("\n\t" & name & " is " & `$1`(value))
let o = Custom(foo: "Hi there!", bar: false)
echo "o=", $o
echo "o1=", `$1`(o)
Intro
Getting Started
- Install
- Docs
- Curated Packages
- Editor Support
- Unofficial FAQ
- Nim for C programmers
- Nim for Python programmers
- Nim for TypeScript programmers
- Nim for D programmers
- Nim for Java programmers
- Nim for Haskell programmers
Developing
- Build
- Contribute
- Creating a release
- Compiler module reference
- Consts defined by the compiler
- Debugging the compiler
- GitHub Actions/Travis CI/Circle CI/Appveyor
- GitLab CI setup
- Standard library and the JavaScript backend
Misc