Pregunta

Logo is the first programming language I ever learned as a child. I recently found out that Logo supposedly uses dynamic scoping, which came as a surprise to me because I always thought it just used global variables. This made me wonder if perhaps I didn't understand what dynamic scoping meant.

I thought that with dynamic scoping, a variable would go on a global stack, so then when you called another method the variable would still be visible. (So far, like a global variable.) Then, if you declared a new variable with the same name, this would be pushed on the global stack, hiding the original variable. (At this point, still not much different than assigning a new value to a global variable.) And lastly, when you exited the method, that new assignment would be popped off the stack, and the variable would revert to its original value. (This seems like the key part that makes it dynamic scoping, as opposed to just reassignment of global variables.)

So having heard that Logo used dynamic scoping, I expected this program:

to test1
  make "x "foo
  print (se [In test1: ] :x)
  test2
  print (se [Back in test1: ] :x)
end

to test2
  print (se [In test2: ] :x)
  make "x "bar
  print (se [Still in test2: ] :x)
end

test1

to have this output:

In test1: foo
In test2: foo
Still in test2: bar
Back in test1: foo

But when I run it in FMSLogo, it actually has this output:

In test1: foo
In test2: foo
Still in test2: bar
Back in test1: bar

This actually matches what I remember from when I was a kid, and is consistent with what I'd expect if there's a single global variable named x. But I don't see how this is dynamic scoping -- the variable never goes out of scope!

So why do references, like this one for instance, claim that Logo uses dynamic scoping?

¿Fue útil?

Solución

Logo does have dynamic scoping, but your example doesn't have a local variable, so in the variable set in the test2 function is the global. You would need to use the local keyword instead of the make keyword to create a local variable.

This should demonstrate the dynamic scoping:

to test1 :x
  test2
end

to test2
  print (se [In test2: ] :x)
end

make "x "foo    
test2
test1 "bar

If I got it right (about two decades since I wrote any Logo), it should produce:

In test2: foo
In test2: bar

Calling the test2 function directly uses the global variable, but when called from test1 it will use the parameter that passed into test1 instead of the global variable.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top