Search code examples
pythoninterpretersly

Can I establish a reference variable that will then let me assign a new value?


I'm writing a script interpreter in Python using Sly. While figuring out how to best write assignment interpretation, I found myself unable to quite understand how to handle the left-hand side being different sorts of values. The scripting language I'm using, the left-hand side could be a variable or a field on an object (possibly a few layers deep). So the following assignments in the scripting language would all be correct:

bob = 4.5
this.speed = 5.3
eachthing.child[prevRef+2].name = "William"

Currently, I have the regular variables stored in a dictionary with type and value. The other sort of "variable" involves object fields which are sometimes a simple reference to the current object that the script is attached to and sometimes a reference to a global object, and it's possible to navigate through a hierarchy of objects (for example, going to the hero, finding his second sword, referencing its magical effect, and getting its name). Thus, it's not a simple lookup in some cases.

Initially writing this for variables, it made sense to look up the variable, verify its existence (and fail with an exception if it doesn't exist), evaluate the right-hand side, check their types against each other, and then assign the value. When thinking through the fields, there are multiple steps to determine where the field exists (FWIW, no operations are allowed in the LHS that would change state) and its details, and it seems slightly wasteful to go through all of those steps to determine the existence of the field, and then do all of the RHS evaluation, and then have to go through the LHS steps to assign a new value.

Is there a way to establish a "reference" like a pointer where I can then use it to assign the new value?

After reading through this article about how variables work in Python, I was pretty certain that it's method of pointing one variable at the other wouldn't allow me to make the assignment, and unfortunately, I was right. I poked around for various "by reference" pages on the web, but they were all discussing passing by ref into functions, not getting a reference to a variable/field.

Alternately, I'm probably looking at creating my own index where the values of the fields are stored in a dictionary such that I can directly access them with a reference value (maybe making that second sword's name accessible with an index of (hero, weapon7, effect, name) although that feels clunky).


Solution

  • All of your assignment operations can be reduced to "set selector S of container C to value V". While Python doesn't let you create a reference value C[S], it certainly lets you pass around the tuple (C, S); that works because Python containers dictionaries, lists, etc.) are effectively reference values.

    (In the case of bob = 4.5, the container is whatever you use to hold global variables and the selector might be the global's index or it might be the name, depending on how you handle globals. But it will certainly be some kind of value.)

    You could use a triple instead, where the first value is a function to call with C and S as arguments. That might turn out to be easier. Or not. You haven't revealed much of your approach so it's difficult to provide an answer which isn't just generalities.