Values and objects

Chris Angelico rosuav at gmail.com
Sat May 10 05:32:03 EDT 2014


On Sat, May 10, 2014 at 7:09 PM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> On Sat, 10 May 2014 17:21:56 +1000, Chris Angelico wrote:
>
> No offence Chris, but I think this demonstrates that learning C causes
> brain damage and prevents clear logical thinking :-P
>
> You're not passing a variable to a function. You're passing a pointer,
> which is itself a first-class value. It could be a pointer to ANYTHING,
> or NOTHING at all -- C doesn't even promise to ensure that it is a valid
> pointer, although more modern languages may. There's certainly no
> guarantee that it's a pointer to a variable. And you cannot create new
> variables -- C only allows variables to be created at compile time.
>
> The question is not, "Can I implement some aspects of first-class
> behaviour for variables by hand?" The question is, "Are variables treated
> as first class values in C?"

Ehh... good point. I admit my brain damage - which, I have to say, has
earned me a good portion of my life's salaries, so it's not useless :)
Okay. So variables are not first-class in C. I still think memory
blocks are pretty much first class, though; you can declare them at
compile time (usually as an array of char or pointers) or at run time
(with malloc or equivalent), and they can be passed to functions,
returned from functions, etc. The only limitation is that a generic
memory block doesn't maintain its size, so you can't distinguish
between a char[10] and a char[1024].

> Being able to manually pass pointers to variables about is not the same
> as having first class variables. It fails on the very first hurdle, "Are
> variables treated the same as other values?"
>
> How do I pass an int to a function? func(some_int)
>
> How do I pass a double to a function? func(some_double)
>
> How do I pass a bool to a function? func(some_bool)
>
> How do I pass a variable to a function? ptr = &some_variable; func(ptr)
>
> Does that look the same to you? The fact that you can do it at all is not
> sufficient to make it first class. It just makes it a work-around for the
> lack of first class variables in the language.

You can simply say func(&some_variable), but yes, there is that
difference. (This is how "out" parameters usually look in C. You stick
ampersands in front of things.) And that's still passing memory blocks
around, not variables.

>>> Rather than *creating* patches of memory, malloc merely allocates it
>>> from pre-existing memory.
>>
>> I disagree. On a modern system with memory management, malloc can grab
>> memory from the system, thus making it available to your process. Sure,
>> physical memory will normally have to have been installed in the system,
>> but conceptually you could have a malloc function that actually freezes
>> the program, asks the user to build a new computer and turn it on,
>> connects to a new service on that computer, and allocates memory from
>> there. As far as your program's concerned, malloc actually does (attempt
>> to) give you more room than you had.
>
> Ha, well I guess you got me there. Perhaps a less over the top example is
> that you're running in a VM, and malloc can request more information from
> the host (which presumably has unlimited memory). Still impractical, but
> theoretically possible.

Yeah. Completely impractical, but so is "Post-It Note Python" where
everything's done with physical strings and sheets of paper. Thought
experiments don't have to be performant :)

> Nevertheless, blocks of memory are not *first class* because you don't
> handle blocks of memory like other values. To make a new int variable,
> you declare it: "int foo". To make a new block of memory, there is no
> declaration "block foo". Rather, you call malloc() at runtime. And it
> might fail. "int foo" can never fail.

As I mentioned above, you can make a new block of memory with "char
foo[1234]". And that's where a lot of buffer overruns come from,
because someone thinks "1234 is *heaps* of space"... but sometimes you
really can know in advance how long something can be. (Maybe you're
about to ask a file to give you the next 1233 bytes of content.) In
this form, it's as safe as "int foo" - that is to say, safe unless
your stack overflows, in which case all bets are off anyway.

>>> Python variables aren't first-class either, but in fact we can get a
>>> bit closer to first-class than either C or Pascal.
>>>
>>> Creating new variables is trivial. Since they don't need to be
>>> declared, you create a new variable just by assigning to it:
>>>
>>> try:
>>>     spam
>>> except NameError:
>>>     spam = 23
>>
>> No no no, this is really creating them at compile time.
>
> It certainly isn't. Here's a slightly different demonstration of the same
> principle, this time inside a function to prove that there's nothing
> special about the global namespace:
>
>
> py> def demo():
> ...     print('spam' in locals())
> ...     spam = 23
> ...     print('spam' in locals())
> ...
> py> demo()
> False
> True

Tell me, what may this function do in a compliant Python?

def demo():
    ret = spam
    spam = 23
    return ret

In CPython, that'll raise UnboundLocalError, because the local
variable 'spam' does already exist, and currently has no value (no
object bound to it). If a compliant Python implementation is allowed
to have this return the value of a global or builtin spam, then I
would agree that you can create variables at run time. Is
demo.__code__.co_varnames a CPython implementation detail or part of
the language spec?

Ultimately, a variable name must be looked up somehow. If you can
create and destroy them inside an inner scope that shadows an outer
scope, then you should be able to shadow and unshadow them. Is there a
way to do this with exec? I tried this and it failed:

def demo():
    print("spam =",spam)
    exec("spam = 23")
    print("spam =",spam)
    exec("del spam")
    print("spam =",spam)

CPython 3.4, each lookup of spam becomes a LOAD_GLOBAL, so each print
outputs the global value of spam. Is there a way to fiddle with this?

ChrisA



More information about the Python-list mailing list