I don't think it's unambiguous. There seem to be several different
distinctions being made which are almost independent of each other.
There's the function/procedure distinction in the Pascal sense: A
function returns a value via the return value of the function. A
procedure doesn't have a return value. Either of these can return
values through arguments that are non-const pointer types. That's
pretty unambiguous but when writing in C, I'm not sure the distinction
is useful. Both can pass back information (status or others). Both
can change external state.
If you say that a function can only return information via a "return"
statement, then functions that dont return values (procedures) must do IO,
in fact output, or else what are they doing?
But very few languages actually enforce that. Most allow writing to
globals, or to pointers.
There's the pure/non-pure distinction: a "pure" function generates
output that depends only on its arguments, and has no state, and a
"non-pure" funcedure may reference external variables or internal
static state that changes. A "pure" function call with arguments
known at compile time could be replaced at compile-time with its
resulting value.
So we have the distinction between pure and impure functions, I'm
making a slightly different one. Hence I can't use the term "pure
function" without being highly confusing.
Exactly. Also a mathematical function, which is a mapping of an input
set to an output set.
Those who think that shuffling bits isn't I/O have never gotten
errors like "panic: I/O error in swap", "Uncorrectable ECC error
in main memory", and various complaints about CPU cache malfunctions.
Granted, these problems are rare, and if they're not, you get the
system repaired or junk it and replace it.
You have to assume that the abstract machine is functioning correctly.
If occasionally the act of writing a byte will raise an error which
needs to be handled, the system breaks down.
Now suppose we have one of those Atmel processors that can have
external RAM attached. It has internal registers (often called I/O
registers in the documentation) to control interrupts and timers,
and contain things like the current timer count, the timer count
at which to cause an interrupt, and bits to choose the speed of
the clock that drives it. These are internal to the CPU, so they
are bit-shuffling. It also has RAM which is external to the CPU,
so using RAM must be I/O. Oh, and I haven't specified where it's
fetching the code from, but it's often internal flash.
You need the abstract model of the machine which can write to
memory, which can;t be changed by any external factor. Obviously
for any physical machine, it will be physically possible to
manipulate the bits during function execution. Then the analysis
breaks down.
A Malcom funcedure (we haven't figured out whether it's a Malcom-function
or a Malcom-procedure yet) whose function is to set up a timeout
is just shuffling bits to load the I/O registers, so it's a
Malcom-function. Oh, wait -- if it needs to use RAM (such as for
auto variables), that's external, so it's a Malcom-procedure.
No, because writing to bytes with the intention of creating a
side-effect is doing IO. If we refactor the function so that
program bit state on exit is the same given bit state on entry,
but don't write to the memory-mapped bits, then that doesn't change
a Malcolm-function. It does potentially change a Malcolm-procedure.
A procedure is hardware-dependent, we only know its working
correctly if we have something connected to the memory-mapped
bytes.
However, I may not be able to tell the difference here, so I have
to look at the generated code: if it uses temporary auto variables,
it's a Malcom-procedure, otherwise it's a Malcom-function, and you
can't tell the difference looking at the source code. I guess if
the code is fetched from a flash chip external to the CPU, then
*EVERYTHING* is a Malcom-procedure. I'm not sure the distinction
is worthwhile if it depends on the optimization level of the compiler.
Everything is a procedure if the abstract machine model of reliable,
addressable memory doesn't hold, yes.
A "pure" function can't read global state that someone else changes.
The output depends only on the input.
A pure function is a Malcolm function, assuming it doesn't do any
output. But not all Malcolm functions are pure functions.
Mathematics isn't so cooperative here. Mathematical functions can
have inputs or outputs that are undefined in spots, such as
implementations of the tangent and arctangent functions. The same
applies to square root if you're expecting it to return a real
number rather than complex.
A computer can't express concepts like "every number from +/-
infinity". It can only shuffle discrete bits. So not every mathematical
function can be coded as a Malcolm-function, though most
mathematics that people want practically can.
Most of the time when that kind of distinction is made, it's called
"pure" or "impure". But it doesn't matter where the "pure" function
has state, "internal" (e.g. static variables), or "external" (e.g.
global variables or disk files), a "pure" function can't have state
that anyone modifies.
Yes, we're making a slightly different distinction than the pure/impure
function distinction.