Preben already answered the basic question how Maple keeps track of local variables: by their address. Other than that, the x are in fact indistinguishable. Except that, if you e.g. try to subs(x=<something>,...) the subs will silently fail and not do anything visible. Made me tear my hair out when I first ran into this situation (due to an unrelated mistake).
The reason why this happens is that you returned an unassigned local variable, which just returns the variable itself. It isn't quite clear to me why you would want to do that, but of course there maybe perfectly valid reasons I just haven't encountered yet. The fact that you cannot do anything with this variable makes some sense: it is procedure-local and not supposed to be visible outside of the proc, much less changeable. It is a bit confusing, however, as no distinction is made.
But what if you actually want to get access to the x? One way to achieve that is to wrap the whole proc in a module and then have x be an export of the module. Like this:
#local x; # turn this off
Run the proc (I use the long form here):
x := 99
and you can access both xes:
If you load module bar using with(bar) [you may need to use option package to do this] then x will implicitly refer to bar:-x and you need to say :-x to get at the x you assigned 99 to [assuming you assign to x first and then use with(bar)]. In this case you have created a new namespace (bar:-) that can be used to keep variables apart.
Finally, in this case repeated calls to foo will not create new instances of x, naturally, as x belongs to module bar. If you want to create several instances of bar you need to use the copy() function; if you assign bar to two different variables you just get two pointers to the same instance.
Obviously now we are on our way to do "OOP lite" in Maple, a feature introduced in Maple 15 that I quite like and use often in my larger packages.
Thanks for the question/post; it exposed an interesting peculiaroty of Maple.