I'm attempting to make a template that mirrors GNU Awk's split(). In Awk, you don't need to declare the array 'arr' before filled by split:
c = split("abc", arr, "b")
echo arr[0] #=> "a"
Thus far I have
template split*(source: string, dest: untyped, match: string): int =
var dest: seq[string]
dest = newSeq[string](0)
dest = nre.split(source, re("(?s)" & match))
len(dest)
This in fact works with the above example. However it doesn't work like this:
split("abc", arr, "b")
echo arr[0]
Generates an error about discard. {.discardable.} pragma doesn't work in templates, and a template is needed for the "untyped" so that arr doesn't need to be declared beforehand.
Is it possible to "discardable" a template without a "discard" at the point of origin?
I am not sure if it helps, but what you are trying to do doesn't feel like you should do it at all.
proc split*(source: string, match: string): seq[string] =
nre.split(source, re("(?s)" & match))
This is better than what you tried to do, because it is shorter, it uses less complicated features of the language (proc instead of template), and it behaves more expected, because it doesn't magically convert an argument in a new local variable after the call.
But, when it is more about the concept you want to apply, then what is the problem with this:
discard split("abc", arr, "b")
echo arr[0]
Not sure the solution you proposed will do those things. Try running your code, it returns and error "undeclared identifier: 'arr'" .. that's the whole point of the template .. arr was not declared prior to running split() and it works wonderfully using the template method.
I've made a library of Nim proc's to mirror the Awk stdlib to make porting Awk scripts to Nim painless. I've already ported a 5,000+ line Awk program to Nim and it was mostly painless and often a 1:1 match of code the same code in Awk works in Nim ie. cut and paste with minor changes (such as : instead of {} ). This is not a 1 time discard how hard can that be, it's maintaining dozens of differences between the awk vs Nim version code base which I want to keep to a minimum where possible.
import nre except split
proc makeDiscardable[T](a: T): T {.discardable, inline.} = a
template split*(source: string, dest: untyped, match: string): int =
when declaredInScope(dest):
dest = nre.split(source, re("(?s)" & match))
else:
var dest = nre.split(source, re("(?s)" & match))
makeDiscardable dest.len
split("abc", arr, "b") # works ;)
echo arr[0]
let i = split("abc", arr, "b") # works again ;)
echo arr[0]
;)
EDIT: Renamed hackyDiscardable to makeDiscardable ;)