I don't think adding a nil check will become the performance bottleneck. Here
is my test code:
import times
proc MulDiv*(P1: int32, P2: int32, P3: int32): int32 {.stdcall,
discardable, dynlib: "kernel32", importc.}
proc test(s: cstring) =
# do someting, to make sure the loop will not be eliminated by the
compiler
MulDiv(cast[int32](s), cast[int32](s), cast[int32](s))
var
s1: string
s2 = "abc"
count = 100000000
start: float
start = cpuTime()
for i in 1..count:
test(cast[cstring](0))
test(cast[cstring](-1))
echo cpuTime() - start, " (loop only)"
start = cpuTime()
for i in 1..count:
test(s1)
test(s2)
echo cpuTime() - start, " (default convert)"
start = cpuTime()
for i in 1..count:
test(cast[cstring](cast[uint](s1) + (if s1.isNil: 0 else: 8)))
test(cast[cstring](cast[uint](s2) + (if s2.isNil: 0 else: 8)))
echo cpuTime() - start, " (safe convert)"
start = cpuTime()
for i in 1..count:
test(if s1.isNil: nil else: s1)
test(if s2.isNil: nil else: s2)
echo cpuTime() - start, " (worst code)"
Output
3.33 (loop only)
3.504 (default convert)
3.476999999999999 (safe convert)
24.2 (worst code)
nim -d:release --opt:speed
0.855 (loop only)
1.107 (default convert)
1.138 (safe convert)
3.684 (worst code)
After optimization, there is no conditional jump in the asm output for safe
convert:
mov edx, DWORD PTR _s1_121012_755421110
mov DWORD PTR _i_121068_755421110, ebx
cmp edx, 1
sbb eax, eax
not eax
and eax, 8
add eax, edx
Most people will use the WORST CODE to check nil, right? So in my opinion, add
the check by compiler is clever.