On Sat, 10 May 2014 17:21:56 +1000, Chris Angelico wrote: > On Sat, May 10, 2014 at 4:15 PM, Steven D'Aprano > <steve+comp.lang.pyt...@pearwood.info> wrote: >> On Sat, 10 May 2014 12:33:28 +1000, Chris Angelico wrote: >>> 1) Passing them as parameters. You can pass a pointer to a variable, >>> which is effectively the same as passing a variable to a function. >> >> No it is not. It is nothing like passing a variable to a function. You >> are passing a pointer, which is itself a value. True, it is a value >> which you, the author, gives meaning as a pointer to a variable, but >> that need not be the case. It might be a pointer to a part of an array, >> or a record, or to some random address in memory, or a dangling >> pointer. C allows you to perform arithmetic on pointers, which means >> you can construct pointers to nothing in particular. > > I think at this point it's arguable, in that you can get so close to > "passing a variable to a function" that it doesn't really matter about > the distinction. But as I explained further down, it really just shows > that "patch of memory" can be passed around, and that a variable can be > backed by such a patch of memory.
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?" If you asked, "Does Pascal have an exponentiation or power operator?", and I answered "Sure it does! If you want to calculate x squared, you just write x*x, if you want x cubed, write x*x*x, and if you want x to the power of twelve, x*x*x*x*x*x*x*x*x*x*x*x" you would rightfully slap me with a halibut. Being able to manually perform repeated multiplication is not the same as having the language support exponentiation. To say nothing of fractional exponents. "How about x to the power of one third?" 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. Personally, I don't imagine that there ever could be a language where variables were first class values *exactly* the same as ints, strings, floats etc. Otherwise, how could you tell the difference between a function which operated on the variable itself, and one which operated on the value contained by the value? The best you can do is for variables to be "second class" -- you can do these things to them, but you need special syntax or declarations to tell the compiler you're operating on the variable rather than the variable's value. E.g. Pascal and Algol have syntax for instructing the compiler when to pass a variable as a value, and when to pass the value. C gives you nothing. I would say that C variables are *third class*. There's no compiler support for variables-as-values at all, but you can manually fake it a bit by using pointers. There is no way to tell whether the pointer actually points to a variable, and since arrays aren't first class neither are pointer-to-arrays. Algol and Pascal are *second class*, since the compiler does allow you to pass variables as arguments (var parameters in Pascal, I forget what they are called in Algol). Likewise, Python let's you create new variables at runtime, or delete them, but you can't pass them around. But still, you're quite limited in what the language does for you, compared to what you have to do yourself: x = 23 function("x", globals()) # See, I can pass a variable! Not. >> 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. 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. >> 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 > If you do this > inside a function, the name has to be created as a local name before the > function begins execution. An implementation detail. CPython -- but not necessarily other Pythons -- use pre-allocated slots for local variables, but tries to hide this fact from you (it *almost* succeeds too). But those pre-allocated slots can represent unbound variables, i.e. variables which from the perspective of Python code don't exist: py> def demo2(): ... spam = 23 ... print('spam' in locals()) ... del spam ... print('spam' in locals()) ... py> demo2() True False If you peer under the hood of the CPython implementation, the slot still exists, but that's invisible from Python, and just an implementation detail. Other implementations may not even have slots at all. >> There are at least two other ways: >> >> globals()['spam'] = 23 >> exec('spam = 23') > > With exec, you can do anything "at run time". Does that mean that, in > languages with an exec action, absolutely everything is first-class? I'm > not sure that that counts. Maybe I'm wrong. No, you're right. That's why I said "Python variables aren't first-class either". But they're less second class than C or Pascal. > Subscript-assigning to globals() is actually creating new (module-level) > variables, though. And if Python allowed you to assign to locals() > inside a function, then I would accept that local function variables can > be created and destroyed at run time, but you can't, so local variables > aren't first-class. See above. -- Steven D'Aprano http://import-that.dreamwidth.org/ -- https://mail.python.org/mailman/listinfo/python-list