Programming intro book ch1 and ch2 (Windows/Python 3) - Request For Comments

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Dec 19 01:02:51 EST 2009


On Sat, 19 Dec 2009 04:04:51 +0100, Alf P. Steinbach wrote:

> * Steven D'Aprano:
>> On Fri, 18 Dec 2009 19:00:48 +0100, Alf P. Steinbach wrote:
>> 
>>> In fact almost no Python
>>> code does, but then it seems that people are not aware of how many of
>>> their names are constants and think that they're uppercasing constants
>>> when in fact they're not. E.g. routine arguments
>> 
>> Routine arguments are almost never constants, since by definition they
>> will vary according to the value passed by the caller.
> 
> I'm sorry, but that requires a definition of "constant" that explicitly
> excludes routine arguments, 

/s/explicitly/implicitly


> which is like saying horses are not mammals, just "because".

No, it's like saying that horses are not apes, because the definition of 
apes excludes horses.

But in any case, rather than continue my argument (which was absolutely 
brilliant and flawless, I might add... *wink*), I'm going to skip ahead 
to the place where the penny drops and I understand what you were trying, 
but failed, to say.


> Consider some C++ code:
> 
>    void foo( SomeType const v )
>    {
>        // Here the name v is constant: that name's value can't change.
>        // (Except that in C++ you can do anything by using low-level
>        stuff.)
>    }

*penny drops*

Ahaha!!! Now I get it! You want to make the *parameter* of the function a 
constant, rather than the *argument* passed to the function. In other 
words, you want to prohibit something like this:

def f(x):
    y = x + 1  # do something with the value passed by the caller
    x = 0  # changing the binding will fail INSIDE the function
    
while still allowing the caller to call the function with variables.


Right -- now what you say makes sense, and is a perfectly reasonable 
thing to do in languages that support constants.

You weren't clear about what you wanted, and the only thing I could think 
of which matched your description was something completely bizarre: given 
some function f with one parameter, you wanted to declare that parameter 
as a constant with some value (say 42), so that calling the function with 
an argument of any other value would be an error, e.g.:

x = 42
f(x)  # succeeds
x = 43
f(x)  # fails

E.g. implemented something like this:

def f(x):
    if x != 42:
        raise ConstantError('x is not the constant 42')
    ...

except that the test is done automatically by the compiler.


> To be pedantic, original routine names are usually absolutely not meant
> to be assigned to.
> 
> If you have
> 
>    def foo(): whatever()
> 
> you simply shouldn't, in general, do
> 
>    foo = bar
> 
> I think you understood that, i.e., that the above comment of yours is
> just rhetoric?

First of all, I think you're underestimating the usefulness and frequency 
of rebinding names to functions. I'll accept that it's uncommon, but it's 
not *that* uncommon to justify "absolutely not meant to be assigned to".

In fact, it's so common that we have special syntax for one special case 
of it. Instead of:

def f():
    ...

f = g(f)

we can write:

@g
def f():
    ...

While decorator syntax can only be used at function-definition time, the 
concept of function decoration is far more general. You can decorate any 
function, at any time, and doing so is very, very useful for (e.g.) 
debugging, logging, monkey-patching, introspection, error-checking, and 
others. And decoration itself is only one special case of function 
rebinding.

As for your second point, my earlier comment is mostly aimed at what I 
see as your misleading habit of referring to *names* as being constants, 
rather than the value assigned to the name. Such terminology is 
misleading. So if you want to call that rhetoric, I won't argue.



>> As far as I know, no programming language provides a standard facility
>> for renaming entities, be they data or routines:
> 
> Eiffel (IIRC) and C++ come pretty close.
> 
> E.g., in C++:
> 
>    int a;
>    int& b = a;    // A new name for a.
> 
>    b = 123;  // Assigns to a.

No, that's not a renaming operation. a still exists; you haven't told the 
compiler "stop accepting a as the name for this memory location, and 
accept b instead". It's an aliasing operation: name b and name a both 
refer to the same memory location and hence the same value.

Even if C++ had an operation for "delete this name from the compiler's 
symbol table" (equivalent to del in Python), that's still a two-step 
process: create a new name that co-exists with the original name, then 
delete the original name. The fact that the C++ designers didn't see fit 
to give the language a way to change a name demonstrates that it's not 
the mutability of *names* which matter, but of *values* assigned to the 
names.

I can think of a language where it would probably be possible, but non-
standard, to write a rename instruction: Forth. It should be possible to 
use the tick instruction to get the address of a variable, constant or 
function, then directly manipulate the compiler's dictionary (not like 
Python dictionaries!) to change the name. But even Forth doesn't provide 
a rename instruction as standard.


> Well, you're off on the wrong track as far as convincing me about
> something is concerned. First, your belief about renaming not being
> supported by any languages is largely incorrect, as shown above.
> Secondly, I was not talking about renaming things  --  that creative
> interpretation is pretty meaningless...

But if you talk about mutating *names*, then what else could it mean than 
that you want to change the *name*? I can only respond to what you write, 
not what you were thinking.

You wrote "routine names are usually constants, absolutely not meant to 
be modified". Forget all about routines. If you had written:

"int names are usually constants, absolutely not meant to be modified"

then I'm sure you and I would agree: such a claim confuses the name with 
the value assigned to the name. It's literally true that given an int n, 
it is not usual to modify the *name* n regardless of whether n is a 
variable or a constant. But that's irrelevant to the question of whether 
n is a variable or a constant. That depends on the *value* assigned to n, 
not the name itself. Exactly the same applies to functions.

If you think I'm harping on a trivial point of terminology, I guess 
you're half-right: I can *guess* what you mean to say, namely that 
function objects themselves are meant to be unmodified, and in Python it 
is unusual to rebind names once they have been bound to a function. 
(Unusual but not vanishingly so.) But that's just an assumption, and you 
know what they say about assumptions.

Judging by what you actually say, and not what I assume you mean, your 
reason for believing functions are constants is incorrect and illogical. 
In languages that treat functions as constants, functions aren't treated 
as constant because the name of the function is unchangeable (since 
variables have unchangeable names too). They do so because the value (the 
function itself) is unchangeable.



-- 
Steven



More information about the Python-list mailing list