Adrian
Adrian

Reputation: 3298

Building a list of functions that return strings

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

Answers (2)

Tommy
Tommy

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

IRTFM
IRTFM

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

Related Questions