On 14/03/2016 03:01, Steven D'Aprano wrote:
On Mon, 14 Mar 2016 12:16 am, BartC wrote:

Worth having but at significant cost. But look at my jpeg test (look at
any other similar programs); how many function names are used
dynamically? How many functions *really* need to be dynamic?

As difficult as it may seem sometimes, Python is not a specialist
programming language designed to be optimal for your jpeg test, it is a
general purpose programming language designed for many different uses :-)

jpeg is an example of the sort of program that many, many people are writing. The sort where you write a bunch of functions, and you write code that calls them.

Sometimes, you need to call a function indirectly, or need a table of functions, or need to pass a function as an argument, but that's possible /without having to rename functions/. Even C can do all this.

there seems to be just one kind. The
different categories (function, variable, class, built-in, module etc)
are sorted out at *run-time*.

What do you mean by "sorted out"?

Well, in the case of executing f(a,b,x=c), then runtime will do the lookup of f, check the number of arguments, sort out that keyword argument, all that stuff.

That could be done at compile-time (ie. the byte-code compiler) if the compiler had sight of the definition of f, and it knew for sure the f in f() referred to that definition.

> You have names in a namespace which are
> bound to objects. Once you have bound a name, you can rebind it:

At compile time, you don't in general know what value things will have. You
don't even know what type they will have (since the type of an object is
part of its value).

That's true of *variables*. It needn't be true of *functions* and *modules* and *classes* because you've told the compiler exactly what they are!

If you want to do this with functions, I've already shown a few times a technique where you split the function name used with 'def' into two: a fixed static name and a dynamic name, a 'pointer' initially referring to this function, that can later be assigned something else. If you have to.

Here is an extreme example to demonstrate the difficulty:


import random
if random.random() < 0.5:
     def f():
         return 1
else:
     f = "hello"

f = "goodbye"


So tell me: *at compile time*, how do you know whether the final binding
(assignment of "goodbye" to variable f) should be allowed or not?

First, let me try and emulate that exact behaviour in a 'crippled' language that doesn't allow function rebinding:

function f1= {return 1}

if random(1)<0.5 then
  f:=f1
else
  f:="hello
fi

f:="goodbye"


So the question doesn't come up; we're simply dealing with variables. The actual function (the name that permanently refers to the code 'return 1', or 'f1' in my example) doesn't change.

I don't think you are, but let's suppose you're right and that the compiler
can reliably detect and prevent code like this:

def f(): return 1
g = f
g = something_else  # allowed
f = something_else  # not allowed

Are we talking about some imaginary version of Python where the ability to re-bind function, module and class names hadn't been allowed?

Then you would simply tweak the code so that 'f' the variable and 'f' the actual function are different names.

Or how you change Python now to have both fixed function names yet allow all these manipulations?

I don't know. People don't seem to like adding annotations such as:

static def f(): return 1

which would force you to create an alias for f as I said above:

static def _f(): return 1
f = _f

How do you intend to prevent this?

def f(): return 1
exec "f = something_else"

(I don't use exec or eval, and have never seriously implemented them. In fact I wrote these comments once in comp.programming a few years back:

>> Perhaps an "Eval Index" can be created which measures how much Eval
>> slows down a language: the bigger the slow-down, then the more
>> efficient would be the language. And it could be measured by putting
>> Eval "...." around every line or statement (or smallest unit of
>> which Eval can make sense) of a benchmark program and seeing how
>> much it slows down.
>>
>> (And something like Lisp I'd imagine would have an Eval Index of 1.0
>> :-)  )

But to get back to your question: same answer as above.

Suppose we removed the ability to rebind names that were bound to a
function, as you suggest. There's a very important and commonplace use for
rebinding functions that we would lose: decorators.

But there are times where you
cannot use decorator syntax, and have to write it the old-school way:

func = decorate(func)

I can't see a problem here. Just a minor bit of renaming needed. (Although I don't understand whatever else decorators too.)

Yes, there's a bit of inconvenience when you're importing a library where you're not allowed to re-bind the functions inside it, so that you can use the same name to mean something different.

But how many programs need that functionality? It might be a case of the tail wagging the dog...

And there will generally be a way around it.

I think anyway that any Python program using dynamic functions, can be
trivially transformed to one that uses static functions. It won't be
pretty, but any function:

   def f(): whatever

could be rewritten as:

   def __f(): whatever
   f = __f()

No it can't. You haven't thought it through.

(1) Are you expecting to write "__f()" inside your code when you mean to
call f()? If so, then what's the purpose of f()? If not, then you
write "f()" and nothing has changed: the interpreter has to do a runtime
lookup because f might have changed.

(2) What is stopping people from changing __f in all the many different ways
that it could be changed?

The above is simply to demonstrate that a program that relies on writing to function names (ie. the names that follow 'def') can be transformed into an equivalent program where such a name doesn't need writing to.

Ergo, Python doesn't /need/ mutable function names. (Disclaimer: this is conjecture on my part...)

I'm not suggesting that people now have to start writing these aliases everywhere (that would be needed in more languages that foolishly separate the concept of a function, from a reference to a function).

It just opens up the possibility of such static functions which can lead to more streamlined or more easily optimisable code.

Now that I've shown you all the ways that code can be changed on the fly,
and probably convinced you that it is impossible to optimize Python without
changing the language,

I'm sure it can. Projects such as PyPy have shown that, and on certain programs that can give dramatic increases in performance far beyond what is possibly by tinkering with CPython.

But because I do language design, I can see many possibilities from changing the language too!

--
Bartc
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to