For example, it doesn't seem uncommon for a new programmer to believe that the following function might modify the passed variable itself (rather than a copy):
void add_five( int val ) {
val += 5
}
This code of course does nothing useful in C/C++, because val is just a copy.
One question we might ask then, is what is the most intuitive interpretation of this? If you take a random person off the street who hasn't ever been exposed to programming, would they say that it's more intuitive to assume it won't modify the original or that it will modify the original?
What was your fist intuition when you started programming? I'm curious what it was, if you can remember. I could see people arguing for either of the sides.
So, theoretically if we were designing a language with one of the goals being to eliminate this confusion what might we do? The confusion often comes from the inconsistency that in many languages primitives are passed by value and objects are passed by pointer or reference (and therefore appear to behave differently). Of course, under the hood, a reference is largely just a pointer passed by value and dereferenced automatically, but the way humans think about it still comes into play.
To make it consistent, we could perhaps enforce that all function parameters appear as if they are either all passed by value or all passed by reference. Also, suppose we don't want the programmer to have to deal with pointers directly. In that case, we can't really choose to pass them all by value, because then no function could ever modify it's parameters (remember, I said assume no pointer values). Therefore perhaps we could make everything (including primitives) appear to be passed by reference (with some hidden exceptions).
We could state that all parameters could only be declared syntactically as either being constant references or non-constant references in the syntax of the language. In the case of the constant reference parameters we could have the compiler do some "smoke and mirrors" and compile literal primitive values and constant variables as passed by value (under the hood). If the programmer used it as a reference in the function, it could compile as a reference instead. The idea would be to make it so the programmer didn't have to concern themselves with whether a parameter is more efficient as a value or as a reference, because the compiler would figure it out on its own for those special cases. This is one of the kind of things that a programmer shouldn't have to waste time worrying about, in my opinion.
With these function parameter limitations we would not be able to ever use the parameter as a temporary variable for performing calculations within the function, but this effect is both intentional and fairly beneficial. By forcing the programmer to not be allowed to use the parameters as temporary variables, we also force the programer to retain all initial state information of the function call (except where we intentionally modify referenced data of course). To use temporary variables, a function local variable would have to be declared explicitly, thereby making its use much more obvious.
For example:
// parameters are: constant and reference to int, respectively
int do_something( const int val1, int val2 ) {
int tmp_val1 = val1; //use of temporary variable
...
val2 = 0; //changes the value of the caller's variable
}
Also, it seems wise to me to require that all function calls explicitly acknowledge the possibility of a variable being changed during the function call, to make reading the source easier and more traceable.
For example, we might require that a symbol be placed before every non-constant reference parameter in a function call in order to indicate this. The reason for doing this is to make it very easy for a programmer reading the code to pick out which parameters might be changing during any and all function calls, hence resulting in better and more self-aware code practices and maintainability.
C/C++ programs can partly indicate the possibility of values changing, by consistently using pointers instead of references thereby forcing the user to use the address-of operator (&) where the variable is passed. However, if the variable being passed is already the pointer of this address, then the & will not appear in the function call and it will hence no longer make it as easy to realize that a variable could be being modified there.
Instead, with parameters restricted to references, we would require a "change acknowledgment" symbol that bears a resemblance to the & usage
For example, if "$" was our symbol for indicating the possibility of variable change due to a function call, then a call to a swap function might look like this:
int x; int y; swap( $x, $y ); //explicitly indicates the values x and y might change in the function call
rather than using pointer syntax like so:
int x_val; int y_val; int* x = &x_val; int* y = &y_val; swap( x, y ); //does not explicitly indicate the possibility of change, although we know it will
Together, these two conventions (all parameters appear to act like references, and all function calls must explicitly indicate the possibility of variable change) could, I think, make for a more consistent and less confusing function system for new programmers.
Of course, not having access to pointers is perhaps bad for doing systems programming, like making an operating system. But, you could always include direct pointer access as a feature that can be enabled optionally, for this reason.
What do you think?
Also, are there any languages that already do any of this?











