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

Discussion in 'Python' started by Alf P. Steinbach, Dec 18, 2009.

  1. I finally finished (draft), I believe!, chapter 2...

    Chapter 1 gets the reader up & running, i.e. it's "Hello, world!", basic tool
    usage, without discussing anything about programming really. One reaction to
    this chapter, based on the two example programs in it, was that it wasn't
    gradual and slow enough; hey, those examples are far too advanced, and
    unexplained! But that reader misunderstood: the progression is actually *slower*
    than one might expect. This chapter is only about tool usage. I.e., it's about
    getting those programs running, for the reader who can't rely on teachers or
    fellow students or, as Kernighan & Ritchie put it, "your local guru" (IIRC).

    Chapter 2 is about Basic Concepts (of programming). It's the usual: variables,
    basic types and arrays, loops, decision, routines, classes, events, although not
    presented in that order. I make heavy use of complete, concrete examples, many
    of them graphical, and everything is in support of what's actually needed for
    such concrete examples. The intent is to enable the reader to experiment and try
    things out -- since the only way to really learn is by doing! As best I could
    I've labored to apply this minimalism also to the Python language, using only a
    "minimal" subset (to the degree of not even introducing boolean ops :) ).

    Chapter 3 will, by my current plan, delve into the Python language and such
    things as how integers and floating point works on the inside, and that includes
    those in chapter 2 not even mentioned boolean operations. One important issue,
    introducing exceptions, and in support of that, type hierarchies. After chapter
    3 I have only much vaguer notions about what to introduce in what order, but a
    main issue, assuming that I go on with this writing, will be to apply and teach
    methodology all the way, integrated into the examples and text.

    A table of contents + chapters 1 and 2 is available in PDF format at Google Docs, at

    <url: http://tinyurl.com/programmingbookP3>

    Comments are very welcome!

    Re comments: there are two deviations from current Python practice in chapter 2.
    First, that I use spaces inside argument parentheses, which makes the code more
    readable when one gets used/trained to it because it gives the eye more direct
    information (with some training visual structure can be processed unconsciously
    & effortlessly, but purely logical structure has to be processed analytically).
    The second deviation is that since most names are constants, I do not follow PEP
    8's recommendation to use uppercase names of constants. 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 and in particular routine names are usually
    constants, absolutely not meant to be modified, but it would be silly to UC...

    So both these two deviations from Python practice are /intentional/, since this
    is a book about programming, not about Python the language & how to conform to
    idiosyncratic language-specific conventions.

    But, if there are other deviations from Python practice I'd be very glad to hear
    of it! I'm very hopeful that any such convention deviations can be fixed. :)


    Cheers,

    - Alf
     
    Alf P. Steinbach, Dec 18, 2009
    #1
    1. Advertising

  2. Alf P. Steinbach

    Mensanator Guest

    Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    > The second deviation is that since most names are constants,

    Really? Does that mean you don't use literals, to save the time
    required to convert them to integers? Isn't that done at compile
    time?

    So, instead of doing the Collatz Conjecture as

    while a>1:
    f = gmpy.scan1(a,0)
    if f>0:
    a = a >> f
    else:
    a = a*3 + 1

    You would do this?

    zed = 0
    one = 1
    two = 2
    twe = 3
    while a>one:
    f = gmpy.scan1(a,zed)
    if f>zed:
    a = a >> f
    else:
    a = a*twe + one

    Does this really save any time?

    Now, it's a different story if you're using the gmpy module.
    You DON'T want to use literals in loops involving gmpy, because
    they would have to be coerced to .mpz's on every pass through the
    loop.

    In that case, you DO want to use constants as opposed to literals:

    ZED = gmpy.mpz(0)
    ONE = gmpy.mpz(1)
    TWO = gmpy.mpz(2)
    TWE = gmpy.mpz(3)
    while a>ONE:
    f = gmpy.scan1(a,0) # int used here, so it can be a literal
    if f>ZED:
    a = a >> f
    else:
    a = a*TWE + ONE

    And yes, the time savings can be tremendous, especially when 'a'
    has over 50,000 decimal digits.

    .. I do not follow PEP
    > 8's recommendation to use uppercase names of constants. In fact almost no Python
    > code does,


    Mine does when I use gmpy. Otherwise, the notion that "most names
    are constants" is generally false.
     
    Mensanator, Dec 18, 2009
    #2
    1. Advertising

  3. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    * Mensanator:
    >> The second deviation is that since most names are constants,

    >
    > Really? Does that mean you don't use literals, to save the time
    > required to convert them to integers? Isn't that done at compile
    > time?
    >
    > So, instead of doing the Collatz Conjecture as
    >
    > while a>1:
    > f = gmpy.scan1(a,0)
    > if f>0:
    > a = a >> f
    > else:
    > a = a*3 + 1
    >
    > You would do this?
    >
    > zed = 0
    > one = 1
    > two = 2
    > twe = 3
    > while a>one:
    > f = gmpy.scan1(a,zed)
    > if f>zed:
    > a = a >> f
    > else:
    > a = a*twe + one


    That seems to have no relation to what you quoted / responded to.

    On the other hand, if there is some specific rôle played by the 3 above, where
    some other value (like e.g. 5) might be used instead, then a self descriptive
    name for that rôle might be good.

    Such reasonable naming (not what you did above) then allows easier modification
    of and makes it easier to understand the code.

    That said, and a bit off-tangent to your comment's main thrust, the time spent
    on coding that repeated-division-by-2 optimization would, I think, be better
    spent googling "Collatz Conjecture" -- avoiding writing /any/ code. ;-)


    > Does this really save any time?


    If by "it" you mean the silly naming, no it doesn't.

    On the contrary, it wastes time, both for writing the code and reading it.

    Generally, IMO, think about the clarity of your code. If naming something
    increases clarity, then name the thing. If it doesn't increase clarity, don't.


    > Now, it's a different story if you're using the gmpy module.
    > You DON'T want to use literals in loops involving gmpy, because
    > they would have to be coerced to .mpz's on every pass through the
    > loop.
    >
    > In that case, you DO want to use constants as opposed to literals:
    >
    > ZED = gmpy.mpz(0)
    > ONE = gmpy.mpz(1)
    > TWO = gmpy.mpz(2)
    > TWE = gmpy.mpz(3)
    > while a>ONE:
    > f = gmpy.scan1(a,0) # int used here, so it can be a literal
    > if f>ZED:
    > a = a >> f
    > else:
    > a = a*TWE + ONE
    >
    > And yes, the time savings can be tremendous, especially when 'a'
    > has over 50,000 decimal digits.


    Yeah, good point. Few languages have compile time evaluation of logically
    constant expressions. C++0x will have that feature (called 'constexpr' IIRC) but
    in Python, current C++ etc. it's just a good idea to precompute values, and name
    them, rather than computing them again and again where they're needed.


    > . I do not follow PEP
    >> 8's recommendation to use uppercase names of constants. In fact almost no Python
    >> code does,

    >
    > Mine does when I use gmpy. Otherwise, the notion that "most names
    > are constants" is generally false.


    No, it depends on what you mean by "constant". The problem with Python, as
    Google noted, is that the language is so excessively dynamic: even names of
    routines are variables, and there /are/ no named user defined constants except
    logically, in the programmer's mind. And logically (that is, at the "in the
    programmer's mind" level), if you define "constant" as a name whose value will
    not change after initialization, then routine names are constants.

    However, if you define "constant" as only a global scope (that is, module scope)
    name that denotes a boolean, numerical or string or Null value and that doesn't
    change after initialization, then your statement about the scarcity of constants
    appears to be true, but using a practically useless definition.

    I think for such constants exported by modules it's a good idea to at least
    provide uppercase names so as conform to very firmly established convention.
    There might even be tools that rely on that convention. But for application code
    the uppercase names are just distracting, and they don't help you...


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Dec 19, 2009
    #3
  4. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    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.

    (The exception is that some formal parameters in Python are given default
    values and flagged as "do not use", e.g. some methods in the random
    module. One might argue that they are constants in the sense that the
    caller is warned not to use them at all.)


    > and in particular
    > routine NAMES are usually constants, absolutely not meant to be
    > modified, but it would be silly to UC...

    [emphasis added by me]


    The only thing sillier than uppercasing routine names is to confuse the
    name of a thing for the thing it represents. The names of *all* entities,
    whether of constants, variables or routines, are "not meant to be
    modified". As a general rule, programs will no more work if you rename a
    variable 'x' to 'y' than if you rename a function 'f' to 'g' -- that's
    why refactoring requires that any renamings be done carefully. There's no
    need to single out routines for special treatment in that regard.

    As far as I know, no programming language provides a standard facility
    for renaming entities, be they data or routines: the closest we have is
    something like Python where you can do this:

    # make an entity x
    x = 23
    # use it
    x += 1
    # make a new name that refers to the same entity as x
    y = x
    # delete the old name
    del x
    # now use the new name
    y += 1

    So while it is true that routine names are not meant to be modified,
    neither are variable names (that is, the names of variables) or the names
    of anything else either. But this is not what is meant by "constant":
    being a constant means that the *value*, not the *name*, is never meant
    to change.

    It is true that, usually, the names of certain types of object (usually
    functions, classes, methods and modules) are typically expected to not be
    re-bound. Having done this:

    def parrot(colour='blue'):
    return "Norwegian %s" % colour.titlecase()


    I would *rarely* rebind the name parrot to another object. Rarely, but
    not quite never: I might monkey-patch the function, or decorate it in
    some way, or change the implementation, so such routines aren't quite
    constant in the sense you mean. While it's unusual to vary a function, it
    isn't forbidden.

    Even in languages where routines are "first class objects" like ints and
    strings, we treat such objects as special. Even if the function named
    parrot above was expected to never change, I wouldn't describe it as a
    constant. "Constant" and "variable" refer to *data*, not routines or
    other special objects like modules.

    It's illustrative to consider what we might do when writing a program
    that does treat functions as data, say, a program that integrated other
    functions. One might very well do something like this:

    function_to_be_integrated = math.sin # a variable
    SIMPSONS = integrators.simpsons_method # a constant
    UPPER_RECT = monkey_patch(integrators.upper)
    LOWER_RECT = monkey_patch(integrators.lower)

    integrate(function_to_be_integrated,
    limits=(-math.pi/2, math.pi),
    method=SIMPSONS
    )

    This would clearly indicate that `function_to_be_integrated` holds
    variable data (which happens to be a function) while `SIMPSONS` etc are
    expected to hold constant data (which also happen to be functions).


    --
    Steven
     
    Steven D'Aprano, Dec 19, 2009
    #4
  5. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    On Sat, 19 Dec 2009 01:25:48 +0100, Alf P. Steinbach wrote:

    > That said, and a bit off-tangent to your comment's main thrust, the time
    > spent on coding that repeated-division-by-2 optimization would, I think,
    > be better spent googling "Collatz Conjecture" -- avoiding writing
    > /any/ code. ;-)


    That's a strange thing to say.


    >> Now, it's a different story if you're using the gmpy module. You DON'T
    >> want to use literals in loops involving gmpy, because they would have
    >> to be coerced to .mpz's on every pass through the loop.

    [...]
    > Yeah, good point. Few languages have compile time evaluation of
    > logically constant expressions.


    Surely that's an implementation issue rather than a language issue.


    > C++0x will have that feature (called
    > 'constexpr' IIRC) but in Python, current C++ etc. it's just a good idea
    > to precompute values, and name them, rather than computing them again
    > and again where they're needed.


    CPython 2.5 and on has a keyhole optimizer that replaces many constant
    expressions with pre-computed values.

    # Python 2.4
    >>> dis.dis(compile('1+1', '', 'eval'))

    0 0 LOAD_CONST 0 (1)
    3 LOAD_CONST 0 (1)
    6 BINARY_ADD
    7 RETURN_VALUE

    # Python 2.5
    >>> dis.dis(compile('1+1', '', 'eval'))

    1 0 LOAD_CONST 1 (2)
    3 RETURN_VALUE


    Unfortunately it doesn't help Mensanator's case, because there's no way
    to tell the compiler to generate mpz objects instead of int objects, and
    expressions such as gmpy.mpz(0) are not recognised as compile-time
    constants.


    >> Mine does when I use gmpy. Otherwise, the notion that "most names are
    >> constants" is generally false.

    >
    > No, it depends on what you mean by "constant".


    All names are constant. Always. The Python language does not support
    renaming names -- as far as I know, no language does.


    > The problem with Python,
    > as Google noted, is that the language is so excessively dynamic: even
    > names of routines are variables,


    Don't say that, that is confusing the name with the value. The terms
    "constant" and "variable" refer to the values bound to a name, not the
    name itself: what you mean is that even routines are variables.

    Consider the following Pascal declaration:

    const
    a = 1;
    var
    b: integer;

    Neither name 'a' nor 'b' ever change; a is always a and b is always b.
    You wouldn't describe b as a constant because the name never changes,
    would you? What matters is that the value assigned to the name can, or
    can't, be changed by the caller.

    Like any other language, Python *names* are always constant: you can
    create them at will (without needing a declaration); you can delete them
    (with the del statement, something Pascal doesn't allow you to do); but
    there's no way to change a name once it exists. Obviously it would be
    misleading to claim that Python name/object bindings ("variables") are
    therefore constant because of this.

    So how would I say what you are trying to say, but in a less-misleading
    fashion?

    Names can always (well, almost -- there are a few exceptions) be rebound,
    regardless of whether they are currently bound to a data object (string,
    int, float...) or a routine (function, method...). Since the name by
    which we refer to a function can be rebound, we refer to the name/object
    binding as variable rather than constant -- exactly the same as any other
    name/object binding.

    Or the shorter way:

    Since all names can be rebound, regardless of what value they have (int,
    string, function, whatever) all names are variables and Python has no
    constants other than special pre-defined names like None.



    > and there /are/ no named user defined
    > constants except logically, in the programmer's mind.


    Yes, that is correct, although there are tricks you can do to make
    slightly-more-constant-like constants, such as Alex Martelli's "constant
    module" recipe in the Cookbook, but there are no true constants in Python.


    > And logically
    > (that is, at the "in the programmer's mind" level), if you define
    > "constant" as a name whose value will not change after initialization,
    > then routine names are constants.


    Some languages enforce that, and in those languages, it makes sense to
    describe functions as constants. Python is not one of those languages.


    > However, if you define "constant" as only a global scope (that is,
    > module scope) name that denotes a boolean, numerical or string or Null
    > value and that doesn't change after initialization, then your statement
    > about the scarcity of constants appears to be true, but using a
    > practically useless definition.


    I won't speak for Mensanator, but I wouldn't be so restrictive about the
    *types* of data that constants can hold. Not in Python, at least, other
    languages can and do limit the types of constants to a handful of
    predefined types known to the compiler.

    Nor would I say that "constants" (note the scare-quotes) can only occur
    in module scope. There's nothing wrong with naming "constants" in other
    scopes, although I must admit I'm a tad less consistent about doing so
    than I should.



    --
    Steven
     
    Steven D'Aprano, Dec 19, 2009
    #5
  6. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    * 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, which is like saying horses are not mammals, just "because".

    There are two sensible definitions of "constant": compile time constant, and
    constant-after-initialization.

    And since Python doesn't have or support user defined compile time (named)
    constants even in the way that a programmer views the execution of a program,
    only the const after initialization meaning can /reasonably/ apply.

    I hope you see that with the constant-after-initialization meaning it's rather
    irrelevant that an argument's value "will vary according to [the actual
    argument]" -- for an argument A, id(A) does in general not vary after
    initialization, after creation of A; and it can certainly not vary before!

    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.)
    }

    As the comment there exemplifies, in addition to the 2 main meanings of
    constness one can differentiate between constness at different levels of an
    expression, e.g., in Python, with respect to what the language enforces,

    s = "blah"

    is a non-constant name referring to a constant (immutable value), while

    a = ["blah"]

    is a non-constant name referring to a non-constant value (a Python 'list')
    containing a constant value -- but with respect to intended constness there
    might be more constness here, although there can't be less.

    Since Python doesn't support constness enforcement, your statement that routine
    arguments are almost never constants must refer to their actual usage, i.e.
    intention. It may be the case that in most code you're familiar with routine
    arguments are generally modified. And/or it may be that in code you're familiar
    with routines regularly modify the objecs that their arguments refer to, i.e.
    that the arguments are constant names referring to mutable objects.

    In code that I'm familiar with, but that's admittedly mostly in other languages,
    most argument names are constant at the top level of constness, i.e., translated
    to Python, id(A) does generally not change when A is a formal argument.


    > (The exception is that some formal parameters in Python are given default
    > values and flagged as "do not use", e.g. some methods in the random
    > module. One might argue that they are constants in the sense that the
    > caller is warned not to use them at all.)


    Huh.


    >> and in particular
    >> routine NAMES are usually constants, absolutely not meant to be
    >> modified, but it would be silly to UC...

    > [emphasis added by me]
    >
    >
    > The only thing sillier than uppercasing routine names is to confuse the
    > name of a thing for the thing it represents. The names of *all* entities,
    > whether of constants, variables or routines, are "not meant to be
    > modified". As a general rule, programs will no more work if you rename a
    > variable 'x' to 'y' than if you rename a function 'f' to 'g' -- that's
    > why refactoring requires that any renamings be done carefully. There's no
    > need to single out routines for special treatment in that regard.


    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?


    > 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.


    > the closest we have is
    > something like Python where you can do this:
    >
    > # make an entity x
    > x = 23
    > # use it
    > x += 1
    > # make a new name that refers to the same entity as x
    > y = x
    > # delete the old name
    > del x
    > # now use the new name
    > y += 1


    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...


    [snipped the rest, irrelevant]

    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Dec 19, 2009
    #6
  7. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    * Steven D'Aprano:
    > On Sat, 19 Dec 2009 01:25:48 +0100, Alf P. Steinbach wrote:
    >
    >> That said, and a bit off-tangent to your comment's main thrust, the time
    >> spent on coding that repeated-division-by-2 optimization would, I think,
    >> be better spent googling "Collatz Conjecture" -- avoiding writing
    >> /any/ code. ;-)

    >
    > That's a strange thing to say.


    No. The code shown was like attacking Fermat's last theorem with a little Python
    script checking out number triplets. It's already been done (not to mention that
    that theorem's been proven, although that's, AFAIK, not the case for Collatz').


    >>> Now, it's a different story if you're using the gmpy module. You DON'T
    >>> want to use literals in loops involving gmpy, because they would have
    >>> to be coerced to .mpz's on every pass through the loop.

    > [...]
    >> Yeah, good point. Few languages have compile time evaluation of
    >> logically constant expressions.

    >
    > Surely that's an implementation issue rather than a language issue.


    No, it isn't.

    An optimizer can only do so much, as you yourself note below!

    With language support it's a very different matter because guarantees propagate
    so that sophisticated analysis is no longer necessary: the compiler /knows/,
    because it's explicitly being told.


    >> C++0x will have that feature (called
    >> 'constexpr' IIRC) but in Python, current C++ etc. it's just a good idea
    >> to precompute values, and name them, rather than computing them again
    >> and again where they're needed.

    >
    > CPython 2.5 and on has a keyhole optimizer that replaces many constant
    > expressions with pre-computed values.
    >
    > # Python 2.4
    >>>> dis.dis(compile('1+1', '', 'eval'))

    > 0 0 LOAD_CONST 0 (1)
    > 3 LOAD_CONST 0 (1)
    > 6 BINARY_ADD
    > 7 RETURN_VALUE
    >
    > # Python 2.5
    >>>> dis.dis(compile('1+1', '', 'eval'))

    > 1 0 LOAD_CONST 1 (2)
    > 3 RETURN_VALUE
    >
    >
    > Unfortunately it doesn't help Mensanator's case, because there's no way
    > to tell the compiler to generate mpz objects instead of int objects, and
    > expressions such as gmpy.mpz(0) are not recognised as compile-time
    > constants.


    See?

    ;-)


    >>> Mine does when I use gmpy. Otherwise, the notion that "most names are
    >>> constants" is generally false.

    >> No, it depends on what you mean by "constant".

    >
    > All names are constant. Always. The Python language does not support
    > renaming names -- as far as I know, no language does.


    No-ones been talking about renaming names. I think that's purely rhetorical on
    your part but it may be that you really believe so. In the latter case, just try
    to interpret statements so that they're meaningful instead of meaningless. :)


    >> The problem with Python,
    >> as Google noted, is that the language is so excessively dynamic: even
    >> names of routines are variables,

    >
    > Don't say that, that is confusing the name with the value.


    Nope.


    > The terms
    > "constant" and "variable" refer to the values bound to a name, not the
    > name itself:


    I'm sorry, that's incorrect.

    Quote from §4.1 "Naming and binding" of the Python 3.1.1 language spec:

    "If a name is bound in a block, it is a local variable of that block, unless
    declared as nonlocal. If a name is bound at the module level, it is a global
    variable. (The variables of the module code block are local and global.) If a
    variable is used in a code block but not defined there, it is a free variable."


    > what you mean is that even routines are variables.


    I'm sorry but I can't make sense of what you write here. In addition I'm not
    sure what you mean because there are two main interpretations.

    If you mean that user defined Python routines are mutable, yes that's right, but
    not what I was talking about (which you can easily see by checking whether it
    makes sense in context; it doesn't).

    If you mean that a routine of itself is a variable, no it isn't, but the name of
    a routine, like "foo" in

    def foo: print( "uh" )

    or "bar" in

    bar = lambda: print( "oh" )

    is a variable, per the language specification's definition quoted above (and
    also by any reasonable meaning of "variable"!).

    The meaning of "variable" for Python terminology is specified by the language
    specification, as quoted above: a variable is a name.


    [snipped rest, irrelevant]


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Dec 19, 2009
    #7
  8. Alf P. Steinbach

    John Bokma Guest

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

    Steven D'Aprano <> writes:

    > CPython 2.5 and on has a keyhole optimizer that replaces many constant

    ^^^^^^^
    Shouldn't that be peephole?

    > expressions with pre-computed values.


    And that's called constant folding.

    Unless I misread your post (or have been out of touch with compiler
    building too long)

    --
    John Bokma

    Read my blog: http://johnbokma.com/
    Hire me (Perl/Python): http://castleamber.com/
     
    John Bokma, Dec 19, 2009
    #8
  9. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    On Fri, 18 Dec 2009 15:26:05 -0800, Mensanator wrote:

    >> The second deviation is that since most names are constants,

    >
    > Really? Does that mean you don't use literals, to save the time required
    > to convert them to integers? Isn't that done at compile time?
    >
    > So, instead of doing the Collatz Conjecture as
    >
    > while a>1:
    > f = gmpy.scan1(a,0)
    > if f>0:
    > a = a >> f
    > else:
    > a = a*3 + 1
    >
    > You would do this?
    >
    > zed = 0
    > one = 1
    > two = 2
    > twe = 3
    > while a>one:
    > f = gmpy.scan1(a,zed)
    > if f>zed:
    > a = a >> f
    > else:
    > a = a*twe + one
    >
    > Does this really save any time?


    There are some people who might argue that using *any* magic constants in
    code is wrong, and that *all* such values should be declared as a
    constant.

    It's easy to take the mickey out of such an extreme position:

    zed = 0 # in case we need to redefine 0 as something else
    one = 1 # likewise
    two = 3 # changed from 2 to 3 to reflect the end of the Mayan calendar

    # The following is guaranteed to pass unless the world is ending.
    assert one+one == two-zed



    --
    Steven
     
    Steven D'Aprano, Dec 19, 2009
    #9
  10. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    Mensanator wrote:
    > Really? Does that mean you don't use literals, to save the time
    > required to convert them to integers?


    I think all he means is that when he *does* use a named
    constant, he spells it in lower case rather than upper
    case, e.g. 'twopi' rather than 'TWOPI'.

    I don't think there's anything much wrong with that. It
    can be useful sometimes to visually distinguish constants
    from variables, but it's not a necessity. Also the all-
    uppercase convention isn't the only way to do that -- it's
    a C-ism that isn't universally followed in Python. An
    alternative often used is just to uppercase the first
    character. Python itself uses that for many of its
    built-in constants, such as None, True, False.

    Arguing that functions are usually constants and should
    therefore have uppercase names is missing the point --
    everyone expects them to be constant anyway, so there's
    no need for a typographical convention to indicate that.
    In the rare cases where they're not constant, they can
    usually be named in a way that makes this obvious.

    (And BTW, looking up a global name is *slower* than using
    a literal. Although a local name is probably about the
    same speed as a literal, as they're both array accesses.)

    --
    Greg
     
    Gregory Ewing, Dec 19, 2009
    #10
  11. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    On Fri, 18 Dec 2009 21:29:27 -0600, John Bokma wrote:

    > Steven D'Aprano <> writes:
    >
    >> CPython 2.5 and on has a keyhole optimizer that replaces many constant

    > ^^^^^^^
    > Shouldn't that be peephole?


    Alternate names for the same thing.


    >> expressions with pre-computed values.

    >
    > And that's called constant folding.


    Yes.

    > Unless I misread your post (or have been out of touch with compiler
    > building too long)


    No :)



    --
    Steven
     
    Steven D'Aprano, Dec 19, 2009
    #11
  12. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    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
     
    Steven D'Aprano, Dec 19, 2009
    #12
  13. Alf P. Steinbach

    Mensanator Guest

    Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    On Dec 18, 6:25 pm, "Alf P. Steinbach" <> wrote:
    > * Mensanator:
    >
    > >> The second deviation is that since most names are constants,

    >
    > > Really? Does that mean you don't use literals, to save the time
    > > required to convert them to integers? Isn't that done at compile
    > > time?

    >
    > > So, instead of doing the Collatz Conjecture as

    >
    > > while a>1:
    > >   f = gmpy.scan1(a,0)
    > >   if f>0:
    > >     a = a >> f
    > >   else:
    > >     a = a*3 + 1

    >
    > > You would do this?

    >
    > > zed = 0
    > > one = 1
    > > two = 2
    > > twe = 3
    > > while a>one:
    > >   f = gmpy.scan1(a,zed)
    > >   if f>zed:
    > >     a = a >> f
    > >   else:
    > >     a = a*twe + one

    >
    > That seems to have no relation to what you quoted / responded to.


    Whose fault is that? Here's a hint: when people's replies don't
    make any sense, it's because they don't understand your prattle.
    That's not good for someone who fancies himself a teacher of
    programming.


    >
    > On the other hand, if there is some specific rôle played by the 3 above, where
    > some other value (like e.g. 5) might be used instead, then a self descriptive
    > name for that rôle might be good.
    >
    > Such reasonable naming (not what you did above) then allows easier modification
    > of and makes it easier to understand the code.
    >
    > That said, and a bit off-tangent to your comment's main thrust, the time spent
    > on coding that repeated-division-by-2 optimization would, I think, be better
    > spent googling "Collatz Conjecture"  --  avoiding writing /any/ code. ;-)


    Ha! I know more about Collatz than you can ever find by Googling!
    And how did I achieve that? By writing such code. Be a good boy and
    maybe I'll show you how to do Ulam's Spiral with Turtle Graphics.

    >
    > > Does this really save any time?

    >
    > If by "it" you mean the silly naming, no it doesn't.
    >
    > On the contrary, it wastes time, both for writing the code and reading it..
    >
    > Generally, IMO, think about the clarity of your code. If naming something
    > increases clarity, then name the thing. If it doesn't increase clarity, don't.
    >
    >
    >
    >
    >
    > > Now, it's a different story if you're using the gmpy module.
    > > You DON'T want to use literals in loops involving gmpy, because
    > > they would have to be coerced to .mpz's on every pass through the
    > > loop.

    >
    > > In that case, you DO want to use constants as opposed to literals:

    >
    > > ZED = gmpy.mpz(0)
    > > ONE = gmpy.mpz(1)
    > > TWO = gmpy.mpz(2)
    > > TWE = gmpy.mpz(3)
    > > while a>ONE:
    > >   f = gmpy.scan1(a,0) # int used here, so it can be a literal
    > >   if f>ZED:
    > >     a = a >> f
    > >   else:
    > >     a = a*TWE + ONE

    >
    > > And yes, the time savings can be tremendous, especially when 'a'
    > > has over 50,000 decimal digits.

    >
    > Yeah, good point. Few languages have compile time evaluation of logically
    > constant expressions. C++0x will have that feature (called 'constexpr' IIRC) but
    > in Python, current C++ etc. it's just a good idea to precompute values, and name
    > them, rather than computing them again and again where they're needed.
    >
    > > . I do not follow PEP
    > >> 8's recommendation to use uppercase names of constants. In fact almost no Python
    > >> code does,

    >
    > > Mine does when I use gmpy. Otherwise, the notion that "most names
    > > are constants" is generally false.

    >
    > No, it depends on what you mean by "constant".


    Why don't you try using what PEP 8 means by "constant".

    > The problem with Python, as
    > Google noted, is that the language is so excessively dynamic: even names of
    > routines are variables, and there /are/ no named user defined constants except
    > logically, in the programmer's mind. And logically (that is, at the "in the
    > programmer's mind" level), if you define "constant" as a name whose value will
    > not change after initialization, then routine names are constants.


    You're sitting too close to the fire. Why don't you back off and
    quit overanalizing things.

    >
    > However, if you define "constant" as only a global scope (that is, module scope)
    > name that denotes a boolean, numerical or string or Null value and that doesn't
    > change after initialization, then your statement about the scarcity of constants
    > appears to be true, but using a practically useless definition.
    >
    > I think for such constants exported by modules it's a good idea to at least
    > provide uppercase names so as conform to very firmly established convention.
    > There might even be tools that rely on that convention. But for application code
    > the uppercase names are just distracting, and they don't help you...


    They help when I look at something like

    a = (i-ONE)*NIN**(k-ONE) + (NIN**(k-ONE) - ONE)//TWO + ONE

    >
    > Cheers & hth.,
    >
    > - Alf
     
    Mensanator, Dec 19, 2009
    #13
  14. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    * Mensanator:
    >>
    >> That said, and a bit off-tangent to your comment's main thrust, the time spent
    >> on coding that repeated-division-by-2 optimization would, I think, be better
    >> spent googling "Collatz Conjecture" -- avoiding writing /any/ code. ;-)

    >
    > Ha! I know more about Collatz than you can ever find by Googling!
    > And how did I achieve that? By writing such code. Be a good boy and
    > maybe I'll show you how to do Ulam's Spiral with Turtle Graphics.


    It's probably good for you that you know so much about Collatz.

    I fail to see the relevance to anything.


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Dec 19, 2009
    #14
  15. Alf P. Steinbach

    Mensanator Guest

    Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    On Dec 19, 12:21 am, "Alf P. Steinbach" <> wrote:
    > * Mensanator:
    >
    >
    >
    > >> That said, and a bit off-tangent to your comment's main thrust, the time spent
    > >> on coding that repeated-division-by-2 optimization would, I think, be better
    > >> spent googling "Collatz Conjecture"  --  avoiding writing /any/ code. ;-)

    >
    > > Ha! I know more about Collatz than you can ever find by Googling!
    > > And how did I achieve that? By writing such code. Be a good boy and
    > > maybe I'll show you how to do Ulam's Spiral with Turtle Graphics.

    >
    > It's probably good for you that you know so much about Collatz.
    >
    > I fail to see the relevance to anything.


    No kidding. Here let me explain it:

    You said my time would be better spent googling "Collatz Conjecture".

    I said I know more than can be found by googling. Therefore,
    it follows that my time could NOT be better spent googling.

    Thus, your staement is shown to be false.

    QED

    >
    > Cheers & hth.,
    >
    > - Alf
     
    Mensanator, Dec 19, 2009
    #15
  16. Alf P. Steinbach

    Lie Ryan Guest

    Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestForComments

    On 12/19/2009 12:56 PM, Steven D'Aprano wrote:
    > As far as I know, no programming language provides a standard facility
    > for renaming entities, be they data or routines:


    The C-preprocessor does to C/C++, in a limited fashion.
     
    Lie Ryan, Dec 19, 2009
    #16
  17. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

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

    > * Steven D'Aprano:
    >> On Sat, 19 Dec 2009 01:25:48 +0100, Alf P. Steinbach wrote:
    >>
    >>> That said, and a bit off-tangent to your comment's main thrust, the
    >>> time spent on coding that repeated-division-by-2 optimization would, I
    >>> think, be better spent googling "Collatz Conjecture" -- avoiding
    >>> writing /any/ code. ;-)

    >>
    >> That's a strange thing to say.

    >
    > No. The code shown was like attacking Fermat's last theorem with a
    > little Python script checking out number triplets. It's already been
    > done (not to mention that that theorem's been proven, although that's,
    > AFAIK, not the case for Collatz').


    You're assuming that Mensanator's motive for writing code is to challenge
    the Collatz Conjecture, rather than to just have fun doing maths and
    programming, or to build up his skills for a serious effort at extending
    the domain of values for which it is known to be true. Or just because he
    needs a function that calculates the hailstone numbers.



    >>>> Now, it's a different story if you're using the gmpy module. You
    >>>> DON'T want to use literals in loops involving gmpy, because they
    >>>> would have to be coerced to .mpz's on every pass through the loop.

    >> [...]
    >>> Yeah, good point. Few languages have compile time evaluation of
    >>> logically constant expressions.

    >>
    >> Surely that's an implementation issue rather than a language issue.

    >
    > No, it isn't.
    >
    > An optimizer can only do so much, as you yourself note below!


    You make no sense here. What I note below is the existence of an
    implementation-specific optimizer. And your conclusion? That such
    optimization is language specific! How does that make sense?

    Obviously it wouldn't be sensible for CPython to optimize numeric
    literals as mpz objects, because that would be a lot of overhead for very
    little gain. But it might make sense for somebody to create a "Numeric
    Python" implementation which used mpz as the standard integer type.

    A slightly more tricky case is optimizing away more complex runtime
    expressions. len("abc") is not necessarily the constant 3, because the
    function len may have been replaced by something else, thus requiring it
    to be calculated at runtime rather than compile-time. But an
    implementation might relax that condition and treat built-ins as
    constants. Guido probably will never allow such a thing in CPython, but
    other implementations are free to do things differently. Even if people
    argue that such a behavioural change is "no longer Python", there's
    nothing preventing an optimizing implementation from replacing
    "abc".__len__() with the constant 3 except the complexity of
    implementation and the diminishing returns of doing so.


    > With language support it's a very different matter because guarantees
    > propagate so that sophisticated analysis is no longer necessary: the
    > compiler /knows/, because it's explicitly being told.


    Of course if a language makes a certain guarantee (for example, that
    calls to math.exp(0) will be replaced at compile-time with 1.0) then the
    compiler can make that substitution. But such optimizations tend not to
    be specified by the language (in fact languages like C often tend to
    leave large amounts of behaviour as implementation-defined), and even
    when languages do make certain guarantees, implementations are free to
    implement any behaviour not implicitly or explicitly forbidden.



    >>>> Mine does when I use gmpy. Otherwise, the notion that "most names are
    >>>> constants" is generally false.
    >>> No, it depends on what you mean by "constant".

    >>
    >> All names are constant. Always. The Python language does not support
    >> renaming names -- as far as I know, no language does.

    >
    > No-ones been talking about renaming names. I think that's purely
    > rhetorical on your part but it may be that you really believe so. In the
    > latter case, just try to interpret statements so that they're meaningful
    > instead of meaningless. :)


    (1) It's not meaningless to talk about renaming names.

    (2) I will not try to guess what you mean on the basis of what I consider
    sensible, rather than respond to what you actually say.

    (3) I've already gone over the name/value thing to death in another post,
    so I'll do everyone a favour and not continue it here.



    [...]
    >> The terms
    >> "constant" and "variable" refer to the values bound to a name, not the
    >> name itself:

    >
    > I'm sorry, that's incorrect.
    >
    > Quote from §4.1 "Naming and binding" of the Python 3.1.1 language spec:
    >
    > "If a name is bound in a block, it is a local variable of that block,
    > unless declared as nonlocal. If a name is bound at the module level, it
    > is a global variable. (The variables of the module code block are local
    > and global.) If a variable is used in a code block but not defined
    > there, it is a free variable."


    Since the above quote doesn't mention "constant", how on earth can you
    use it as evidence for what "constant" refers to?

    In any case, the words "constant" and "variable" have multiple meanings.
    They can be either nouns or adjectives. Constants (nouns) are called
    constants because of the value is constant (adjective) -- and similar for
    variables.



    --
    Steven
     
    Steven D'Aprano, Dec 19, 2009
    #17
  18. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    * Steven D'Aprano:
    > 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.


    On the contrary. Apes are not superclass of 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.


    I would want the possibility of having that enforced, of course, because the
    more you know about what can't take place in the code, i.e. the more easy-to-see
    constraints there are, the easier it is to understand and reason about the code,
    not to mention modifying it without breaking original assumptions.

    But I wasn't talking about such a language feature (which I believe could also
    greatly improve Python's efficiency by removing the need for many lookups).

    Rather, I was remarking that in the absence of such a language feature, to be
    consistent those who insist on using naming conventions to indicate design level
    constraints should use those naming conventions also for this case and others.
    For there's little point in making some occurrences of a constraint visually
    explicit and others not. That just means that one cannot rely on the convention
    to tell where the constraint is (meant to be) in effect or not.


    > 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".


    Yeah, hence the weasel term "in general".


    > 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.


    But usually this wrapping occurs before the function is first used by other
    code, i.e. it's usually part of initialization -- isn't it?

    For debugging purposes you might want to replace a function on-the-fly, in the
    middle of the program execution.

    But debugging does all sorts of things not commonly accepted for normal execution.


    > 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.


    Not sure what that second point was (lost in response stack and snippage
    somewhere), but as I remarked else-thread, in response to you, I'm sorry, but
    your view about names is incorrect.

    Quote from §4.1 "Naming and binding" of the Python 3.1.1 language spec:

    "If a name is bound in a block, it is a local variable of that block, unless
    declared as nonlocal. If a name is bound at the module level, it is a global
    variable. (The variables of the module code block are local and global.) If a
    variable is used in a code block but not defined there, it is a free variable."

    It's not just terminology that a Python name "is" a variable, and vice versa.

    Constness of the referred to value is an appropriate concept when that value is
    conceptually mutable, like

    v = [1, 2, 3]

    This particular case is supported for the referent,

    v = (1, 2, 3) # Voila, constant referent

    which expresses and enforces the constness of the referent.

    But to express the constness of the variable, which is what matters most of all
    (for without that top level constness all other constness, such as of direct
    referent, can be easily and inadvertently circumvented) all you can do is to
    e.g. name it V instead of v, or put its creation in a region of text clearly
    signalling "these are constants", or some such -- conventions.

    Since a variable is a name, and in Python a name is a variable, "constness of a
    variable" means "constness of a name". In Python. And as discussed above it's
    about any name binding whatsoever, while the PEP 8 naming convention is limited
    to communicating the intended constraint in just a few special cases, and hence
    is unreliable by design (in addition to introducing lots of visual gruff).


    >>> 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.


    Well, you can always do

    int& b = a;
    #define a __NO_SUCH_NAME__

    He he. :)

    Without the preprocessor you can do things like (or more elaborate)

    int a = 666;
    {
    int& b = a; struct a;
    // Only name b useful at this point. Most uses of a will be flagged.
    }

    And with the preprocessor that kind of renaming can be automated.

    But seriously I thought you were referring to aliasing, because changing a name
    mid-code generally makes no sense -- other than perhaps in an obfuscation
    contest (where of course techniques like the #define shown above /are/ employed,
    although typically with single letter names; it's a yearly contest for C...).


    [snip]
    >
    >> 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.


    In Python names are variables, per the language spec and in practice.

    The language spec's saying:

    "If a name is bound in a block, it is a local variable of that block, unless
    declared as nonlocal. If a name is bound at the module level, it is a global
    variable. (The variables of the module code block are local and global.) If a
    variable is used in a code block but not defined there, it is a free variable."

    Plus that of course, given this, the spec generally uses "variable" and "name"
    as interchangeable synonyms, with just a little context-dependent favoring of
    one or the other -- if you want example quotes I can provide a host of them.

    And most variables, at least in code I'm familiar with, are constants, in the
    sense that they're not intended to be re-bound after initialization.

    And that's what I wrote, "most names are constants", and it was actually meant
    to be precise: I was not talking about referred to objects, only about name
    re-binding, that is, about changing what you get by id(N) for a name N.



    Cheers & hth. (all cleared up now?),

    - Alf
     
    Alf P. Steinbach, Dec 19, 2009
    #18
  19. Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    * Steven D'Aprano:
    > On Sat, 19 Dec 2009 04:29:22 +0100, Alf P. Steinbach wrote:
    >
    >> * Steven D'Aprano:
    >>> On Sat, 19 Dec 2009 01:25:48 +0100, Alf P. Steinbach wrote:
    >>>
    >>>> That said, and a bit off-tangent to your comment's main thrust, the
    >>>> time spent on coding that repeated-division-by-2 optimization would, I
    >>>> think, be better spent googling "Collatz Conjecture" -- avoiding
    >>>> writing /any/ code. ;-)
    >>> That's a strange thing to say.

    >> No. The code shown was like attacking Fermat's last theorem with a
    >> little Python script checking out number triplets. It's already been
    >> done (not to mention that that theorem's been proven, although that's,
    >> AFAIK, not the case for Collatz').

    >
    > You're assuming that Mensanator's motive for writing code is to challenge
    > the Collatz Conjecture, rather than to just have fun doing maths and
    > programming, or to build up his skills for a serious effort at extending
    > the domain of values for which it is known to be true. Or just because he
    > needs a function that calculates the hailstone numbers.


    I would rather not speculate about motives.

    I can say things about the code that was presented, and I did, but as for the
    motives that went into creating it or presenting it in this thread, well I'm not
    telepathic.


    >>>>> Now, it's a different story if you're using the gmpy module. You
    >>>>> DON'T want to use literals in loops involving gmpy, because they
    >>>>> would have to be coerced to .mpz's on every pass through the loop.
    >>> [...]
    >>>> Yeah, good point. Few languages have compile time evaluation of
    >>>> logically constant expressions.
    >>> Surely that's an implementation issue rather than a language issue.

    >> No, it isn't.
    >>
    >> An optimizer can only do so much, as you yourself note below!

    >
    > You make no sense here. What I note below is the existence of an
    > implementation-specific optimizer. And your conclusion? That such
    > optimization is language specific! How does that make sense?


    No, I meant exactly what I wrote, that an optimizer only can do so much, which
    you also noted yourself; that language support facilitates this optimization;
    and that few languages have that support (but e.g. C++0x will have it).


    [snip]

    >> With language support it's a very different matter because guarantees
    >> propagate so that sophisticated analysis is no longer necessary: the
    >> compiler /knows/, because it's explicitly being told.

    >
    > Of course if a language makes a certain guarantee (for example, that
    > calls to math.exp(0) will be replaced at compile-time with 1.0) then the
    > compiler can make that substitution.


    Yes, that's what C++0x 'constexpr' is about.

    But I've lost the context here, not sure what this is all about.


    [snip]

    > (1) It's not meaningless to talk about renaming names.


    Well, as good as meaningless, IMHO. In fact, earlier, when you wrote under the
    assumption that I was talking about such renaming, you seemed to maintain that
    it was pretty meaningless. I conclude from that that also this is relative.


    > (2) I will not try to guess what you mean on the basis of what I consider
    > sensible, rather than respond to what you actually say.


    I rather hoped you would try to employ the "sensible" heuristic.

    The problem so far has, apparently, been that you refuse to accept the language
    specification's definition, in §4.1, of variable as name and vice versa.

    An "is-it-sensible" heuristic could have cleared that up, I think.


    > (3) I've already gone over the name/value thing to death in another post,
    > so I'll do everyone a favour and not continue it here.


    But when that is the problem, a basic misunderstanding of what a word means,
    then it's worth uh, harping on the issue, I think:


    > [...]
    >>> The terms
    >>> "constant" and "variable" refer to the values bound to a name, not the
    >>> name itself:

    >> I'm sorry, that's incorrect.
    >>
    >> Quote from §4.1 "Naming and binding" of the Python 3.1.1 language spec:
    >>
    >> "If a name is bound in a block, it is a local variable of that block,
    >> unless declared as nonlocal. If a name is bound at the module level, it
    >> is a global variable. (The variables of the module code block are local
    >> and global.) If a variable is used in a code block but not defined
    >> there, it is a free variable."

    >
    > Since the above quote doesn't mention "constant", how on earth can you
    > use it as evidence for what "constant" refers to?


    I don't. I use it as evidence for what "name" refers to. A constant "name" is
    then, logically, a constant such thing, to wit, a constant variable. You may
    find that terminology paradoxical. For C++, which has the means of enforcing it,
    it's a FAQ (many novices have some trouble accepting constant /variables/...).
    If it helps let's adopt Java's terminology and talk about "final" variables. Or,
    as Bjarne had it in original C++, "readonly" variables.


    > In any case, the words "constant" and "variable" have multiple meanings.
    > They can be either nouns or adjectives. Constants (nouns) are called
    > constants because of the value is constant (adjective) -- and similar for
    > variables.


    Yeah, but you're not seriously suggesting that any global variable initialized
    to a constant (immutable value) should be uppercased. So "constant" in this
    regard does not refer to the refererred to value. It refers to the id(v).


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Dec 19, 2009
    #19
  20. Alf P. Steinbach

    John Posner Guest

    Re: Programming intro book ch1 and ch2 (Windows/Python 3) - RequestFor Comments

    On Fri, 18 Dec 2009 13:00:48 -0500, Alf P. Steinbach <>
    wrote:

    >
    > Chapter 2 is about Basic Concepts (of programming). It's the usual:
    > variables, ...


    1. Overall suggestion

    You have a tendency to include non-pertinent asides [1]. But then,
    rambling a bit endows a manuscript with the author's distinctive voice.
    Fortunately, we live in a hypertext-enabled world, where you can have your
    cake and eat it, too. I suggest that you go over your manuscript with a
    ruthless eye, and turn your rambles into hypertext-accessible "sidebars"..
    See how much you can reduce the length of Chapter 2, which current runs 98
    pages!

    2. Comments on Section 2.6.7, "References & automatic garbage collection"

    There's a spell-check evader on page 2:49: "trough" s.b. "through". And
    your spell-checker should have caught "adressable" on page 2:48.

    I find your sequence-of-attribute-lookups approach to the topic of
    "variable assignment" interesting. The directed-graph illustration on page
    2:49 even hints at the fact that in the world of Python, names ("turtle",
    "forward", etc.) and objects (various kinds of yellow boxes) are very
    different things.

    (I suggest getting rid of the callout "Very small fixed size variable".
    That way, only objects, not names, have the italicized callouts.)

    But using the term "references" and the directed-graph metaphor has its
    drawbacks. Avoiding the term "reference" will make it easier to navigate
    the turbulent waters of call-by-reference vs. call-by-value vs.
    call-by-name. (You don't even stick a toe in those waters in Section
    2.7.5.) Combining memory addresses with the directed graph metaphor
    invites the reader to think at way too low a level, IMHO.

    Another metaphor just occurred to me: a scavenger hunt. It even fits in
    with your potentially-infinite-attribute-access approach to the topic. A
    sequence of attribute accesses:

    turtle.forward.__doc__

    .... is like a sequence of scavenger-hunt instructions:

    1. Get your next clue at the big oak tree
    2. Get your next clue at the back door of the Valley Bank
    3. Get your next clue under Dad's Oldsmobile

    It's clear that the scavenger hunt's clues (short characters strings --
    like Python names) are different from the physical objects that you access
    as the hunt progresses (tree, bank building, automobile -- like Python
    objects). I haven't lived with this metaphor long enough to form an
    opinion as to where it might reside on the brain-dead <---> brilliant
    scale.

    As I've said in this forum (and the edu-sig forum) before, I think the
    best metaphor for understanding Python variable assignment is John Zelle's
    yellow-sticky-note metaphor. [2]

    I hope these comments help.

    -John

    --------------
    [1] Examples:

    Section 2, page 2:1

    It's almost impossible, but, as Robert A. Heinlein remarked,
    "A Paradox May Be Paradoctored".

    Section 2, page 2:3

    (I believe the original text comes from the "Jargon file")
    about how arbitrary, undesirable and downright dangerous DWIM
    guessing can be: ...

    Section 2.5.1, page 2:14

    a natural extension is to make that into a square spiral with
    far more windings; I recall it as a common theme in 1970’s
    pop-art and it can be quite impressive!

    Section 2.6.7, page 2:46

    (some flat-Earthers once thought that the flat Earth rested
    on four turtles, which in turn stood on four larger
    turtles, and so on all the way down)

    [2] "Python Programming: An Introduction to Computer Science" by John
    Zelle (Franklin, Biddle & Associates, 2004) See Section 2.5.1, "Simple
    Assignment"
     
    John Posner, Dec 19, 2009
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. TechBookReport

    Looking for an intro C programming book?

    TechBookReport, Feb 19, 2004, in forum: C Programming
    Replies:
    7
    Views:
    464
    Peter Nilsson
    Feb 22, 2004
  2. Larry
    Replies:
    5
    Views:
    400
    Bud Rogers
    Mar 4, 2004
  3. Boogie El Aceitoso

    Intro to concurrent programming with python

    Boogie El Aceitoso, Mar 5, 2004, in forum: Python
    Replies:
    1
    Views:
    2,541
    Jeff Duffy
    Mar 5, 2004
  4. arnuld
    Replies:
    7
    Views:
    387
    Salt_Peter
    Oct 30, 2006
  5. Enteng
    Replies:
    26
    Views:
    915
    Jeff Higgins
    Nov 17, 2007
Loading...

Share This Page