type
IntOrString = int | string
template doSth*(x: IntOrString): untyped =
when x is int:
echo $(x + 1)
else:
echo $(x & "1")
when isMainModule:
doSth(2) # prints 3
doSth("X") # prints X1
var myBool = true
if myBool: # this obviously works as well
doSth(2)
else:
doSth("X")
##################
doSth(if myBool: 2 else: "X") # got string, but expected int
# let's trick the compiler
var param: IntOrString =
if myBool: 2 # got string, but expected int
else: "X"
var param2: int = # but a non-generic variable
if myBool: 2 # works fine
else: 3
# let's try to trick the compiler again
var param3: IntOrString # invalid type IntOrString for var
Is there any way to be able to do something like doSth(if myBool: 2 else: "X"), without being forced to repeat the whole thing over and over again?
P.S. obviously the issue is about a much more complex construct, but apparently I cannot seem to make even this one "work".
if myBool: 2 else: "X"
is invalid because it is only determined at runtime which type it will be. Hence the compiler can't know at compile-time which type the expression has. If you can use when instead of if I think it could work, but the myBool needs to be known at compile-time.
If you only know the value of it at runtime, then you have to do something along a case object or write a macro that rewrites the if-statement to something the compiler can predict the types of.
I totally get what you mean...
The problem is that if there are 3-4 "switches" like myBool, I would end up writing a vast if-else tree just to call doSth with different (compile-time) known params.
And, yes, I'm not expecting the final binary would be different; it would still lead to an enormous mess...
The truth is it's very difficult to show what I mean exactly since the actual code is fairly complicated (right now, I don't even I know what I'm doing...)
But let's say the starting point is: https://github.com/arturo-lang/arturo/blob/master/src/library/Iterators.nim#L58-L134 (now imagine, a couple of the existing params, e.g. collection may also be of different types...)
Is iterateThrough equivalent of doSth in your example above? Or is it the body of it that you want to use things like this in?
if myBool: 2 else: "X"
Ok, then I think I understand a bit of the problem. I have written a quick macro (bugs may exist) expandIfCall which let's you write inline if-statements like you showed earlier: https://play.nim-lang.org/#ix=4ga3
What it does is essentially if you write:
expandIfCall fun(if cond1: a else: b)
It will expand it to:
if cond:
fun(a)
else:
fun(b)
It should also work with multiple arguments:
expandIfCall fun(if cond1: a else: b, if cond2: c else: d)
And rewrite it to the much more verbose:
if cond1:
if cond2:
fun(a, c)
else:
fun(a, d)
else:
if cond2:
fun(b, c)
else:
fun(b, d)
I hope could be useful as a starting point at least for what you want to achieve.
That definitely looks like a promising approach, at least until I figure out how to clean up the core idea...
Thanks a lot for the input!