Reputation: 3298
Could someone please explain why the following snippet behaves as it does?
l <- list()
AddFn <- function(str) { l[[length(l) + 1]] <<- function() { return(str) }}
AddFn("hello")
AddFn("there")
l[[1]]() # Returns "hello" as expected
l[[2]]() # Returns "there" as expected
for (letter in letters) AddFn(letter)
l[[3]]() # Returns "z"
I expected l[[3]]()
to return "a". What am I missing? What exactly does my AddFn function do?
Thank you in advance,
Adrian
Upvotes: 3
Views: 117
Reputation: 40821
This is a nasty one. The str
argument is set to a promise that says to return letter
, but it isn't actually evaluated until called via l[[3]]()
. So the value at that point is used!
If you change the last part to:
for (letter in letters) AddFn(letter)
letter="foo"
l[[3]]() # Returns "foo"
...You'll see it more clearly.
...So do what @DWin suggests and call force
first.
Upvotes: 7
Reputation: 263362
Lazy evaluation often results in the last evaluation in a loop getting returned. Try this instead:
AddFn <- function(str) { force(str); l[[length(l) + 1]] <<- function() { return(str) }}
Upvotes: 7