Version 1.6.0 released
19 October 2021 The Nim Team
Nim version 1.6 is now officially released!
A year in the making, 1.6 is the latest stable release and by far the largest yet. We’re proud of what we — the core team and dedicated volunteers — have accomplished with this milestone:
- 1667 PRs merged (1760 commits)
- 893 issues closed
- 15 new stdlib modules
- new features in more than 40 stdlib modules, including major improvements to 10 commonly used modules
- documentation and minor improvements to 170 modules, including 312 new runnable examples
- 280 new nimble packages
Nim made its first entry in TIOBE index in 2017 at position 129, last year it entered the top-100, and for 2 months the top-50 (link). We hope this release will reinforce this trend, building on Nim’s core strengths: a practical, compiled systems programming language offering C++-like performance and portability, Python-like syntax, Lisp-like flexibility, strong C, C++, JS, Python interop, and best-in-class metaprogramming.
This release includes improvements in the following areas:
- new language features (
iterable[T]
, user-defined literals, private imports, strict effects, dot-like operators, block arguments with optional parameters) - new compiler features (
nim --eval:cmd
, custom nimscript extensions, customizable compiler messages) - major improvements to
--gc:arc
and--gc:orc
- correctness and performance of integer and float parsing and rendering in all backends
- significant improvements in error messages, showing useful context
- documentation generation logic and documentation, in particular
runnableExamples
now works in more contexts - JS, VM and nimscript backend are more consistent with the C backend, allowing more
modules to work with those backends, including the imports from
std/prelude
; the test suite now standardizes on testing stdlib modules on each major backend (C, JS, VM) - support for Apple silicon/M1, 32-bit RISC-V, armv8l, CROSSOS, improved support for NodeJS backend
- major improvements to the following modules:
system
,math
,random
,json
,jsonutils
,os
,typetraits
,wrapnils
,lists
,hashes
including performance improvements - deprecated a number of error prone or redundant features
Why use Nim?
- One language to rule them all: from shell scripting to web frontend and backend, scientific computing, deep learning, blockchain client, gamedev, embedded, see also some companies using Nim.
- Concise, readable and convenient:
echo "hello world"
is a 1-liner. - Small binaries:
echo "hello world"
generates a 73K binary (or 5K with further options), optimized for embedded devices (Go: 2MB, Rust: 377K, C++: 56K) [1]. - Fast compile times: a full compiler rebuild takes ~12s (Rust: 15min, gcc: 30min+, clang: 1hr+, Go: 90s) [2].
- Native performance: see Web Frameworks Benchmark, ray tracing, primes.
- No need for makefiles, cmake, configure or other build scripts, thanks to compile-time function evaluation (CTFE) and dependency tracking [3].
- Target any platform with a C compiler: Android and iOS, embedded systems, micro-controllers, WASM, Nintendo Switch, Game Boy Advance.
- Zero-overhead interop lets you reuse code in C, C++ (including templates, C++ STL), JS, Objective-C, Python (via nimpy).
- Built-in documentation generator that understands Nim code and runnable examples that stay in sync.
Last but not least, macros let you manipulate/generate code at compile time instead of relying on code generators, enabling writing DSLs and language extensions in user code. Typical examples include implementing Python-like f-strings, optional chaining, command line generators, React-like Single Page Apps, protobuf serialization and binding generators.
Installing Nim 1.6
We recommend everyone to upgrade to 1.6:
New users
Check out if your package manager already ships version 1.6 or install it as described here.
Note: earlier this year researchers spotted malware written in Nim programming language which supposedly led to antivirus vendors falsely tagging all software written in Nim as a potential threat, including the Nim compiler, nimble (Nim’s package manager) and so on (core Nim tooling is written entirely in Nim). This has been an ongoing issue ever since - if you have any issues related to this, please report the Nim compiler and associated tooling as false detection to the respective antivirus vendors.
Existing users
If you have installed a previous version of Nim using choosenim
,
getting Nim 1.6 is as easy as:
choosenim update self
choosenim update stable
If you don’t have choosenim
, you can follow the same
install link as above.
Building from source
git clone https://github.com/nim-lang/Nim
cd Nim
sh build_all.sh
The last command can be re-run after pulling new commits.
Note that the csources
repo used was changed to csources_v1
, the new setup
is designed to be forward and backward compatible.
Building from a CI setup
We now have bash APIs to (re-)build Nim from source which hide implementation details,
for example: . ci/funs.sh && nimBuildCsourcesIfNeeded
.
This can be useful for CI when alternatives (using nightly builds or a Docker image) are not suitable;
in fact all the existing CI pipelines have been refactored to use this, see
#17815.
Contributors to Nim 1.6
Many thanks to our recurring and new contributors. Nim is a community driven collaborative effort that welcomes all contributions, big or small.
Backward compatibility and preview flags
Starting with this release, we’ve introduced preview flags of the form -d:nimPreviewX
(e.g. -d:nimPreviewFloatRoundtrip
), which allow users to opt-in to new stdlib/compiler behavior
that will likely become the default in the next or a future release.
These staging flags aim to minimize backward compatibility issues.
We also introduced opt-out flags of the form -d:nimLegacyX
, e.g. -d:nimLegacyCopyFile
,
for cases where the default was changed to the new behavior.
For a transition period, these flags can be used to get the old behavior.
Here’s the list of these flags introduced in this release, refer to the text below for explanations:
-d:nimLegacyCopyFile
-d:nimLegacyJsRound
-d:nimLegacyMacrosCollapseSymChoice
-d:nimLegacyParseQueryStrict
-d:nimLegacyRandomInitRand
-d:nimLegacyReprWithNewline
-d:nimLegacySigpipeHandler
-d:nimLegacyTypeMismatch
-d:nimPreviewDotLikeOps
-d:nimPreviewFloatRoundtrip
-d:nimPreviewHashRef
-d:nimPreviewJsonutilsHoleyEnum
Major new features
With so many new features, pinpointing the most salient ones is a subjective exercise, but here are a select few:
iterable[T]
The iterable[T]
type class was added to match called iterators,
which solves a number of long-standing issues related to iterators.
Example:
iterator iota(n: int): int =
for i in 0..<n: yield i
# previously, you'd need `untyped`, which caused other problems such as lack
# of type inference, overloading issues, and MCS.
template sumOld(a: untyped): untyped = # no type inference possible
var result: typeof(block:(for ai in a: ai))
for ai in a: result += ai
result
assert sumOld(iota(3)) == 0 + 1 + 2
# now, you can write:
template sum[T](a: iterable[T]): T =
# `template sum(a: iterable): auto =` would also be possible
var result: T
for ai in a: result += ai
result
assert sum(iota(3)) == 0 + 1 + 2 # or `iota(3).sum`
In particular iterable arguments can now be used with the method call syntax. For example:
import std/[sequtils, os]
echo walkFiles("*").toSeq # now works
See PR #17196 for additional details.
Strict effects
The effect system was refined and there is a new .effectsOf
annotation that does
explicitly what was previously done implicitly. See the
manual
for more details.
To write code that is portable with older Nim versions, use this idiom:
when defined(nimHasEffectsOf):
{.experimental: "strictEffects".}
else:
{.pragma: effectsOf.}
proc mysort(s: seq; cmp: proc(a, b: T): int) {.effectsOf: cmp.}
To enable the new effect system, compile with --experimental:strictEffects
.
See also #18777 and RFC
#408.
Private imports and private field access
A new import syntax import foo {.all.}
now allows importing all symbols
(public or private) from foo
.
This can be useful for testing purposes or for more flexibility in project organization.
Example:
from system {.all.} as system2 import nil
echo system2.ThisIsSystem # ThisIsSystem is private in `system`
import os {.all.} # weirdTarget is private in `os`
echo weirdTarget # or `os.weirdTarget`
Added a new module std/importutils
, and an API privateAccess
, which allows access
to private fields for an object type in the current scope.
Example:
import times
from std/importutils import privateAccess
block:
let t = now()
# echo t.monthdayZero # Error: undeclared field: 'monthdayZero' for type times.DateTime
privateAccess(typeof(t)) # enables private access in this scope
echo t.monthdayZero # ok
See PR #17706 for additional details.
nim --eval:cmd
Added nim --eval:cmd
to evaluate a command directly, e.g.: nim --eval:"echo 1"
.
It defaults to e
(nimscript) but can also work with other commands, e.g.:
find . | nim r --eval:'import strutils; for a in stdin.lines: echo a.toUpper'
# use as a calculator:
nim --eval:'echo 3.1 / (1.2+7)'
# explore a module's APIs, including private symbols:
nim --eval:'import os {.all.}; echo weirdTarget'
# use a custom backend:
nim r -b:js --eval:"import std/jsbigints; echo 2'big ** 64'big"
See PR #15687 for more details.
Round-trip float to string
system.addFloat
and system.$
now can produce string representations of
floating point numbers that are minimal in size and possess round-trip and correct
rounding guarantees (via the
Dragonbox algorithm).
This currently has to be enabled via -d:nimPreviewFloatRoundtrip
.
It is expected that this behavior becomes the new default in upcoming versions,
as with other nimPreviewX
define flags.
Example:
from math import round
let a = round(9.779999999999999, 2)
assert a == 9.78
echo a # with `-d:nimPreviewFloatRoundtrip`: 9.78, like in python3 (instead of 9.779999999999999)
New std/jsbigints
module
Provides arbitrary precision integers for the JS target. See PR #16409. Example:
import std/jsbigints
assert 2'big ** 65'big == 36893488147419103232'big
echo 0xdeadbeef'big shl 4'big # 59774856944n
New std/sysrand
module
Cryptographically secure pseudorandom number generator, allows generating random numbers from a secure source provided by the operating system. Example:
import std/sysrand
assert urandom(1234) != urandom(1234) # unlikely to fail in practice
See PR #16459.
New module: std/tempfiles
Allows creating temporary files and directories, see PR #17361 and followups.
import std/tempfiles
let tmpPath = genTempPath("prefix", "suffix.log", "/tmp/")
# tmpPath looks like: /tmp/prefixpmW1P2KLsuffix.log
let dir = createTempDir("tmpprefix_", "_end")
# created dir looks like: getTempDir() / "tmpprefix_YEl9VuVj_end"
let (cfile, path) = createTempFile("tmpprefix_", "_end.tmp")
# path looks like: getTempDir() / "tmpprefix_FDCIRZA0_end.tmp"
cfile.write "foo"
cfile.setFilePos 0
assert readAll(cfile) == "foo"
close cfile
assert readFile(path) == "foo"
User-defined literals
Custom numeric literals (e.g. -128'bignum
) are now supported.
Additionally, the unary minus in -1
is now part of the integer literal, i.e.
it is now parsed as a single token.
This implies that edge cases like -128'i8
finally work correctly.
Example:
func `'big`*(num: cstring): JsBigInt {.importjs: "BigInt(#)".}
assert 0xffffffffffffffff'big == (1'big shl 64'big) - 1'big
Dot-like operators
With -d:nimPreviewDotLikeOps
, dot-like operators (operators starting with .
,
but not with ..
) now have the same precedence as .
, so that a.?b.c
is now
parsed as (a.?b).c
instead of a.?(b.c)
.
A warning is generated when a dot-like operator is used without -d:nimPreviewDotLikeOps
.
An important use case is to enable dynamic fields without affecting the
built-in .
operator, e.g. for std/jsffi
, std/json
, pkg/nimpy
. Example:
import std/json
template `.?`(a: JsonNode, b: untyped{ident}): JsonNode =
a[astToStr(b)]
let j = %*{"a1": {"a2": 10}}
assert j.?a1.?a2.getInt == 10
Block arguments now support optional parameters
This solves a major pain point for routines accepting block parameters, see PR #18631 for details:
template fn(a = 1, b = 2, body) = discard
fn(1, 2): # already works
bar
fn(a = 1): # now works
bar
Likewise with multiple block arguments via do
:
template fn(a = 1, b = 2, body1, body2) = discard
fn(a = 1): # now works
bar1
do:
bar2
Other features
For full changelog, see here.
Footnotes
Tested on a 2.3 GHz 8-Core Intel Core i9, 2019 macOS 11.5 with 64GB RAM.
- [1] command used:
nim c -d:danger
. The binary size can be further reduced to 49K with stripping (--passL:-s
) and link-time optimization (--passC:-flto
). Statically linking againstmusl
brings it under 5K - see here for more details. - [2] commands used:
- [3] a separate nimscript file can be used if needed to execute code at compile time before compiling the main program but it’s in the same language