Version 1.2.0 released

We are very proud to announce Nim version 1.2 after six months of continuous development!

This release contains around 600 new commits which have not already been backported to our 1.0.x versions. There are several new features and standard library additions compared to 1.0. We tried to keep breaking changes to a minimum, but some bugfixes weren’t possible without making those necessary changes, and we feel that our users will benefit from them.

We would recommend to all of our users to upgrade and use version 1.2.

Using multiple Nim versions

useVersion

If you would like to upgrade to version v1.2, but you are relying on v1.0 behaviour, there is a command line switch --useVersion , which you can use with the newest Nim to simulate previous versions.

For example, Nim v1.2 is more strict about type conversions concerning proc types. If this breaks your code, pass --useVersion:1.0 , which will emulate the old behaviour.

This is not limited to the above example. If you were relying on some edge case and/or buggy behaviour which is now fixed, try if --useVersion:1.0 gives you back the results you expect to see. If that doesn’t work and you need the old behaviour, please open an issue in our bug tracker and we will try to make it work in future bugfix releases (1.2.x).

when declared

If you are library author and you would like your library to be available both for v1.0 and v1.2 users, but you are relying on some new features introduced in v1.2 which are not available in v1.0 release, you can use when declared to your advantage.

For example, sequtils module now has the unzip proc. You can write your code like this:

import sequtils when not declared ( unzip ): proc unzip *[ S , T ] ( s : openArray [ ( S , T ) ] ): ( seq [ S ] , seq [ T ] ) = result [ 0 ] = newSeq [ S ] ( s . len ) result [ 1 ] = newSeq [ T ] ( s . len ) for i in 0 .. < s . len : result [ 0 ][ i ] = s [ i ][ 0 ] result [ 1 ][ i ] = s [ i ][ 1 ] let a = @[ ( 'a' , 1 ), ( 'b' , 2 ), ( 'c' , 3 ) ] let b = unzip ( a ) # version 1.0 will use the proc declared above # version 1.2 will use sequtils' proc assert b == ( @[ 'a' , 'b' , 'c' ] , @[ 1 , 2 , 3 ] )

Installing Nim 1.2

New users

Check out if the package manager of your OS already ships version 1.2 or install it as described here.

Existing users

If you have installed a previous version of Nim using choosenim , getting Nim 1.2 is as easy as:

$ choosenim update stable

Contributors to v1.2

Our contributors are amazing, and there is far too many to list here. Big thanks to all of you, we couldn’t have pulled off this release without you!

New features

GC: ARC

--gc:arc is our main new feature for this release!

Instead of going into lots of details and hijacking this release article, we would like to point you to this video from FOSDEM where Araq explains details behind ARC and shows some benchmarks which show the benefits of it.

A more detailed article about ARC might follow in the future.

New sugar macros

Version 1.2.0 introduces several new macros which should help with writing some common tasks.

In the next few sections we will show them and their usages. All the examples imply import sugar .

Collect

collect is a macro which helps with writing seq/set/table comprehensions. It replaces the lc (list comprehension), and it is both more idiomatic and more powerful than lc . There is no overhead for using collect , e.g. you can use newSeqOfCap with it.

The syntax for all collections is similar, with the difference being the init function and the last expression.

Examples:

let numbers = collect ( newSeq ): # or: collect(newSeqOfCap(10)) for i in 1 .. 10 : i assert numbers == @[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] import tables let oddSquares = collect ( initTable ): for i in numbers : if i mod 2 == 1 : { i : i * i } assert len ( oddSquares ) == 5 assert oddSquares [ 7 ] == 49 import sets let oddOrNegative = collect ( initHashSet ): for i in numbers : { if i mod 2 == 1 : i else : - i } assert 5 in oddOrNegative assert 2 notin oddOrNegative assert - 2 in oddOrNegative

Dup

dup is a macro which turns an in-place function into one that returns a result without modifying its input. The idea is that future versions of Nim will offer only in-place versions of the functions (i.e. no more sort and sorted , rotateLeft and rotatedLeft , and so on), which could be transformed to functions returning a copy via dup .

This macro also allows for (otherwise in-place) function chaining.

Examples:

proc makePalindrome ( s : var string ) = for i in countdown ( s . len - 2 , 0 ): s . add ( s [ i ] ) var a = "abc" makePalindrome ( a ) assert a == "abcba" var b = "xyz" var c = b . dup ( makePalindrome ) assert b == "xyz" assert c == "xyzyx"

An underscore ( _ ) can be used to denote the place of the argument you’re passing:

import algorithm # b = "xyz" var d = dup b : makePalindrome # xyzyx sort ( _, SortOrder.Descending) # zyyxx makePalindrome # zyyxxxyyz assert d == "zyyxxxyyz"

Capture

capture is a macro which is useful when creating a closure in a loop to capture some local loop variables by their current iteration values. You might want to use it for example for event handling and {int: callBack} lookup tables.

Example:

import strformat , sugar var myClosure : proc (): string for i in 5 .. 7 : for j in 7 .. 9 : if i * j == 42 : capture i , j : myClosure = proc (): string = fmt"{i} * {j} = 42" let a = myClosure () assert a == "6 * 7 = 42"

Changelog

Standard library additions and changes

Added overloaded strformat.fmt macro that use specified characters as delimiter instead of ‘{‘ and ‘}’.

macro that use specified characters as delimiter instead of ‘{‘ and ‘}’. Added new procs in tables.nim : OrderedTable.pop , CountTable.del , CountTable.pop , Table.pop .

: , , , . Added strtabs.clear overload that reuses the existing mode.

overload that reuses the existing mode. Added browsers.osOpen const alias for the operating system specific “open” command.

const alias for the operating system specific “open” command. Added sugar.dup for turning in-place algorithms like sort and shuffle into operations that work on a copy of the data and return the mutated copy, like the existing sorted does.

for turning in-place algorithms like and into operations that work on a copy of the data and return the mutated copy, like the existing does. Added sugar.collect that does comprehension for seq/set/table collections.

that does comprehension for seq/set/table collections. Added sugar.capture for capturing some local loop variables when creating a closure. This is an enhanced version of closureScope .

for capturing some local loop variables when creating a closure. This is an enhanced version of . Added typetraits.tupleLen to get number of elements of a tuple/type tuple, and typetraits.get to get the ith element of a type tuple.

to get number of elements of a tuple/type tuple, and to get the ith element of a type tuple. Added typetraits.genericParams to return a tuple of generic params from a generic instantiation.

to return a tuple of generic params from a generic instantiation. options now treats proc like other pointer types, meaning nil proc variables are converted to None .

now treats like other pointer types, meaning proc variables are converted to . Added os.normalizePathEnd for additional path sanitization.

for additional path sanitization. Added times.fromUnixFloat,toUnixFloat , sub-second resolution versions of fromUnix , toUnixFloat .

, sub-second resolution versions of , . Added wrapnils module for chains of field-access and indexing where the LHS can be nil. This simplifies code by reducing need for if-else branches around intermediate maybe nil values. E.g. echo ?.n.typ.kind .

module for chains of field-access and indexing where the LHS can be nil. This simplifies code by reducing need for if-else branches around intermediate maybe nil values. E.g. . Added minIndex , maxIndex and unzip to the sequtils module.

, and to the module. Added os.isRelativeTo to tell whether a path is relative to another.

to tell whether a path is relative to another. Added resetOutputFormatters to unittest .

to . Added expectIdent to the macros module.

to the module. Added os.isValidFilename that returns true if filename argument is valid for cross-platform use.

that returns if argument is valid for cross-platform use. Added times.isLeapDay .

. base64 adds URL-Safe Base64, implements RFC-4648 Section-7.

adds URL-Safe Base64, implements RFC-4648 Section-7. Added a new module, std / compilesettings for querying the compiler about diverse configuration settings.

for querying the compiler about diverse configuration settings. Added net.getPeerCertificates and asyncnet.getPeerCertificates for retrieving the verified certificate chain of the peer we are connected to through an SSL-wrapped Socket / AsyncSocket .

and for retrieving the verified certificate chain of the peer we are connected to through an SSL-wrapped / . Added browsers.openDefaultBrowser without URL, implements IETF RFC-6694 Section-3.

without URL, implements IETF RFC-6694 Section-3. Added jsconsole.trace , jsconsole.table , jsconsole.exception for JavaScript target.

, , for JavaScript target. Added distinctBase overload for values: assert 12.MyInt.distinctBase == 12

overload for values: Added new module std/stackframes , in particular setFrameMsg , which enables custom runtime annotation of stackframes, see #13351 for examples. Turn on/off via --stackTraceMsgs:on/off .

, in particular , which enables custom runtime annotation of stackframes, see #13351 for examples. Turn on/off via . Added sequtils.countIt , allowing for counting items using a predicate.

, allowing for counting items using a predicate. Added a with macro for easy function chaining that’s available everywhere, there is no need to concern your APIs with returning the first argument to enable “chaining”, instead use the dedicated macro with that was designed for it. For example:

import std / with type Foo = object col , pos : string proc setColor ( f : var Foo ; r , g , b : int ) = f . col = $ ( r , g , b ) proc setPosition ( f : var Foo ; x , y : float ) = f . pos = $ ( x , y ) var f : Foo with ( f , setColor ( 2 , 3 , 4 ), setPosition ( 0.0 , 1.0 )) echo f

macros.newLit now works for ref object types.

now works for ref object types. macro pragmas can now be used in type sections.

can now be used in type sections. 5 new pragmas were added to Nim in order to make the upcoming tooling more convenient to use. Nim compiler checks these pragmas for syntax but otherwise ignores them. The pragmas are requires , ensures , assume , assert , invariant .

, , , , . system.writeFile has been overloaded to also support openarray[byte] .

has been overloaded to also support . asyncdispatch.drain now properly takes into account selector.hasPendingOperations and only returns once all pending async operations are guaranteed to have completed.

now properly takes into account and only returns once all pending async operations are guaranteed to have completed. sequtils.zip now returns a sequence of anonymous tuples i.e. those tuples now do not have fields named “a” and “b”.

now returns a sequence of anonymous tuples i.e. those tuples now do not have fields named “a” and “b”. distinctBase has been moved from sugar to typetraits and now it is implemented as compiler type trait instead of macro. distinctBase in sugar module is now deprecated.

has been moved from to and now it is implemented as compiler type trait instead of macro. in sugar module is now deprecated. CountTable.mget has been removed from tables.nim . It didn’t work, and it was an oversight to be included in v1.0.

has been removed from . It didn’t work, and it was an oversight to be included in v1.0. tables.merge(CountTable, CountTable): CountTable has been removed. It didn’t work well together with the existing inplace version of the same proc ( tables.merge(var CountTable, CountTable) ). It was an oversight to be included in v1.0.

has been removed. It didn’t work well together with the existing inplace version of the same proc ( ). It was an oversight to be included in v1.0. asyncdispatch.drain now consistently uses the passed timeout value for all iterations of the event loop, and not just the first iteration. This is more consistent with the other asyncdispatch APIs, and allows asyncdispatch.drain to be more efficient.

now consistently uses the passed timeout value for all iterations of the event loop, and not just the first iteration. This is more consistent with the other asyncdispatch APIs, and allows to be more efficient. base64.encode and base64.decode were made faster by about 50%.

and were made faster by about 50%. htmlgen adds MathML support (ISO 40314).

adds MathML support (ISO 40314). macros.eqIdent is now invariant to export markers and backtick quotes.

is now invariant to export markers and backtick quotes. htmlgen.html allows lang in the <html> tag and common valid attributes.

allows in the tag and common valid attributes. macros.basename and basename= got support for PragmaExpr , so that an expression like MyEnum {.pure.} is handled correctly.

and got support for , so that an expression like is handled correctly. httpclient.maxredirects changed from int to Natural , because negative values serve no purpose whatsoever.

changed from to , because negative values serve no purpose whatsoever. httpclient.newHttpClient and httpclient.newAsyncHttpClient added headers argument to set initial HTTP Headers, instead of a hardcoded empty newHttpHeader() .

and added argument to set initial HTTP Headers, instead of a hardcoded empty . parseutils.parseUntil has now a different behaviour if the until parameter is empty. This was required for intuitive behaviour of the strscans module (see bug #13605).

has now a different behaviour if the parameter is empty. This was required for intuitive behaviour of the strscans module (see bug #13605). strutils.formatFloat with precision = 0 has the same behavior in all backends, and it is compatible with Python’s behavior, e.g. formatFloat(3.14159, precision = 0) is now 3 , not 3. .

with has the same behavior in all backends, and it is compatible with Python’s behavior, e.g. is now , not . times.parse now only uses input to compute its result, and not now : parse("2020", "YYYY", utc()) is now 2020-01-01T00:00:00Z instead of 2020-03-02T00:00:00Z if run on 03-02; it also doesn’t crash anymore when used on 29th, 30th, 31st of each month.

now only uses input to compute its result, and not : is now instead of if run on 03-02; it also doesn’t crash anymore when used on 29th, 30th, 31st of each month. httpcore.==(string, HttpCode) is now deprecated due to lack of practical usage. The $ operator can be used to obtain the string form of HttpCode for comparison if desired.

is now deprecated due to lack of practical usage. The operator can be used to obtain the string form of for comparison if desired. std/oswalkdir was buggy, it’s now deprecated and reuses std/os procs.

was buggy, it’s now deprecated and reuses procs. os.walkDir and os.walkDirRec now have new flag, checkDir (default: false). If it is set to true, it will throw if input dir is invalid instead of a noop (which is the default behaviour, as it was before this change), os.walkDirRec only throws if top-level dir is invalid, but ignores errors for subdirs, otherwise it would be impossible to resume iteration.

and now have new flag, (default: false). If it is set to true, it will throw if input dir is invalid instead of a noop (which is the default behaviour, as it was before this change), only throws if top-level dir is invalid, but ignores errors for subdirs, otherwise it would be impossible to resume iteration. The FD variant of selector.unregister for ioselector_epoll and ioselector_select now properly handle the Event.User select event type.

variant of for and now properly handle the select event type. joinPath path normalization when / is the first argument works correctly: assert "/" / "/a" == "/a" . Fixed the edge case: assert "" / "" == "" .

path normalization when is the first argument works correctly: . Fixed the edge case: . xmltree now adds indentation consistently to child nodes for any number of children nodes.

now adds indentation consistently to child nodes for any number of children nodes. os.splitPath() behavior synchronized with os.splitFile() to return “/” as the dir component of /root_sub_dir instead of the empty string.

behavior synchronized with to return “/” as the dir component of instead of the empty string. The deprecated lc macro has been removed from sugar . It is now replaced with the more powerful collect macro.

macro has been removed from . It is now replaced with the more powerful macro. os.relativePath("foo", "foo") is now "." , not "" , as "" means invalid path and shouldn’t be conflated with "." ; use -d:nimOldRelativePathBehavior to restore the old behavior.

is now , not , as means invalid path and shouldn’t be conflated with ; use to restore the old behavior. os.joinPath(a, b) now honors trailing slashes in b (or a if b = “”).

now honors trailing slashes in (or if = “”). base64.encode no longer supports lineLen and newLine . Use base64.encodeMime instead.

Breaking changes

net.newContext now performs SSL Certificate checking on Linux and OSX. Define nimDisableCertificateValidation to disable it globally.

Language changes

An align pragma can now be used for variables and object fields, similar to the alignas declaration modifier in C/C++.

pragma can now be used for variables and object fields, similar to the declaration modifier in C/C++. The =sink type bound operator is now optional. The compiler can now use a combination of =destroy and copyMem to move objects efficiently.

type bound operator is now optional. The compiler can now use a combination of and to move objects efficiently. Unsigned integer operators have been fixed to allow promotion of the first operand.

Conversions to unsigned integers are unchecked at runtime, imitating earlier Nim versions. The documentation was improved to acknowledge this special case. See https://github.com/nim-lang/RFCs/issues/175 for more details.

There is a new syntax for lvalue references: var b {.byaddr.} = expr enabled by import std/decls .

enabled by . var a {.foo.}: MyType = expr now lowers to foo(a, MyType, expr) for non-builtin pragmas, enabling things like lvalue references (see decls.byaddr ).

Compiler changes

The generated JS code uses spaces, instead of mixing spaces and tabs.

The Nim compiler now supports the --asm command option for easier inspection of the produced assembler code.

command option for easier inspection of the produced assembler code. The Nim compiler now supports a new pragma called .localPassc to pass specific compiler options to the C(++) backend for the C(++) file that was produced from the current Nim module.

to pass specific compiler options to the C(++) backend for the C(++) file that was produced from the current Nim module. The compiler now inferes “sink parameters”. To disable this for a specific routine, annotate it with .nosinks . To disable it for a section of code, use { .push sinkInference: off. } … { .pop. } .

. To disable it for a section of code, use … . The compiler now supports a new switch --panics:on that turns runtime errors like IndexError or OverflowError into fatal errors that cannot be caught via Nim’s try statement. --panics:on can improve the runtime efficiency and code size of your program significantly.

that turns runtime errors like or into fatal errors that be caught via Nim’s statement. can improve the runtime efficiency and code size of your program significantly. The compiler now warns about inheriting directly from system.Exception as this is very bad style. You should inherit from ValueError , IOError , OSError or from a different specific exception type that inherits from CatchableError and cannot be confused with a Defect .

as this is style. You should inherit from , , or from a different specific exception type that inherits from and cannot be confused with a . The error reporting for Nim’s effect system has been improved.

Implicit conversions for const behave correctly now, meaning that code like const SOMECONST = 0.int; procThatTakesInt32(SOMECONST) will be illegal now. Simply write const SOMECONST = 0 instead.

behave correctly now, meaning that code like will be illegal now. Simply write instead. The { .dynlib. } pragma is now required for exporting symbols when making shared objects on POSIX and macOS, which make it consistent with the behavior on Windows.

pragma is now required for exporting symbols when making shared objects on POSIX and macOS, which make it consistent with the behavior on Windows. The compiler is now more strict about type conversions concerning proc types: Type conversions cannot be used to hide .raise effects or side effects, instead a cast must be used. With the flag --useVersion:1.0 the old behaviour is emulated.

effects or side effects, instead a must be used. With the flag the old behaviour is emulated. The Nim compiler now implements a faster way to detect overflows based on GCC’s __builtin_sadd_overflow family of functions. (Clang also supports these). Some versions of GCC lack this feature and unfortunately we cannot detect this case reliably. So if you get compilation errors like “undefined reference to __builtin_saddll_overflow ” compile your programs with -d:nimEmulateOverflowChecks .

Bugfixes