How can I use expression inside formatted string in Nim?

Viewed 320

The if expression is not working if used inside of fmt string.

Why, and how to make it work?

import strformat

let v = if true: 1 else: 2 # <= Works
echo fmt"{v}"

echo fmt"{if true: 1 else: 2}" # <= Error
2 Answers

why?

because fmt uses : to separate value of expression from format specifier so (see docs and implementation) the line

echo fmt"{if true: 1 else: 2}"

is expanded by the macro into

var temp = newStringOfCap(educatedCapGuess)
temp.formatValue if true, " 1 else: 2"
temp

which clearly does not compile.

how?

update

currently (April 2021) in devel branch there is a enhancement that allows to use any expression inside a formatted string. For the specific case mentioned you need to surround the expression by parenthesis:

echo fmt"{(if true: 1 else: 2)}"

the new enhancements also allow to use curly brackets in expression (escaping them).

See:

This enhancement will be released for the general public in the next stable version (likely to be 1.6).

old content

I guess it could be seen as a limitation of fmt and I do not think there is currently a way to use an expression with : in fmt where it does not act as a format specificier.

One way to fix this would be to provide an additional formatSpecifierSeparator keyword argument in order to change the default : and be able to do something like:

echo "{if true: 1 else: 2}".fmt('|')

Another way would be to change the implementation of strformatImpl and make sure that the part before a : actually compiles before interpreting : as a formatSpecifier separator.

Both of these ways imply a PR in nim-lang code and would be available after next release or on devel, if accepted and merged.

this works:

import std/strformat
let x = 3.14
assert fmt"{(if x!=0: 1.0/x else: 0):.5}" == "0.31847"
assert fmt"{(if true: 1 else: 2)}" == "1"
assert fmt"{if true\: 1 else\: 2}" == "1"

and avoids conflicts with format specifier. See https://github.com/nim-lang/Nim/pull/17700 for more details.

Related