I know there is "when defined(x):" and that it does not create a new scope. There is also the extension for objects definition such that you can create them depending on defined values.
Interested in the implementation of nim-fuse I tripped over some really annoying problems for related cases because I can not even compile it on my mac without a lot of code duplication is done in the lib, which is partial looking really really bad.
I tried to illustrate the problem with some sample code and hope that there is an easy solution to it:
# Sample for problems with conditional code in Nim
let
all = "ALL"
unused = "Not used!"
# needs a new let statement. not to bad.
when defined(macosx):
let
sys = "OSX"
else:
let
sys = "OTHER"
# First problem: Needs multiple times the same code
# It also needs a new type statement (scope)
when defined(macosx):
type num = enum
NUM_NONE = 0
NUM_ALL = 1
NUM_OSX = 10 # only this differs for real
NUM_XTRA = 20
else:
type num = enum
NUM_NONE = 0
NUM_ALL = 1
NUM_XTRA = 20
type MyObject = object
i: int
# This is cool. When works with objects
when defined(macosx):
f: float
else:
f: int
n: num
s: string
a: string
# This works with auto initialising to binary 0 for f
var x = MyObject(i: 1, n: NUM_ALL, s: sys, a: all)
# As it is expected we have extra work here
when defined(macosx):
x.f = 1.2
else:
x.f = 12
echo x
# But now the maybe worst part :(
# Code duplication again.
# Imagine 40 identical + 2 extras/diffs cases
when not defined(macosx):
case x.n:
of NUM_NONE: echo "None"
of NUM_ALL: echo "All"
of NUM_XTRA: echo "Nim"
else:
case x.n:
of NUM_NONE: echo "None"
of NUM_ALL: echo "All"
of NUM_XTRA: echo "Nim"
of NUM_OSX: echo "Mac" # just that is special
I wonder how to handle those cases efficiently. The only idea I have is to use include for duplicated parts but that seems rather odd. I thought the handling for "object" could probably extended to other cases like case/of, enum or even all of type (and var / let)?
If that does not happen, what would be a goo way in the spirit of "dumb" filtering? I know there are filters for Nim sources but I did not looked at them closer yet.
let
all = "ALL"
unused = "Not used!"
sys = when defined(macosx): "OSX" else: "OTHER"
There isn't a really good solution that I know of. A workaround is an immediate macro that filters unused case branches by architecture, but that can be fairly tedious to write and is not necessarily a big improvement. E.g.:
macro platformSpecific(s: stmt): stmt {.immediate.} =
...
platformSpecific:
case x.n:
of NUM_NONE: echo "None"
of NUM_ALL: echo "All"
of NUM_XTRA: echo "Nim"
of NUM_OSX: echo "Mac" # just that is special
The macro would then remove all case branches that are not supported for a specific platform.
Jehan would it be possible write a macro to filter out all "of cases" which have no current enum entry associated or even better which is invalid against the case expression?
That would solve the problems for the case statements I guess. But looses some important checks. Still.
macro filterCaseByEnum(s: strmt, ??enum_type??):
...
filterCaseByEnum(num):
case x.n:
of..
macro filterCaseOfInvalid(s: strmt):
...
I guess what Araq just wrote is in a way similar to filtering the case for invalid values but without loosing checks. Sounds cool and looks like it fits into the language.
Is it hard to do Araq? And could probably the object implementation of when be applied to the enum case?
Besides that: Could one annotate the case:of / enum lines with something (comment? pragmas?) and filter by that in a macro?
It's 1 line of code, perhaps 2. Look at semtypes.nim, line 460 following.
EDIT Ok, it's more work ;-) but simple enough.
Araq If I understand it right then this would compiler afterwards:
let anything = 6502
case anything
of 1: echo "I am the one"
of {}: echo "me not fail"
of {}: echo "me neither"
of (when defined(uwillnevadefthis): 1 else: {}): echo "i could be, but"
else: "me! me! me! pick me!!!11eleven"
I looked into that code but only marginally understand what happens. Afais it checks for empty ()/{} and emits an error (in an for me obscure way). This had to be split into the () and {} case. Then we can accept and drop the {} silently.
As matching the empty set regulary is not needed, this would be a sensible extension to the language targeting conditional compilation only (imho).
Are you going to implement this feature into the language? I think that would be really helpful.
Are you going to implement this feature into the language?
Consider it done.
OK. Cool! I will try to update nim-fuse for OS X as soon as this is in the compiler. It's a pain without!
What about the when in enum? I saw that a related compiler error was fixed (for nim check). Could when be implemented instead? Would be elegant I think!