This is one of those little helper functions I miss from my old Ruby days,
where tap():
Yields self to the block, and then returns self.
The primary purpose of this method is to “tap into” a method chain, in order to perform operations on intermediate results within the chain.
puts "Result = ", 123.tap{|i| puts "Double = ", 2*i}
Double = 246
Result = 123
proc tap[T](obj: T, block: proc (obj: var T)) =
block(obj)
result = obj
Not surprisingly the above fails to compile :-)
After a little massaging, I can get it compile but the sample invocation (i.e last line) doesn't :-(
proc tap*[T](obj: T, code: proc(obj: var T)): T =
code obj
obj
let code = proc(i: var int): int {.closure.} =
echo 2*i
result = 321
var num = 123
echo num.tap(code)
The compiler tells me:
temp.nim(10, 9) Error: type mismatch
Expression: tap(num, code)
[1] num: int
[2] code: proc (i: var int): int{.closure, gcsafe.}
Expected one of (first mismatch at [position]):
[2] proc tap[T](obj: T; code: proc (obj: var T)): T
expression 'code' is of type: proc (i: var int): int{.closure, gcsafe.}
As usual, any suggestions would be appreciated
You overcomplicated it. This works:
proc tap*[T](obj: T, code: proc(obj: T)): T =
code obj
obj
let code = proc(i: int) =
echo 2*i
var num = 123
echo num.tap(code)
To make it feel more like the Ruby version, you can use an anonymous proc:
echo num.tap(proc(i: int) = echo 2 * i)
Here is also an anaphoric version (to borrow Lisp terminology) if you prefer:
template tapIt*[T](obj: T, code: untyped): T =
let it {.inject.} = obj
code
obj
var num = 123
echo num.tapIt(echo 2 * it)
This last one is the winner!!
It feels more nim'ish and better still gives me an excuse to use the word anaphoric 🙂
Yes I did overcomplicate it -- I used the var since I thought I might want to mutate the input... probably a bad practice anyways.
Thanks.... It always so simple once you show me the answer... 🙂
Would you mind sharing the source code for debugs? I'm curious to see how it was done.
Thanks
INim 0.6.1
Nim Compiler Version 2.0.4 [MacOSX: amd64] at /Users/dennismisener/.nimble/bin/nim
nim> template tapIt*[T](obj: T, code: untyped): T =
block:
let it {.inject.} = obj
code
it
nim> var num = 123
nim> echo num.tapIt(echo 2 * it)
246
123
nim> echo num.tapIt(echo 2 * it)
Error: redefinition of 'it'; previous declaration here: /private/var/folders/dn/zz9c2pmx3qddx39kj0btzx340000gn/T/inim_1714005760.nim(9, 9)
What about :
INim 0.6.1
Nim Compiler Version 2.0.4 [MacOSX: amd64] at /Users/dennismisener/.nimble/bin/nim
nim> template tapIt*[T](obj: T, code: untyped): T =
.... let it {.inject.} = obj
.... code
.... it
....
nim> var num = 123
nim> echo num.tapIt(echo 2 * it)
246
123
nim> echo num.tapIt(echo 2 * it)
246
123
That's very easy to fix, use a block to avoid clash of identifiers:
template tapIt*[T](obj: T, code: untyped): T =
block:
let it {.inject.} = obj
code
it
var num = 123
echo num.tapIt(echo 2 * it)
echo num.tapIt(echo 3 * it)
var num = 123
echo (echo num * 2; num)
echo (echo (echo num * 3; num) * 4; num)
echo block:
echo num * 4
num