There are several reasons, next are just a couple. Suppose, there is a code that receives a variable x
and accesses a field foo
on it, and one time this variable is attached to an object of type Bar
, other time it is attached to an object of type Baz
, both have other fields and there is no relationship between the two. The access x.foo
is valid in both cases, but because the classes are completely unrelated, it's difficult to map the identifier foo
to some integer that can be later used to quickly access the desired field: its location and its type may be unpredictable. To add some reality, imagine that some other classes may come and go in the system, and they also may have the field foo
.
Another scenario has nothing to do with object-oriented approaches and was learned at the time when LISP and similar languages were invented. They allow to compute not only what is statically written in the code, but also to evaluate some terms at run-time. The terms may be retrieved, e.g. as plain strings, from external files, databases, network, etc. and then interpreted with a special function, often called eval
. Of course, the dynamically computed terms may refer to existing variables. And there is no other way to do it except by their names.
However it seems reasonable that some variable accesses are optimized at run-time. The key issue is that it can be done only in some specific circumstances, not most of the time like in statically-typed languages.