Implementing pass-by-reference argument semantics in an interpreter - programming-languages

Pass-by-value semantics are easy to implement in an interpreter (for, say, your run-of-the-mill imperative language). For each scope, we maintain an environment that maps identifiers to their values. Processing a function call involves creating a new environment and populating it with copies of the arguments.
This won't work if we allow arguments that are passed by reference. How is this case typically handled?

First, your interpreter must check that the argument is something that can be passed by reference – that the argument is something that is legal in the left-hand side of an assignment statement. For example, if f has a single pass-by-reference parameter, f(x) is okay (since x := y makes sense) but f(1+1) is not (1+1 := y makes no sense). Typical qualifying arguments are variables and variable-like constructs like array indexing (if a is an array for which 5 is a legal index, f(a[5]) is okay, since a[5] = y makes sense).
If the argument passes that check, it will be possible for your interpreter to determine while processing the function call which precise memory location it refers to. When you construct the new environment, you put a reference to that memory location as the value of the pass-by-reference parameter. What that reference concretely looks like depends on the design of your interpreter, particularly on how you represent variables: you could simply use a pointer if your implementation language supports it, but it can be more complex if your design calls for it (the important thing is that the reference must make it possible for you to retrieve and modify the value contained in the memory location being referred to).
while your interpreter is interpreting the body of a function, it may have to treat pass-by-referece parameters specially, since the enviroment does not contain a proper value for it, just a reference. Your interpreter must recognize this and go look what the reference points to. For example, if x is a local variable and y is a pass-by-reference parameter, computing x+1 and y+1 may (depending on the details of your interpreter) work differently: in the former, you just look up the value of x, and then add one to it; in the latter, you must look up the reference that y happens to be bound to in the environment and go look what value is stored in the variable on the far side of the reference, and then you add one to it. Similarly, x = 1 and y = 1 are likely to work differently: the former just goes to modify the value of x, while the latter must first see where the reference points to and modify whatever variable or variable-like thing (such as an array element) it finds there.
You could simplify this by having all variables in the environment be bound to references instead of values; then looking up the value of a variable is the same process as looking up the value of a pass-by-reference parameter. However, this creates other issues, and it depends on your interpreter design and on the details of the language whether that's worth the hassle.

Related

How does variable binding work with recursion in Haskell?

I was reading about Haskell and it stated that once a variable is bound to an expression it cannot be rebound for example
x = 10
x = 11
Assign.hs:2:1: error:
Multiple declarations of ‘x’
Declared at: Assign.hs:1:1
Assign.hs:2:1
So if this is the case... how is recursion working where the same variable keeps getting bound to other things? For example
drop n xs = if n <= 0 || null xs
then xs
else drop (n-1) (tail xs)
the variable n... is being bound again and again every time the function recurses. Why is this allowed?
Also if you guys could tell me some key words to search for so I can learn more about this myself I'd highly appreciate it.
Haskell has lexical scoping. When you declare a variable inside a scope, it hides any variable with the same name from an outer scope. For example, in the following program,
x :: Int
x = 5
main :: IO ()
main = do
x <- readLn :: IO Int
print x
If you compile with ghc -Wall, it will compile correctly, but give you the following warnings:
sx-scope.hs:2:1: warning: [-Wunused-top-binds]
Defined but not used: ‘x’
sx-scope.hs:6:10: warning: [-Wname-shadowing]
This binding for ‘x’ shadows the existing binding
defined at sx-scope.hs:2:1
So the x outside main and the x in main are different variables, and the one in the inner scope temporarily hides the one in the outer scope. (Okay, “temporarily” in this example means until main returns, which is as long as the program is running, but you get the concept.)
Similarly, when you declare drop n xs or \n xs ->, n and xs are local variables that only exist during that invocation of the function. It can be called more than once with different values of n and xs.
When a function is tail-recursive, that is, returns a call to itself, the compiler knows it is about to replace the old parameters, which were from a scope that no longer exists, with updated parameters of the same type. So it can re-use the stack frame and store the new parameters in the same locations as the previous ones. The resulting code can be as fast as iteration in a procedural language.
In almost any language, identifiers are only meaningful because they exist in a scope; conceptually a sort of implicit map from names to the things they denote.
In modern languages you usually have (at least) a global scope, and each local scopes associated with each function/procedure. Pseudocode example:
x = 1
print x
x = 2
print x
function plus_one(a):
b = 1
return a + b
print plus_one(x)
x is a name in the global scope, a and b are names in the local scope of the function plus_one.
Imperative languages (and non-pure declarative languages) are generally understood by thinking of those names as mapped to a sort of slot or pigeon hole, into which things can be stored by assignment, and the current connects referred to by using the name. This works only because an imperative step-by-step way of thinking about these programs gives us a way of understanding what "current" means.1 The above example shows this; x is first assigned 1, then printed, then assigned 2, then printed again; we'd expect this to print "1" and then print "2" (and then print "3" from the last line).
Given that understanding of variables as slots that can store things, it's easy to fall into the trap of thinking of the local variables that represent a function's arguments as just slots that get filled when you call the function. I say trap because this is not a helpful way of thinking about function arguments and calls, even in imperative languages. It more or less works as long as each function only ever has one call "in flight" at once, but introducing one of any number of common programming features breaks this model (recursion, concurrency, laziness, closures, etc). That's the misunderstanding at the heart of a number of questions I've seen here on SO, where the poster was having trouble understanding recursive calls, or wanted to know how to access the local variables of a function from outside, or etc.
You should actually think of a function as having a separate scope associated with each call of that function2. The function itself is kind of like a template for a scope, rather than a scope itself (although common language does usually talk about "the scope of a function" as shorthand). If you provided bindings for the function's parameters then you can produce a scope, but a typical function is called many times with different parameters, so there isn't just one scope for that function.
Consider my pseudocode plus_one, with argument a. You could imagine that a is a local name for a variable, and the call plus_one(x) just assigns the contents of x into the slot for a and then starts executing the code of plus_one. But I contend that it's better to think that when you call plus_one on x you're creating a new scope, in which there is a variable called a (containing with the contents of the global scope x at this point), but it is not "the" a variable.
This is vitally important for understanding recursion, even in imperative languages:
function drop(n, xs):
if n <= 0 || null(xs):
return xs
else:
return drop(n - 1, tail(xs))
Here we could try to imagine that there's only one xs variable, and when we make the recursive call to drop we're assigning the tail of the original xs to the xs variable and starting the function's code again. But that falls down as soon as we change it to something like:
function drop(n, xs):
if n <= 0 || null(xs):
return xs
else:
result = drop(n - 1, tail(xs))
print xs
return result
Now we're using xs after the recursive call. What this does is hard to explain if we're imagining that there's only one xs, but trivial if we think of there being a separate xs in a separate scope every time we call drop. When we make the recursive call to drop (passing it n - 1 and tail(xs)) it creates its own separate xs, so it's entirely unmysterious that print xs in this scope still can access xs.
So, is this story different with Haskell? It's true that the nature of variables is quite different in Haskell than from typical recursive languages. Instead of scopes mapping names to slots in which we can place different contents at different times, scopes map names directly to values, and there's no notion of time in which we could say an identifier "was" bound to one value (or was not bound to anything) and "now" is bound to a different value. x = 1 at global scope in Haskell isn't a step that "happens" and changes something, it's just a fact. x just is 1. Haskell isn't throwing an error at your x = 10 and x = 11 lines because the designers wanted to restrict you to only assigning a variable once, rather Haskell does not have a concept of assignment at all. x = 10 is giving a definition for x in that scope, and you can't have two separate definitions for the same name in the same scope.
The local scopes that come from functions in Haskell are the same; each name just is associated with a particular value3. But the actual values are parameterised on the values on which you call the function (they are quite literally a function of those values); each call has its own separate scope, with a different mapping from names to values. It's not that at each call n "changes" to become bound to the new argument, just that each call has a different n.
So recursion affects variable binding in Haskell in pretty much the same way it does in all major imperative languages. What's more, the extremely flippant way to describe how recursion affects name binding in all of these languages is to say "it doesn't". Recursion actually isn't special at all in this way; parameter passing, local scopes, etc, works exactly the same way when you call a recursive function as when you call an "ordinary" non-recursive functions, provided you understand the local scopes as being associated with each call of the function, not as a single thing associated with the function.
1 Sometimes even the scope mapping itself is mutable, and entries mapping names to slots can be added and removed as steps of the program. Python, for example, has a mutable global scope (in each module); you can add and remove module global variables dynamically, even with names determined from runtime data. But it uses immutable local scopes: a function's local variables exist even before they've been assigned a value (or after that value has been removed with del).
2 At least, this is how functions/procedures very common work in modern languages. It's not totally universal, but it's generally acknowledged to be a good way for functions/procedures to work.
3 Of course, thanks to laziness the particular value might be the bottom value, which is the "value" we pretend is the value of infinite loops and other forms of nontermination, so that we can interpret expressions as always having a value.
From https://en.wikibooks.org/wiki/Haskell/Variables_and_functions,
Within a given scope, a variable in Haskell gets defined only once and cannot change.
but scope isn't just the code of the function. Roughly, it's the code of function + its context, i.e. the arguments it's been called with, and anything from its outer scope. This is often referred to as a closure. Every time you call a function, the code runs under a new closure, and so the variables can evaluate to different things.
The recursive case isn't anything special with regards to this: a function being called twice by other code would run with a different closure, and its internal variables can evaluate to different things.

What are the inner workings of the post-increment operator?

I want to know about the inner functionality to execute post-increment or post-decrement operations in any programming language, such as java or c++.
I mean, how can something (function,method...) return a value and then perform operations on it afterwards?
It's not quite accurate to say that the post-increment/decrement operators operate on the value after returning it. The semantics of these operators, as they're defined in Java, C++ and probably all other languages that have such operators, are that they modify the value and then return the old value.
We could define a C++ function that exactly mimics the behavior of ++1 like this:
int post_inc(int& x) {
int old_x = x;
x = x + 1;
return old_x;
}
In terms of the generated assembly, the most straight-forward way to implement postincrement (assuming the variable resides in a register) is to copy it into a second register, increment the first register, and then use the second register in whichever expression the x++ was used in. If necessary the variable is read from memory into the first register at the beginning and written from the first register back into memory after the increment.
In many cases optimizing compilers will then re-arrange the code to just use one a single register, which is incremented after the expression (but that's not possible in all cases - for example it wouldn't work if the variable itself is used in the same expression (barring undefined behavior in C or C++)).
In terms of Java bytecode the implementation is: push the current value of the variable onto the stack, increment the variable (without touching the stack), then evaluate the expression that used x++.
1 Minus undefined behavior because function calls introduce a sequence point

In Python, how to know if a function is getting a variable or an object?

How can you test whether your function is getting [1,2,4,3] or l?
That might be useful to decide whether you want to return, for example, an ordered list or replace it in place.
For example, if it gets [1,2,4,3] it should return [1,2,3,4]. If it gets l, it should link the ordered list to l and do not return anything.
You can't tell the difference in any reasonable way; you could do terrible things with the gc module to count references, but that's not a reasonable way to do things. There is no difference between an anonymous object and a named variable (aside from the reference count), because it will be named no matter what when received by the function; "variables" aren't really a thing, Python has "names" which reference objects, with the object utterly unconcerned with whether it has named or unnamed references.
Make a consistent API. If you need to have it operate both ways, either have it do both things (mutate in place and return the mutated copy for completeness), or make two distinct APIs (one of which can be written in terms of the other, by having the mutating version used to implement the return new version by making a local copy of the argument, passing it to the mutating version, then returning the mutated local copy).

Manipulating/Clearing Variables via Lists: Mathematica

My problem (in Mathematica) is referring to variables given in a particular array and manipulating them in the following manner (as an example):
Inputs: vars={x,y,z}, system=some ODE like x^2+3*x*y+...etc
(note that I haven't actually created variables x y and z)
Aim:
To assign values to the variables in the list "var" with the intention of inputting these values into the system of ODEs. Then, once I am done, clear the values of the variables in the array vars so that it is in its original form {x,y,z} (and not something like {x,1,3} where y=1 and z=3). I want to do this by referring to the positional elements of vars (I aim not to know that x, y and z are the actual variables).
The reason why: I am trying to write a program that can have any number of variables and ODEs as defined by the user. Since the number of variables and the actual letters used for them are unknown, it is necessary to perform manipulations with the array itself.
Attempt:
A fixed number of variables is easy. For the arbitrary case, I have tried modules and blocks, but with no success. Consider the following code:
Clear[x,y,z,vars,svars]
vars={x,y,z}
svars=Map[ToString,vars]
Module[{vars=vars,svars=svars},
Symbol[svars[[1]]]//Evaluate=1
]
then vars={1,y,z} and not {x,y,z} after running this. I have done functional programming with lists, atoms etc. Thus is makes sense to me that vars is changed afterwards, because I have changed x and not vars. However, I cannot get "x" in the list of variables to remain local. Of course I could put in "x" itself, but that is particular to this specific case. I would prefer to put something like:
Clear[x,y,z,vars,svars]
vars={x,y,z}
svars=Map[ToString,vars]
Module[{vars=vars,svars=svars, vars[[1]]},
Symbol[svars[[1]]]//Evaluate=1
]
which of course doesn't work because vars[[1]] is not a symbol or an assignment to a symbol.
Other possibilities:
I found a function
assignToName[name_String, value_] :=
ToExpression[name, InputForm, Function[var, var = value, HoldAll]]
which looked promising. Basically name_String is the name of the variable and value is its new value. I attempted to do:
vars={x,y,z}
svars=Map[ToString,vars]
vars[[1]]=//Evaluate=1
assignToName[svars[[1]],svars[[1]]]
but then something likeD[x^2, vars[[1]]] doesn't work (x is not a valid variable).
If I am missing something, or if perhaps I am going down the wrong path, I'm open to trying other things.
Thanks.
I can't say that I followed your train(s) of thought very well, so these are fragments which might help you to answer your own questions than a coherent and fully-formed answer. But to answer your final 'question', I think you may be going down some wrong path(s).
In passing, note that evaluating the expression
vars = {x,y,z}
does in fact define those three variables though it doesn't define any rewrite rules (such as values) for them.
Given a polynomial poly you can extract the variables in it with the function Variables[poly] so something like
Variables[x^2+3*x*y]
should return
{x,y}
Note that I write 'should' rather than does because I don't have Mathematica on this machine so my syntax may be a bit wonky. Note also that your example ODE is nothing of the sort but it strikes me that you can probably write a wrapper to manipulate an ODE into a form from which Variables can extract the variables. Mathematica offers a lot of other functions for picking expressions apart and re-assembling them, follow the trails from Variables. It often allows the use of functions defined on Lists on expressions with other heads too so it's always worth experimenting a bit.
There are a couple of widely applicable ways to avoid setting values of variables in Mathematica. For instance, you could write
x^2+3*x*y/.{x->2,y->3}
which will evaluate to
22
but not set values for x and y. This is a very simple example of using (sets of) replacement rules for temporary assignment of values to variables
The other way to avoid setting values for variables is to define functions using Modules or Blocks both of which define their own contexts. The documentation will tell you all about these two and the differences between them.
I can't help thinking that all your clever tricks using Symbol, ToExpression and ToString are a bit beside the point. Spend some time familiarising yourself with Mathematica's in-built functionality before going further down that route, you may well find you don't need to.
Finally, writing, in any language, expressions such as
vars=vars,svars=svars
will lead to madness. It may be syntactically correct, you may even be able to decrypt the semantics when you first write code like that, but in a week's time you will curse your younger self for writing it.

Call by need: When is it used in Haskell?

http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_need says:
"Call-by-need is a memoized version of call-by-name where, if the function argument is evaluated, that value is stored for subsequent uses. [...] Haskell is the most well-known language that uses call-by-need evaluation."
However, the value of a computation is not always stored for faster access (for example consider a recursive definition of fibonacci numbers). I asked someone on #haskell and the answer was that this memoization is done automatically "only in one instance, e.g. if you have `let foo = bar baz', foo will be evaluated once".
My questions is: What does instance exactly mean, are there other cases than let in which memoization is done automatically?
Describing this behavior as "memoization" is misleading. "Call by need" just means that a given input to a function will be evaluated somewhere between 0 and 1 times, never more than once. (It could be partially evaluated as well, which means the function only needed part of that input.) In contrast, "call by name" is simply expression substitution, which means if you give the expression 2 + 3 as an input to a function, it may be evaluated multiple times if the input is used more than once. Both call by need and call by name are non-strict: if the input is not used, then it is never evaluated. Most programming languages are strict, and use a "call by value" approach, which means that all inputs are evaluated before you begin evaluating the function, whether or not the inputs are used. This all has nothing to do with let expressions.
Haskell does not perform any automatic memoization. Let expressions are not an example of memoization. However, most compilers will evaluate let bindings in a call-by-need-esque fashion. If you model a let expression as a function, then the "call by need" mentality does apply:
let foo = expression one in expression two that uses foo
==>
(\foo -> expression two that uses foo) (expression one)
This doesn't correctly model recursive bindings, but you get the idea.
The haskell language definition does not define when, or how often, code is invoked. Infinite loops are defined in terms of 'the bottom' (written ⊥), which is a value (which exists within all types) that represents an error condition. The compiler is free to make its own decisions regarding when and how often to evaluate things as long as the program (and presence/absence of error conditions, including infinite loops!) behaves according to spec.
That said, the usual way of doing this is that most expressions generate 'thunks' - basically a pointer to some code and some context data. The first time you attempt to examine the result of the expression (ie, pattern match it), the thunk is 'forced'; the pointed-to code is executed, and the thunk overwritten with real data. This in turn can recursively evaluate other thunks.
Of course, doing this all the time is slow, so the compiler usually tries to analyze when you'd end up forcing a thunk right away anyway (ie, when something is 'strict' on the value in question), and if it finds this, it'll skip the whole thunk thing and just call the code right away. If it can't prove this, it can still make this optimization as long as it makes sure that executing the thunk right away can't crash or cause an infinite loop (or it handles these conditions somehow).
If you don't want to have to get very technical about this, the essential point is that when you have an expression like some_expensive_computation of all these arguments, you can do whatever you want with it; store it in a data structure, create a list of 53 copies of it, pass it to 6 other functions, etc, and then even return it to your caller for the caller to do whatever it wants with it.
What Haskell will (mostly) do is evaluate it at most once; if it the program ever needs to know something about what that expression returned in order to make a decision, then it will be evaluated (at least enough to know which way the decision should go). That evaluation will affect all the other references to the same expression, even if they are now scattered around in data structures and other not-yet-evaluated expressions all throughout your program.

Resources