I'm guessing there are a few folks on here who started the Coursera course this week. I'm confused by the section on shadowing. Here's the example code (this is SML):
According to the instructor, line 3 is not an assignment statement, but how can it be anything else? It's changing the value of a, but then we're reminded that in ML all variables (poor name...symbols?) are immutable and cannot be changed.
This seems contradictory. It's explained that it doesn't change the value of "a", just creates a new "a" in the local static environment, but that smacks of semantics. The bottom line is, you have a symbol called "a" and at two different points in the code it has two different values.
What am I missing?
"The good news about computers is that they do what you tell them to do. The bad news is that they do what you tell them to do." -- Ted Nelson
I just answered exactly that question on the Coursera forum with my understanding of what he means by it, which I'll repeat here.
I think the reason you can't tell the difference in that example is that they're all top-level bindings, which means they never go out of scope. But if you change the construct so that the scope of the second binding is limited you can see the difference (and it probably works as you'd expect it to in non-functional languages as well):
That final line will bind b to 10, showing that the original value of a hasn't been overwritten. More generally, without assignment there's nothing you can do in the scope-limited block that will change the value of a once you've exited that scope.
I just saw your post on the Coursera forum while searching for answers. Funny.
Using scope does make it somewhat clearer, but I'm still surprised that the compiler allows this at all. I would think that it's similar to trying to reassign a final variable in Java. You shouldn't be able to do that. The fact that it's possible will only lead to mass confusion. To say on the one hand that all variables are immutable and then on the other hand write code that assigns different values to the same variable names is just way too confusing and contradictory.
Somehow I still feel like I'm missing some key concept here. I'll keep searching and reading...
Well, Java has shadowing as well. You can have a method parameter or a local variable clash with a class-level variable. Or a subclass can declare a member variable that shadows a member variable in the super-class. This is just the same as that, only it's more general.
I suppose that generally speaking it would be poor style to reuse variable names like this. Especially if they have different meanings. But when you're using nested functions it can be quite useful to be able to re-use method parameter names sometimes (when the meaning is clear).
There's an example in one of the later lectures showing how the earlier bindings have <hidden value>s when the REPL prints the output of the file. That's intended to show that each binding creates a "new environment", both static and dynamic, rather than updating an earlier 'variable'. It's something you'll quickly get used to with Functional Programming and if you use Clojure, you'll see the same thing in that:
The second def doesn't really update a, it changes the binding for the symbol #'user/a to refer to the value 13. However, in Clojure you can actually get at the underlying Var object itself:
This looks a lot more like assignment - because there is a level of indirection here - but it really gets in the way of understanding the generally immutable nature of functional programming to think of it that way.
And of course Clojure isn't quite as "pure" as ML in terms of immutability. Bindings can be altered, per-thread or globally, and there are specific, limited mutable data types (atom, ref) which are controlled via STM to provide atomic / coordinated transactional updates.