Early hardware segment descriptors provided variants that granted or denied the user program write access to the data. Modern memory mapping hardware provides such discrimination. The language Mary was a variant of Algol68 that split the Algol68 concept reference into two that I will call here reference and view. The reference is close enough to C’s pointer concept for the descriptive purposes here. If I understood ANSI’s const construct I could contrast the two schemes. There are two things that one can do to a reference, read it, (dereference it) and perform an assignment statement using the reference as the value of the left side of the assignment statement. In Mary there is an additional thing that can be done with a reference, derive a view from a it. The view can be read (dereferenced or deviewed) but cannot serve in an assignment statement. Being a new type (mode in Algol68) it is possible to qualify parameters as being views. This would cause mechanisms that match arguments to parameters to disallow passing a view as argument to a reference as parameter. Thus a routine might have write access to some data and choose to pass only the ability to read that data to a subroutine. If the routine had only a view of some data then it could not modify that data nor pass modification authority (a reference) to another routine. All of these checks are done at compile time.
Pierce notes the construct Source from Forsythe that is just like my view and probably earlier.
With this background we come to the issue of routines. Whereas references convey the ability to produce side effects views do not. The concept of pure procedures has sometimes been taken to mean that calling the routine would have no effect beyond producing a value and returning it. I am not aware of any language support for this. PL/I has the REDUCIBLE attribute that advised the compiler that expressions involving references to a reducible routine could participate in common expression elimination. Thus sqrt(x) + 1./sqrt(x) need not invoke sqrt twice. The compiler did not verify that sqrt was indeed free of side effects.
The Keykos factory can provide capabilities known by the invoker to be side effect free; even when the invoker does not trust the writer of the code that defines the capability’s function. The factory discipline must be imposed from the beginning of the design of the function. Sub functions of the function must likewise conform to factory discipline.
Another idea may be more applicable to language design. This idea arose from the perspective of the Actors program paradigm. In that paradigm the concept of subroutine is supplanted with more primitive mechanisms. I will describe the actors concept here as a goto with parameters. One of the parameters is a continuation which is a goto with a parameter. In plain english a continuation says what to do after you have computed your thing. It is a pointer to code and thus an opportunity to commence executing that code while transferring the computed value so to be available to that code. In other words a goto with parameters.
It is sort of like C discovered 0 but never got around to revamping their notation to start out at the most primitive construct and build from there. In C’s favor it can express the declaration int * * const * q. Algol68 can’t say that but Mary can say ref ref view ref Int, which means the same thing.
I modified one of my C programs of about 1000 lines by putting const everywhere it was syntactically valid and did not make my program fail. Only about 5% of such sites were inappropriate for const. My programs would be much easier to understand if const were the default. The compiler could optimize more often too.