Re: Question about math.pi is mutable

2015-11-14 Thread Antoon Pardon
Op 14-11-15 om 04:11 schreef Michael Torrie:
> On 11/10/2015 03:03 AM, Antoon Pardon wrote:
>> Op 10-11-15 om 00:29 schreef Ben Finney:
>>>
>>> Who is doing what to whom? The user of the library isn't doing anything
>>> to the library author, so what is it the library author would consent
>>> to? Instead, you seem to be trying to assert a *power* of the library
>>> author to restrict the library user. Such a power is not granted by
>>> Python.
>>
>> Python is not at liberty to grant or deny such a power. Python is just
>> a vehicle in which code is written. The author of a library can restrict
>> its use anyway he sees fit.
> 
> No he cannot, outside the bounds of copyright law.  Why would you think
> otherwise?  The only document that binds the end user in any way is the
> copyright license, unless some other formal contract has been arranged.

You haven't contradicted me in any way. What you are talking about here
is in what form those restrictions must be published. I am talking about
the restrictions the author can put in a license.

-- 
Antoon Pardon
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Question about math.pi is mutable

2015-11-13 Thread Denis McMahon
On Fri, 13 Nov 2015 09:04:54 +1100, Steven D'Aprano wrote:

> On Fri, 13 Nov 2015 07:40 am, Thomas 'PointedEars' Lahn wrote:

> > [crap I expect]

> And you should consider the irony, and hypocrisy, of somebody who signs
> his posts "PointedEars" bitching about supposed "real names".

TPEL has been trolling html, php and javascript newsgroups for years, 
recently he seems to have discovered python newsgroups. :(

-- 
Denis McMahon, denismfmcma...@gmail.com
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Question about math.pi is mutable

2015-11-13 Thread Michael Torrie
On 11/10/2015 03:03 AM, Antoon Pardon wrote:
> Op 10-11-15 om 00:29 schreef Ben Finney:
>>
>> Who is doing what to whom? The user of the library isn't doing anything
>> to the library author, so what is it the library author would consent
>> to? Instead, you seem to be trying to assert a *power* of the library
>> author to restrict the library user. Such a power is not granted by
>> Python.
> 
> Python is not at liberty to grant or deny such a power. Python is just
> a vehicle in which code is written. The author of a library can restrict
> its use anyway he sees fit.

No he cannot, outside the bounds of copyright law.  Why would you think
otherwise?  The only document that binds the end user in any way is the
copyright license, unless some other formal contract has been arranged.

>> Instead, the library author is obliged to treat the library user as an
>> adult who consents to the freedoms inherent to Python's design, and to
>> not restrict their use of the library needlessly.
> 
> There is no such obligation. And if it was an obligation, you can hardly
> talk about consenting. Consenting adults mean that either party can
> decide on conditions. Once one party is obligated it is no longer consenting.

You are correct there is no obligation, but nor does Python empower the
library developer.   He may attempt obfuscation or other means to
control the use of his library of course, but only copyright grants him
legal authority of any kind.

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


Re: Question about math.pi is mutable

2015-11-13 Thread Larry Hudson via Python-list

On 11/13/2015 01:19 AM, Denis McMahon wrote:

On Fri, 13 Nov 2015 09:04:54 +1100, Steven D'Aprano wrote:


On Fri, 13 Nov 2015 07:40 am, Thomas 'PointedEars' Lahn wrote:



[crap I expect]



And you should consider the irony, and hypocrisy, of somebody who signs
his posts "PointedEars" bitching about supposed "real names".


TPEL has been trolling html, php and javascript newsgroups for years,
recently he seems to have discovered python newsgroups. :(

I found that TPEL post to be particularly amusing/ironic (hilarious, really) when he continued 
by talking about a group that ignores posts by people who don't use real names!   :-)

I generally ignore his posts as well.

 -=- Larry -=- <-- My real name, which is NOT Lawrence (or anything 
similar)!

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


Re: Question about math.pi is mutable

2015-11-12 Thread Thomas 'PointedEars' Lahn
Chris Angelico wrote:

> […] Ben Finney […] wrote:
>> I recommend you ignore that request; “Bartc” is fine as a name here,
>> IMO.
> 
> Given that LARTC means Linux Advanced Routing and Traffic Control, I'm
> guessing Bartc is all about *BSD networking? :)

I thought LART were the Luser Attitude Readjustment Tool ;-)

And on GABELNs [1] it is considered polite to post using your real name.  
Lack of politeness towards the people whom would otherwise be willing to 
help you may cause you to be ignored by them instead.  You have been warned.

BTW, it’s attribution *line*, _not_ attribution novel.

[1] {Group Area Board Echo List Newsgroup}s

-- 
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Question about math.pi is mutable

2015-11-12 Thread Steven D'Aprano
On Fri, 13 Nov 2015 07:40 am, Thomas 'PointedEars' Lahn wrote:

> And on GABELNs [1] it is considered polite to post using your real name.

Falsehoods programmers believe about names:

http://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/


> You have been warned.

And you should consider the irony, and hypocrisy, of somebody who signs his
posts "PointedEars" bitching about supposed "real names".

How do you propose to tell the difference between "real" names and "fake"
names? If BartC signed his posts "Engelbert Humperdinck", "Cher", "Thomas
Lahn" or "Bartholomew Roberts" how would you decide whether it was "real"
or "fake"?

Petty bigotry over "real" names is no better than any other sort of bigotry.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-12 Thread BartC

On 12/11/2015 20:40, Thomas 'PointedEars' Lahn wrote:

Chris Angelico wrote:


[…] Ben Finney […] wrote:

I recommend you ignore that request; “Bartc” is fine as a name here,
IMO.


Given that LARTC means Linux Advanced Routing and Traffic Control, I'm
guessing Bartc is all about *BSD networking? :)


I thought LART were the Luser Attitude Readjustment Tool ;-)

And on GABELNs [1] it is considered polite to post using your real name.
Lack of politeness towards the people whom would otherwise be willing to
help you may cause you to be ignored by them instead.  You have been warned.


I'm reading this 'list' on usenet. No-one else in many thousands of 
posts has ever complained before about my user-name.


But I guess you haven't been on that many forums. Few people use their 
full names or anything that looks like a real name. Partly, so they 
don't have someone who violently disagrees with them causing problems 
(like discovering their address and coming round).


Mostly people use names that are wacky, funny, or just meaningless.

(FWIW, my real first name is Bart and C is the initial of my last name. 
Very dull I know.)


--
bart c

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


Re: Question about math.pi is mutable

2015-11-12 Thread Chris Angelico
On Fri, Nov 13, 2015 at 9:19 AM, BartC  wrote:
> (FWIW, my real first name is Bart and C is the initial of my last name. Very
> dull I know.)

That's a common way of signing emails. I sign most of mine "ChrisA",
which (as you'll see from my headers) is constructed the same way. So
did the late Dave Angel (DaveA). Although I suppose I'm going to get
in trouble with PointedEars for not using my *full* name, but
abbreviating it to just "Chris".

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


Re: Question about math.pi is mutable

2015-11-11 Thread Marko Rauhamaa
Steven D'Aprano :

> Since compile, eval and exec are Python built-ins, if it doesn't
> include a byte-code compiler, it isn't Python. It's just a subset of
> Python.

compile() can be implemented trivially, or in any other manner. It
simply needs to return a "code object." I suspect even a string might
work as a code object.


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


Re: Question about math.pi is mutable

2015-11-11 Thread Steven D'Aprano
On Wed, 11 Nov 2015 07:30 pm, Marko Rauhamaa wrote:

> Steven D'Aprano :
> 
>> Since compile, eval and exec are Python built-ins, if it doesn't
>> include a byte-code compiler, it isn't Python. It's just a subset of
>> Python.
> 
> compile() can be implemented trivially, or in any other manner. It
> simply needs to return a "code object." I suspect even a string might
> work as a code object.

Sure. That's just quality of implementation. In principle, a Python
interpreter might even operate without any byte-code at all, parsing each
line of code before executing it.

Nevertheless, whatever quality of implementation compile/eval/exec offer,
they *must* be available at runtime, otherwise the language is just a
subset of Python.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-10 Thread Antoon Pardon
Op 10-11-15 om 00:29 schreef Ben Finney:
>
> Who is doing what to whom? The user of the library isn't doing anything
> to the library author, so what is it the library author would consent
> to? Instead, you seem to be trying to assert a *power* of the library
> author to restrict the library user. Such a power is not granted by
> Python.

Python is not at liberty to grant or deny such a power. Python is just
a vehicle in which code is written. The author of a library can restrict
its use anyway he sees fit.

> Instead, the library author is obliged to treat the library user as an
> adult who consents to the freedoms inherent to Python's design, and to
> not restrict their use of the library needlessly.

There is no such obligation. And if it was an obligation, you can hardly
talk about consenting. Consenting adults mean that either party can
decide on conditions. Once one party is obligated it is no longer consenting.

-- 
Antoon Pardon

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


Re: Question about math.pi is mutable

2015-11-10 Thread Laura Creighton
In a message of Tue, 10 Nov 2015 17:10:09 +1100, Ben Finney writes:
>Steven D'Aprano  writes:
>
>> Ben, I fear that you are not paying attention to me :-)
>
>Possibly, though I also think there's miscommunication in this thread.
>
>You speak of “compile time” and “run time”. You also speak of what the
>compiler can do, at run time.
>
>I am a Bear of Little Brain, but: Isn't anything that the *compiler*
>does, by definition done at *compile* time?

No.

We used to have a pretty strict defintion about what a compiler was, and
what an interpreter was.  You did the compile things at compile time,
and then you the the interpreter things at runtime.

No more.  We have Just in Time compilers.  They do their compiling
at run time.  Or perhaps 'there is no such thing as compile time
any more'.

Laura

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


Re: Question about math.pi is mutable

2015-11-10 Thread Terry Reedy

On 11/9/2015 9:37 PM, Steven D'Aprano wrote:


The compiler doesn't need to decide *in advance* whether the attribute might
have changed. It knows whether it has changed or not *at runtime*.


You are using 'compiler' when you should, to avoid confusion, use 
'interpreter'.



It's one thing to say that *in principle* any function might modify or
shadow builtins. That's true, because we don't know what's inside the
function. But the compiler knows, because it actually executes the code


'interpreter'


inside the function and can see what happens when it does. It doesn't have
to predict in advance whether or not calling `func(x)` shadows the builtin
`len` function, *it can see for itself* whether it did or not.

At compile time, `func(x)` might do anything. But at runtime, we know
exactly what it did, because it just did it.

Imagine that the compiler keeps track of whether or not builtins has been


/compiler/code compiled by the compiler and interpreted by the 
interpreter (which could be the CPU)/



modified. Think of it as a simple "dirty" flag that says "yes, builtins is
still pristine" or "no, something may have shadowed or modified the
builtins". That's fairly straight-forward: builtins is a dict, and the
compiler can tell whether or not __setitem__ etc has been called on that
dict. Likewise, it can keep track of whether or not a global has been
created that shadows builtins: some of that can be done statically, at
compile-time, but most of it needs to be done dynamically, at runtime.


This is more or less Victor Stinner's proposal, and he has a working 
prototype that runs nearly all the test suite.  He now plans to refine 
it and measure changes in space and time usage.



If the flag is set, the compiler knows that the optimization is unsafe and
it has to follow the standard name lookup, and you lose nothing: the
standard Python semantics are still followed. But if the flag is clear, the
compiler knows that nothing has shadowed or modified builtins, and a whole
class of optimizations are safe. It can replace a call to (say) len(x) with
a fast jump, avoiding an unnecessary name lookup in globals, and another
unnecessary name lookup in builtins. Or it might even inline the call to
len. Since *most* code doesn't play tricks with builtins, the overhead of
tracking these changes pays off *most* of the time -- and when it doesn't,
the penalty is very small.



--
Terry Jan Reedy

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


Re: Question about math.pi is mutable

2015-11-10 Thread Ben Finney
Laura Creighton  writes:

> In a message of Tue, 10 Nov 2015 17:10:09 +1100, Ben Finney writes:
> >I am a Bear of Little Brain, but: Isn't anything that the *compiler*
> >does, by definition done at *compile* time?
>
> No.
>
> We used to have a pretty strict defintion about what a compiler was,
> and what an interpreter was. You did the compile things at compile
> time, and then you the the interpreter things at runtime.
>
> No more. We have Just in Time compilers. They do their compiling at
> run time. Or perhaps 'there is no such thing as compile time any
> more'.

Very well. I argued on the basis of what could be determined at the time
Steven refers to as “compile time”, i.e. before any part of the module
begins to run.


Steven D'Aprano  writes:

> Python -- yes, even CPython -- has a runtime compiler. When you import
> a module, it is compiled (if needed) just before the import. Likewise,
> when you call the `compile`, `eval` or `exec` built-ins, the compiler
> operates.
>
> I'm not calling this a JIT compiler, because the simple-minded
> compilation performed by `compile` etc doesn't use any run-time
> information. It just statically compiles the code to byte-code.

That's what I though. I'm aware of JIT compilers, and was pretty sure
Python doesn't have them. What's more, if it operates at a whole-module
level, and not later than when the module is imported.

Under those conditions, I maintain my objection to the proposed
optimisation.

The proposal is explicitly for optimisations made by the Python
compiler. As proposed, it only seems to be worthwhile once Python no
longer has a distinct “compiler” and “interpreter” is dissolved. Until
then, it seems pointless.

-- 
 \ “There is something wonderful in seeing a wrong-headed majority |
  `\   assailed by truth.” —John Kenneth Galbraith, 1989-07-28 |
_o__)  |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-10 Thread Steven D'Aprano
On Tue, 10 Nov 2015 11:14 pm, Ben Finney wrote:

>> Python -- yes, even CPython -- has a runtime compiler. When you import
>> a module, it is compiled (if needed) just before the import. Likewise,
>> when you call the `compile`, `eval` or `exec` built-ins, the compiler
>> operates.
>>
>> I'm not calling this a JIT compiler, because the simple-minded
>> compilation performed by `compile` etc doesn't use any run-time
>> information. It just statically compiles the code to byte-code.
> 
> That's what I though. I'm aware of JIT compilers, and was pretty sure
> Python doesn't have them. 

What do you think PyPy is then?

CPython is intentionally a pretty simple-minded compiler. Even no-brainer
constant folding is mildly controversial among some Python devs. But
CPython isn't "Python", it is just the reference implementation. Nuitka
aims to be an optimized AOT (Ahead Of Time) Python compiler, and PyPy is
already a state of the art (if not cutting edge) JIT Python compiler.

And if Victor Skinner's experimental FAT Python works out, even CPython
itself will gain some simple JIT techniques, rather similar to what Psycho
was doing ten years ago.


> What's more, if it operates at a whole-module 
> level, and not later than when the module is imported.

Now you're getting into implementation details of the JIT compiler. Can it
track entities across modules? How exactly does it operate?

PyPy is a "tracing JIT", which (if I have understood correctly) means it
actually analyses the code as it runs, using knowledge gained at runtime to
dynamically decide what to compile. This means that PyPy is best suited to
code that has long-running loops, and not well suited to scripts that don't
run for a long time. But another (hypothetical) JIT compiler might be more
like Psycho.


> Under those conditions, I maintain my objection to the proposed
> optimisation.
> 
> The proposal is explicitly for optimisations made by the Python
> compiler. As proposed, it only seems to be worthwhile once Python no
> longer has a distinct “compiler” and “interpreter” is dissolved. Until
> then, it seems pointless.

Python has not had a distinct "compiler" and "interpreter" since about
version 0.1. The execution module of Python as a dynamic byte-code
compiled, interpreted language with eval and exec *depends* on the compiler
being available during the execution phase, i.e. at runtime.

Some of the things I've suggested already exist, and have proven that they
work: Psycho and PyPy, to say nothing of similar technologies for other
equally dynamic languages such as Javascript and Smalltalk. Others are
state of the art compiler techniques -- they might not have been applied to
*Python* but that's only because nobody has got around to it, not because
it can't be done.

I daresay that there are implementation challenges to making Python faster
than it is without compromising on the semantics of the language, but there
is nothing fundamentally impossible about the idea.

Ben, I know that the IT crowd is rather conservative, and the Python
community even more so, but at the point where you are denying the
possibility of technologies which *already exist* I think that things have
got a bit out of hand. It's a bit like somebody getting on Twitter to
tweet "A globally interconnected communication network allowing computers
all over the world to communicate? Impossible! And even if it were
possible, nobody would use it."

;-)

 

-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-10 Thread Steven D'Aprano
On Tue, 10 Nov 2015 05:10 pm, Ben Finney wrote:

> Steven D'Aprano  writes:
> 
>> Ben, I fear that you are not paying attention to me :-)
> 
> Possibly, though I also think there's miscommunication in this thread.
> 
> You speak of “compile time” and “run time”. You also speak of what the
> compiler can do, at run time.
> 
> I am a Bear of Little Brain, but: Isn't anything that the *compiler*
> does, by definition done at *compile* time?

In a manner of speaking, yes, of course. But you've missed the critical
issue: when is compile time?

If you're like most people, you probably are thinking about an execution
model where the compiler analyses the source code statically, using nothing
but what can be seen in the source code, then hands over some sort of
compiled byte code to be run by an interpreter or machine code that is
executed by the CPU. The compiler and interpreter are completely distinct.

If so, you're stuck with an obsolete model of computation, like somebody
trying to understand modern chemistry based on the "planetary orbit" model
of the atom.

So when is compile time? Of course, in some languages (like C, or Pascal)
compilation occurs as a distinct stage before you can run the code. But
that's not necessarily true for all compilers. "Just In Time" compilers
operate while the program is running, compiling code just before it is
executed. The distinction between compiler and interpreter is gone, or at
least weakened.

Python -- yes, even CPython -- has a runtime compiler. When you import a
module, it is compiled (if needed) just before the import. Likewise, when
you call the `compile`, `eval` or `exec` built-ins, the compiler operates.

I'm not calling this a JIT compiler, because the simple-minded compilation
performed by `compile` etc doesn't use any run-time information. It just
statically compiles the code to byte-code.

But the fact that it happens *at runtime* is significant, because in
principle there is a lot more information available to the compiler, if it
were intelligent enough to make use of it. For example, suppose you execute
this Python snippet:

result = x + 2

At static compile time, looking just at the source, you may not know what
value x is, or even whether or not x actually exists, so you're forced to
go through the standard Python semantics to determine what the result is:

py> from dis import dis
py> dis("result = x + 1")
  1   0 LOAD_NAME0 (x)
  3 LOAD_CONST   0 (1)
  6 BINARY_ADD
  7 STORE_NAME   1 (result)
 10 LOAD_CONST   1 (None)
 13 RETURN_VALUE


But a JIT compiler gets to compile code right before that line is due to
execute. By the time the JIT compiler gets to see that line of code, it can
already know whether or not name "x" exists, and if so, which namespace it
is in. It knows what value "x" has. The compiler can choose what byte code,
or even machine code, to generate, using information available just before
that code is needed.

Suppose it knows that "x" is bound to an float. Then it can cast the int 1
to the machine floating point double 1.0 and generate code that adds that
to a float. That's likely to be tens of times faster than the BINARY_ADD
op-code, which has to do a whole lot of type-checking, method calling, and
creating and disposing of objects to add the two values.

Only if "x" is unknown, or if it is some type that doesn't have a convenient
optimization, does the JIT compiler generate the standard (but unoptimized)
BINARY_ADD op-code.

Provided that, on average, the book-keeping needed by the JIT compiler is
outweighed by the gains, the whole process counts as a win.

Now, CPython doesn't include a JIT compiler. But PyPy does, and it is much
more sophisticated than anything I could explain. I'm not the only one:

https://glyph.twistedmatrix.com/2012/02/this-isnt-how-pypy-works-but-it-might.html

If you remember Psycho, that might help. Psycho (according to its creator)
isn't a "true" JIT compiler, but it's close enough. Psycho would generate
machine code -- actual low level code running in the CPU or FPU, not byte
code -- for certain Python operations, plus guard code that ensured the
machine code was only called when it was safe to do so. So this is long
proven technology.

More about JIT compilation on Wikipedia:

https://en.wikipedia.org/wiki/Just-in-time_compilation



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-10 Thread Steven D'Aprano
On Wednesday 11 November 2015 00:26, BartC wrote:

> Does the Python language specify how it is to be compiled and executed?

Not in so many words, but there are limitations on what you can do based on 
the specified semantics of Python.

But so long as you meet those semantics, you can implement them any 
reasonable way you like:

- CPython uses one specific implementation written in C;

- PyPy uses a powerful tracing JIT compiler written in an intermediate 
language RPython;

- IronPython uses the .Net CLR virtual machine;

- Jython uses the Java virtual machine;

- there was an experimental version of Python using the Parrot virtual 
machine;

etc. Those implementations will naturally perform differently. For example, 
I believe that IronPython *generally* is faster than CPython, with some 
exceptions.


> If not, then you can use any interpretation you like, provided the
> program gives the expected results.

Precisely.

> That includes using a static compilation pass that generates byte-code,
> even if it is only done immediately before running the main module, or
> just before performing an import operation on another.

That's what CPython already does.


> Anything is possible. But the chances are that if you are running
> CPython, then it will probably include a discrete byte-code compiler.

Since compile, eval and exec are Python built-ins, if it doesn't include a 
byte-code compiler, it isn't Python. It's just a subset of Python.



>> execute this Python snippet:
>>
>> result = x + 2
[...]
>> But a JIT compiler gets to compile code right before that line is due to
>> execute. By the time the JIT compiler gets to see that line of code, it
>> can already know whether or not name "x" exists, and if so, which
>> namespace it is in. It knows what value "x" has.
> 
> How does it do that? How is the 'x+1' even stored in the machine?

That depends entirely on the implementation of the compiler.


> Suppose the preceding lines are:
> 
> if random+bit()==1:
>x=920.5
> else:
>x=[8,5,4,9,1,7,6,3,2]
> 
> or:
> 
> if some_condition: del x
> 
> it will probably know as much about x as the static compiler does!

Not at all. The difference is, having called rand_bit() and tested whether 
it is 1, the compiler takes a branch:

- it binds 920.5 to x

- or it binds [8, 5, 4, ...] to x

The compiler knows which branch it just took, *because it just took it*. If 
it doesn't know which branch it just took, it isn't a JIT compiler! It's 
just a classic, old-fashioned interpreter with no smarts.

So, having just bound some value to x, the compiler knows that x is a float 
(or a list), and can optimize the next instruction, which is "x + 1".

CPython can't do that, because it doesn't have the infrastructure to perform 
the necessary book-keeping. And it probably never will do that, because 
Guido likes the fact that CPython is simple enough for him to understand. 
He's happy for PyPy and other third-party implementations to do the clever 
stuff.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-10 Thread BartC

On 10/11/2015 11:34, Steven D'Aprano wrote:

On Tue, 10 Nov 2015 05:10 pm, Ben Finney wrote:




I am a Bear of Little Brain, but: Isn't anything that the *compiler*
does, by definition done at *compile* time?


In a manner of speaking, yes, of course. But you've missed the critical
issue: when is compile time?

If you're like most people, you probably are thinking about an execution
model where the compiler analyses the source code statically, using nothing
but what can be seen in the source code, then hands over some sort of
compiled byte code to be run by an interpreter or machine code that is
executed by the CPU. The compiler and interpreter are completely distinct.


Does the Python language specify how it is to be compiled and executed?

If not, then you can use any interpretation you like, provided the 
program gives the expected results.


That includes using a static compilation pass that generates byte-code, 
even if it is only done immediately before running the main module, or 
just before performing an import operation on another.



If so, you're stuck with an obsolete model of computation, like somebody
trying to understand modern chemistry based on the "planetary orbit" model
of the atom.

So when is compile time? Of course, in some languages (like C, or Pascal)
compilation occurs as a distinct stage before you can run the code. But
that's not necessarily true for all compilers.


C can also be interpreted from source as you go along, although it can 
be very difficult (but probably not as difficult as implementing PyPy).


Anything is possible. But the chances are that if you are running 
CPython, then it will probably include a discrete byte-code compiler.



execute
this Python snippet:

result = x + 2

At static compile time, looking just at the source, you may not know what
value x is, or even whether or not x actually exists, so you're forced to
go through the standard Python semantics to determine what the result is:

py> from dis import dis
py> dis("result = x + 1")
   1   0 LOAD_NAME0 (x)
   3 LOAD_CONST   0 (1)
   6 BINARY_ADD
   7 STORE_NAME   1 (result)
  10 LOAD_CONST   1 (None)
  13 RETURN_VALUE


But a JIT compiler gets to compile code right before that line is due to
execute. By the time the JIT compiler gets to see that line of code, it can
already know whether or not name "x" exists, and if so, which namespace it
is in. It knows what value "x" has.


How does it do that? How is the 'x+1' even stored in the machine? 
Suppose the preceding lines are:


   if random+bit()==1:
  x=920.5
   else:
  x=[8,5,4,9,1,7,6,3,2]

or:

   if some_condition: del x

it will probably know as much about x as the static compiler does! And a 
static compiler can still do a surprising bit of analysis, such as 
transforming the the first if-statement above, followed by your return 
statement, into:


   if random_bit()==1:
  return 922.5
   else:
  raise_error()

But we're trying to find ways of avoiding a dictionary lookup, ie a 
LOAD_GLOBAL or LOAD_NAME. If static analysis of the entire source can 
yield fixed tables of such names as 'x', even if subject to runtime 
alterations, then why not do that if it means possible faster access.



More about JIT compilation on Wikipedia:

https://en.wikipedia.org/wiki/Just-in-time_compilation


JIT covers a lot including straightforward translation of byte-code for 
a statically language, into native code.


In a language like Python, it's rather more elaborate.

And PyPy, as you hinted, is complelely different. I don't think it even 
attempts to JIT compile your example, it JIT compiles some repeatedly 
executed pathways in a program some way removed from the Python code or 
even its interpreter.


Or something like that... Whatever it is, it's more like magic. But what 
I started discussing here are ways of making a regular Python 
interpreter more efficient. I think that with projects such as PyPy, 
people are less interested with speeding up CPython, for one thing 
because it is not going to speed things up by ten times, so there seems 
little point.


--
BartC


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


Re: Question about math.pi is mutable

2015-11-09 Thread Chris Angelico
On Mon, Nov 9, 2015 at 11:22 PM, BartC  wrote:
> I tried this code:
>
> a=10
> print (a)
>
> del a
> #print (a)
>
> a=20
> print (a)
>
> That sort of confirms what you are saying: that names don't even come into
> existence until the first time they are encountered. They don't just contain
> None, or some other value which means the name itself exists, but it hasn't
> been initialised to anything. And that del removes the name completely from
> the set that are known.
>
> That makes Python unlike any other language I've used.

It's a direct consequence of the dynamic namespacing. You'll find
similar results in JavaScript/ECMAScript if you play around with
prototype-based inheritance, which has a similar rule ("if the
property isn't here, look at the prototype") to the Python namespacing
rule ("if the name isn't in this namespace, look at the next one
outward").

And you're absolutely correct. Unused names do not "contain None" in
any sense - they utterly do not exist. When you 'del' a name, that
name utterly ceases to exist.

> On the other hand, if I put the above code into a function and then call the
> function, attempting to print a just after it's been deleted results in:
>
>  UnboundLocalError: local variable 'a' referenced before assignment

That's a special case of NameError that was added to make it a bit
easier to track down certain types of bug.

> So while local names can presumably be manipulated just like globals, that
> doesn't stop being implemented via a fixed slot in a table.
>

Global names are simply module attributes, so they can be manipulated
in many ways. Function locals are not; there's no way to say
"current_stack_frame.foo = 2", so there's no need to hack around with
name lookups. (The locals() dictionary isn't meant to be modified, and
changes may or may not have effect on actual local name bindings.)

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


Re: Question about math.pi is mutable

2015-11-09 Thread Grant Edwards
On 2015-11-08, Marko Rauhamaa  wrote:
> Grant Edwards :
>
>> On 2015-11-07, Marko Rauhamaa  wrote:
>>> "const" is a very ineffective tool that clutters the code and forces
>>> you to sprinkle type casts around your code.
>>
>> But it allows the compiler to warn you if you pass a pointer to a
>> read-only data to a function that expects a pointer to writable data.
>
> Unfortunately, it doesn't:
>
>
> #include 
> #include 
>
> int main()
> {
> const char name[] = "Tom";
> char *p = strstr(name, "Tom");
> strcpy(p, "Bob");
> printf("name = %s\n", name);
> return 0;
> }
>
>
> $ cc -o prog prog.c
> $ ./prog
> Bob
>
> No warning.

Yes, there are ways to fool the compiler by converting a const char*
to a plain char* like you did with strstr().  But in my experience
there are plenty of cases where it will generate a useful warning.

> Point is, the consequences of "proper" use of const are so annoying
> even standard library functions would rather grossly abuse it than
> tolerate compiler warnings everywhere.

That's your opinion.

My differs: _I_ find it useful.  I don't have that many problems with
it.  If you don't like it, don't use it -- nobody is forcing you to
declare 'const' variables. 

-- 
Grant




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


Re: Question about math.pi is mutable

2015-11-09 Thread Antoon Pardon
Op 07-11-15 om 04:43 schreef Ben Finney:
> Bartc  writes:
>
>> Is there no way then in Python to declare:
>>
>>pi = 3.141519 # etc
>>
>> and make it impossible to override?
> No, and it would be a bad thing if that were something a library author
> could forbid.
>
> Python assumes the programmers using it are consenting adults. Doing
> harmful things is difficult but not forbidden.

I find that to be contradictory. Why should you make something difficult
if you are consenting adults? I also find it important that consenting
adults can choose in how far they can consent. This whole idea of python
assuming we are consenting adults and thus making it impossible to not
consent seems weird.

> Notably, the author of a library should not be forbidding the Pythonic
> ability to change name bindings as needed.

If the author of a library doesn't wish to consent to this I don't see
what is wrong with that.

> If you want to have a different value bound to the name ‘math.pi’, and
> you go ahead and explicitly ask to change that binding, the library
> author has no business forbidding that.

I disagree. Maybe the author is willing to freely give support but only
on the condition that the user used the library as it was largely intended.
I see no more reason to allow math.pi to be rebound to another value as
to allow True, False or None to be rebound.

So why should we allow the language designers to forbid the latter but
library authors not the former?

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


Re: Question about math.pi is mutable

2015-11-09 Thread BartC

On 09/11/2015 02:23, Steven D'Aprano wrote:

On Mon, 9 Nov 2015 09:35 am, BartC wrote:



import m
a=10
b=20
c=30
m.f()

The set of global names the compiler knows will be ("m","a","b","c").


Wrong. Up to the line "c=30", the set of names the compiler can infer are m,
a, b and c. Once the line "m.f()" executes, *all bets are off*. The
compiler can no longer infer *anything* about those names. In principle,
m.f may have reached into the globals and deleted *any* of the names,
including itself.



I don't believe code can remove these names (that would cause problems).


Of course names can be removed. There's even a built-in statement to do
so: "del".


I tried this code:

a=10
print (a)

del a
#print (a)

a=20
print (a)

That sort of confirms what you are saying: that names don't even come 
into existence until the first time they are encountered. They don't 
just contain None, or some other value which means the name itself 
exists, but it hasn't been initialised to anything. And that del removes 
the name completely from the set that are known.


That makes Python unlike any other language I've used.

On the other hand, if I put the above code into a function and then call 
the function, attempting to print a just after it's been deleted results in:


 UnboundLocalError: local variable 'a' referenced before assignment

So while local names can presumably be manipulated just like globals, 
that doesn't stop being implemented via a fixed slot in a table.



Therefore these names could be referred to by index.


Perhaps. But that adds significant complexity to the compiler,


It would mean that each name needs a flag indicating whether or not it 
has yet been brought into existence by an assignment in the program, or 
has been banished by the use of del.



and the
performance benefits *in practice* may not be as good as you imagine. After
all, there is usually far more to real programs than just getting and
setting names.


Any programs will consist largely of pushing names and constants (LOAD 
ops), performing some operations on them, and then sometimes popping 
values (STORE ops).


If the names represent complex data, then doing the work on the data 
will dominate the timings. But often it's the 'little' variables that 
hold indices, counts, flags etc that are being frequently loaded and stored.



def unopt():
 from math import *  # Defeats the local variable optimization.
 x = sin; x = cos; x = tan; x = exp; x = pi
 x = e; x = trunc; x = log; x = hypot; x = sqrt
 return

def opt():
 from math import sin, cos, tan, exp, pi, e, trunc, log, hypot, sqrt
 x = sin; x = cos; x = tan; x = exp; x = pi
 x = e; x = trunc; x = log; x = hypot; x = sqrt
 return



When I run this code, I get

16.5607659817 seconds for unopt, and 3.58955097198 seconds for opt. That's a
significant difference.


The optimisation means the code can use LOAD_FAST instead of LOAD_NAME. 
It still uses STORE_FAST instead of STORE_NAME, so perhaps the 
difference could be even more if the unoptimised version had to use 
STORE_NAME.


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


Re: Question about math.pi is mutable

2015-11-09 Thread Steven D'Aprano
On Tue, 10 Nov 2015 06:45 am, Ben Finney wrote:

> Steven D'Aprano  writes:
> 
>> The compiler doesn't need to decide in advance whether or not the
>> module attributes have been changed. It can decide that at runtime,
>> just before actually looking up the attribute. In pseudo-code:
>>
>> if attribute might have changed:
>> use the slow path just like today
>> else:
>> use the optimized fast path
> 
> As you have pointed out earlier, the “attribute might have changed”
> condition is set by *any* non-trivial code — notably, a function
> call, though that doesn't exhaust the ways of setting that condition.

Ben, I fear that you are not paying attention to me :-)

The compiler doesn't need to decide *in advance* whether the attribute might
have changed. It knows whether it has changed or not *at runtime*.

I'm not a compiler writer, but I pretend to be one on Usenet *wink* so don't
take this as gospel. Treat it as a simple-minded illustration of what sort
of thing a JIT compiler could do.

It's one thing to say that *in principle* any function might modify or
shadow builtins. That's true, because we don't know what's inside the
function. But the compiler knows, because it actually executes the code
inside the function and can see what happens when it does. It doesn't have
to predict in advance whether or not calling `func(x)` shadows the builtin
`len` function, *it can see for itself* whether it did or not.

At compile time, `func(x)` might do anything. But at runtime, we know
exactly what it did, because it just did it.

Imagine that the compiler keeps track of whether or not builtins has been
modified. Think of it as a simple "dirty" flag that says "yes, builtins is
still pristine" or "no, something may have shadowed or modified the
builtins". That's fairly straight-forward: builtins is a dict, and the
compiler can tell whether or not __setitem__ etc has been called on that
dict. Likewise, it can keep track of whether or not a global has been
created that shadows builtins: some of that can be done statically, at
compile-time, but most of it needs to be done dynamically, at runtime.

If the flag is set, the compiler knows that the optimization is unsafe and
it has to follow the standard name lookup, and you lose nothing: the
standard Python semantics are still followed. But if the flag is clear, the
compiler knows that nothing has shadowed or modified builtins, and a whole
class of optimizations are safe. It can replace a call to (say) len(x) with
a fast jump, avoiding an unnecessary name lookup in globals, and another
unnecessary name lookup in builtins. Or it might even inline the call to
len. Since *most* code doesn't play tricks with builtins, the overhead of
tracking these changes pays off *most* of the time -- and when it doesn't,
the penalty is very small.

Depending on how smart the compiler is, there are all sorts of things it can
do. The state of the art (not bleeding edge) for JIT compilers is pretty
smart these days. CPython is a simple-minded, dumb compiler, and that's the
way Guido likes it (its the reference implementation, not the fastest or
most memory efficient implementation). But PyPy can approach the speed of
statically optimized C, at least sometimes, and certainly can beat CPython
by an order of magnitude. Likewise Javascript's V8 compiler.

> So the remaining space of code that is safe for the proposed
> optimisation is trivially small. Why bother with such optimisations, if
> the only code that can benefit is *already* small and simple?

That is absolutely not correct.


-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-09 Thread Random832
Steven D'Aprano  writes:
> The compiler doesn't need to decide in advance whether or not the module
> attributes have been changed. It can decide that at runtime, just before
> actually looking up the attribute. In pseudo-code:
>
> if attribute might have changed:
> use the slow path just like today
> else:
> use the optimized fast path


if attribute might have changed:
   check if attribute really did change
   if it didn't:
  reset means of determining if it might have changed
  goto the optimized fast path
   else:
  use the slow path and/or maybe make a new fast path
else:
   use the optimized fast path

And what if your optimization depends on _two_ things that might change?
Do you create one really fast path and two sort of fast paths?

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


Re: Question about math.pi is mutable

2015-11-09 Thread BartC

On 09/11/2015 01:04, Ben Finney wrote:

Chris Angelico  writes:


Hmm, then I was misunderstanding what BartC was advocating. I didn't
think it would *fail* in the presence of dynamic attributes, but
merely *perform suboptimally* (and presumably worse than current
CPython).


There isn't a way for the compiler to *know*, in all cases, whether
module attributes will be updated during the lifetime of the program


In what way can an attribute be updated, other than deleting it altogether?

(Moving or renaming can be done in terms of creation and deletion. For 
the purposes of trying to avoid a lookup, we're not that interested in 
much else.)


--
Bart C.


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


Re: Question about math.pi is mutable

2015-11-09 Thread Laura Creighton
In a message of Tue, 10 Nov 2015 06:45:40 +1100, Ben Finney writes:
>So the remaining space of code that is safe for the proposed
>optimisation is trivially small. Why bother with such optimisations, if
>the only code that can benefit is *already* small and simple?

You have things backwards.
The reason that you want to optimise this is that it is small, simple, 
and slow_slow_slow_slow_slow.

It is the things that are complicated and large that usually aren't worth
optimising. You don't call them often enough for it to be worth it to
optimise them.  Your analysis and set up overhead will be more than
the speed gains you realise.  If you can find something that is small,
simple, and ubiquitous -- that's the place to look for performance
gains.

PyPy gets most of its speed by optimising loops.  Most loops in Python
run perfectly well without making use of any of the dynanism that is
potentially available -- "it's nice to have the ability to do something
that, as a matter of fact, I am not going to do right now".  But the
overhead for checking to see if I have made use of it is huge, which
is why 'set things up so that if it is never used, we can go pretty much
as fast as C' is a win.  After you have paid for your setup costs for
making the fast and the slow path, you get enough fast path activity
that you come out way ahead.

Laura




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


Re: Question about math.pi is mutable

2015-11-09 Thread Ben Finney
BartC  writes:

> On 09/11/2015 01:04, Ben Finney wrote:
> > There isn't a way for the compiler to *know*, in all cases, whether
> > module attributes will be updated during the lifetime of the program
>
> In what way can an attribute be updated, other than deleting it
> altogether?

* Bind a new name to a value.
* Re-bind an existing name to a different value.
* Delete an existing name.

Any of those can be done at run-time, in any module's namespace, by
arbitrary code somewhere in the program.

-- 
 \“Sane people have an appropriate perspective on the relative |
  `\ importance of foodstuffs and human beings. Crazy people can't |
_o__) tell the difference.” —Paul Z. Myers, 2010-04-18 |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-09 Thread Ben Finney
Steven D'Aprano  writes:

> The compiler doesn't need to decide in advance whether or not the
> module attributes have been changed. It can decide that at runtime,
> just before actually looking up the attribute. In pseudo-code:
>
> if attribute might have changed:
> use the slow path just like today
> else:
> use the optimized fast path

As you have pointed out earlier, the “attribute might have changed”
condition is set by *any* non-trivial code — notably, a function
call, though that doesn't exhaust the ways of setting that condition.

So the remaining space of code that is safe for the proposed
optimisation is trivially small. Why bother with such optimisations, if
the only code that can benefit is *already* small and simple?

I'm not asking you (Steven) to defend the proposal, I'm pointing out
that the “problem” being addressed is essentially the dynamism of
Python. The proposal is misguided.

-- 
 \ “Truth would quickly cease to become stranger than fiction, |
  `\ once we got as used to it.” —Henry L. Mencken |
_o__)  |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-09 Thread Ben Finney
Steven D'Aprano  writes:

> Ben, I fear that you are not paying attention to me :-)

Possibly, though I also think there's miscommunication in this thread.

You speak of “compile time” and “run time”. You also speak of what the
compiler can do, at run time.

I am a Bear of Little Brain, but: Isn't anything that the *compiler*
does, by definition done at *compile* time?

The run-time behaviour of the program is, of course, *affected* by what
the compiler has done in the past. But the compiler acts only at compile
time, and its compile-time behaviour can't be determined by what's
happening at run time.

If that's not true, I fear we're not talking about the same things.

> At compile time, `func(x)` might do anything. But at runtime, we know
> exactly what it did, because it just did it.

Sure. All my statements about compile-time optimisations are those that
can be applied at compile time (which I intend to be synonymous with
“when the compiler is doing its job”), and so can't be informed by what
happens at run time.

If the proposal is to make optimisations that must be informed by the
run-time state of the running program, we're surely talking about not
just the compiler any more. No?

-- 
 \  “Any sufficiently advanced bug is indistinguishable from a |
  `\  feature.” —Rich Kulawiec |
_o__)  |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-09 Thread Steven D'Aprano
On Mon, 9 Nov 2015 12:04 pm, Ben Finney wrote:

> There isn't a way for the compiler to *know*, in all cases, whether
> module attributes will be updated during the lifetime of the program
> (short of, as pointed out elsewhere, running the entire program under
> all possible conditions).
> 
> So the optimisation can't be applied by the compiler without risking
> breaking perfectly valid code.

It's not 1980 any more, compiler technology has come a long way since the
Dragon Book. In the words of Steve Yegge, describing the attitudes of C++
developers who insist that no other language (and especially dynamic
languages) can be sufficiently fast:

"And so, you know, their whole argument is based on these fallacious, you
know, sort of almost pseudo-religious... and often it's the case that
they're actually based on things that used to be true, but they're not
really true anymore"

http://steve-yegge.blogspot.com.au/2008/05/dynamic-languages-strike-back.html


The compiler doesn't need to decide in advance whether or not the module
attributes have been changed. It can decide that at runtime, just before
actually looking up the attribute. In pseudo-code:

if attribute might have changed:
use the slow path just like today
else:
use the optimized fast path


The PyPy FAQs suggest that PyPy is capable of fast, optimized attribute
access in this fashion, using a guard to ensure the fast path is taken only
when “this class attribute was not modified”. I'm not a compiler expert,
but I would expect that this sort of technology could be adapted to do the
same for module attributes.

http://doc.pypy.org/en/latest/faq.html

Such optimizations don't come for free: PyPy has taken a lot of development
effort, and some funding from the EU. And PyPy is more memory-hungry than
CPython. But that's just the same old trade-off that programmers have been
doing since time immemorial: you can save time, or you can save space, but
you can rarely save both together.

Other dynamic languages also have proven fast implementations: for decades,
Lisp (dynamic) and Fortran (static) were the two fastest languages around.
If Lisp has fallen behind, it is not because it is dynamic, but because
nobody is working on optimizing it. What was optimal in 1975 may not be
optimal on today's hardware.

Javascript and PHP also have extremely fast versions. Javascript's V8
compiler is actually two compilers in one, and it automatically swaps over
to the optimizing compiler when it is appropriate:

http://jayconrod.com/posts/54/a-tour-of-v8-crankshaft-the-optimizing-compiler

When Crankshaft's assumptions are violated, the compiler automatically swaps
back to running the unoptimized code.

Facebook took a different approach with HipHop, using a JIT language
translator that takes PHP and outputs compiled C++ code:

https://www.facebook.com/notes/facebook-engineering/hiphop-for-php-move-fast/280583813919

HipHop is perhaps not the best example, as it does give up some of the most
dynamic features of PHP, such as eval. The post above isn't clear whether
using such features is prohibited, or merely falls back on the slow,
regular PHP interpreter when you use them.




-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-09 Thread Ben Finney
Laura Creighton  writes:

> In a message of Tue, 10 Nov 2015 06:45:40 +1100, Ben Finney writes:
> >So the remaining space of code that is safe for the proposed
> >optimisation is trivially small. Why bother with such optimisations, if
> >the only code that can benefit is *already* small and simple?
>
> You have things backwards.
> The reason that you want to optimise this is that it is small, simple, 
> and slow_slow_slow_slow_slow.
>
> It is the things that are complicated and large that usually aren't
> worth optimising. You don't call them often enough for it to be worth
> it to optimise them.

I appreciate you making the the distinction explicit between a small and
simple *code unit* (e.g. an small, simple, often-called function),
versus a large and complex *code unit* (e.g. a large, complex,
infrequently-called class definition).

I'm pointing out an orthogonal issue: The only code to which the
proposed optimisation could apply is *module-level* (infrequently
called) code, which *has no complications* (i.e. not a code unit).

The simplicitly of the small section of code is not the issue; the
dynamism of the entire program is what negates the applicability of the
optimisation.

If the simple, predictable-by-the-compiler segment of code were actually
isolated in a simple unit, then yes, such optimisations might be
considered. But, as already discussed, the optimisation is not intended
to apply to such code units. So that is moot in this case.

Instead, we're talking about optimisations proposed *only* for
module-level code (i.e. not isolated); and what negates their
applicability is *any* dynamism (i.e. not simple), anywhere in the
program (i.e. not a code unit). The space of applicability for the
proposed optimisation shrinks to irrelevance, AFAICT.

-- 
 \“If the arguments in favor of atheism upset you, explain why |
  `\they’re wrong. If you can’t do that, that’s your problem.” |
_o__) —Amanda Marcotte, 2015-02-13 |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-09 Thread Ben Finney
Antoon Pardon  writes:

> Op 07-11-15 om 04:43 schreef Ben Finney:
> > Python assumes the programmers using it are consenting adults. Doing
> > harmful things is difficult but not forbidden.
>
> I find that to be contradictory. Why should you make something difficult
> if you are consenting adults?

It's no more contradictory than the fact Python makes it difficult for
consenting adults to exchange hard-to-follow code indentation. The
principle that There Should Be (Preferably Only) One Obvious Way To Do
It directly implies that other ways should be difficult. That's not a
contradiction with treating Python programmers as consenting adults.

> This whole idea of python assuming we are consenting adults and thus
> making it impossible to not consent seems weird.

You misunderstand the implication: I'm saying that because Python
assumes we are consenting adults, that such actions remain possible.

> > Notably, the author of a library should not be forbidding the Pythonic
> > ability to change name bindings as needed.
>
> If the author of a library doesn't wish to consent to this I don't see
> what is wrong with that.

Who is doing what to whom? The user of the library isn't doing anything
to the library author, so what is it the library author would consent
to? Instead, you seem to be trying to assert a *power* of the library
author to restrict the library user. Such a power is not granted by
Python.

Instead, the library author is obliged to treat the library user as an
adult who consents to the freedoms inherent to Python's design, and to
not restrict their use of the library needlessly.

-- 
 \ “Facts are stubborn things; and whatever may be our wishes, our |
  `\   inclinations, or the dictates of our passion, they cannot alter |
_o__)the state of facts and evidence.” —John Adams, 1770-12-04 |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-09 Thread Gregory Ewing

Ben Finney wrote:


We
should certainly not have a compiler that makes needless difference to
code behaviour under test conditions versus non-test conditions.


Indeed. Volkswagen tried a version of that recently,
and it didn't end well...

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


Re: Re: Question about math.pi is mutable

2015-11-09 Thread wa...@travelsky.com
Hi, Chris Angelico ,

Thank you for your help !  :-)
 
From: Chris Angelico
Date: 2015-11-06 18:30
To: wa...@travelsky.com
CC: python-list
Subject: Re: Question about math.pi is mutable
On Fri, Nov 6, 2015 at 1:33 PM, wa...@travelsky.com <wa...@travelsky.com> wrote:
> Hello, python-list guys:
>
> I am a newbie of python from Beijing. China.
> I have a question about "math.pi".
> As you can see in the attachment, why i can modify "math.pi"?
> (in "mathmodule.c" "pi" is a "static const double")
>
> Thank you in advance!
>
> Best Wishes!
 
Simply because, in Python, virtually everything can be changed. You're
welcome to go in and say "math.pi = 3" if you like... and then you
accept the consequences of that.
 
There are times when you want to change these sorts of 'constants'.
For example, math.pi is a float; but if you're working with
decimal.Decimal everywhere, it might be useful to replace it with a
corresponding Decimal value:
 
math.pi = decimal.Decimal("3.14159265358979323")
 
And that's perfectly legal.
 
ChrisA
 
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Question about math.pi is mutable

2015-11-08 Thread Steven D'Aprano
On Sun, 8 Nov 2015 08:44 pm, Marko Rauhamaa wrote:

> Steven D'Aprano :
> 
>> On Sun, 8 Nov 2015 01:23 am, Marko Rauhamaa wrote:
>>> Correct. That's not Python's fault, however. Python should not try to
>>> placate the performance computing people. (Alas, it is now trying to
>>> do just that with the introduction of static typing annotation.)
>>
>> That is factually incorrect.
>>
>> The motive behind the introduction of typing annotations is not "speed",
>> but "correctness".
> 
> Oh, then I'm even more disappointed with type annotation.


/me does a double-take


Wait a minute, you've just spent a bunch of paragraphs explaining that
Python is plenty fast enough (for you), that you don't need it to be
faster. Okay. Now you're saying that you're *even more* disappointed that
type annotations will be used to make code *more correct* and *less buggy*.

So... you have no need for Python to be fast, and even less need for Python
code to be correct...

Or perhaps you mean that you don't need help writing correct code, because
your code is perfect...

It is moments like this I wonder if you are trolling.


-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 11:50, Marko Rauhamaa wrote:

BartC :


On 08/11/2015 11:02, Marko Rauhamaa wrote:

That elegant dynamism comes at a cost: method lookup is not a constant
memory offset. Rather, it is a dictionary lookup.


I've never understood why this seems to be necessary in Python. Why do
names have to be looked up? (I'm assuming this is searching by name in
some sort of table.)

When a module is compiled, while the compiler can't see the
definitions inside the imported modules, it /will/ know all the names
that appear in this module, so it can organise them into fixed tables.
Then the names can be referred to by index. (I think LOAD_FAST does
this.)


Modules are not the issue. Barely any functions are invoked from the
modules. Rather, almost all invocations are object methods. (Of course,
modules are objects, too.) Methods belong to objects that can be
literally anything.

Consider, for example,

 shutil.copyfileobj(src, dst[, length])

The shutil module has absolutely no idea what kind of objects src and
dst are. An example program:


import shutil

class Source:
 def __init__(self):
 self.remaining = "hello world"

 def read(self, count):
 if count <= 0:
 return ""
 chunk, self.remaining = self.remaining[:count], self.remaining[count:]
 return chunk

class Dest:
 def write(self, stuff):
 print("<{}>".format(stuff))

shutil.copyfileobj(Source(), Dest())



OK, so here, it is necessary to resolve "copyfileobj" by seeing if 
"shutil" is something that contains a name "copyfileobj" that happens to 
be a method.


Is this the lookup you're talking about, and is it done using the actual 
string "copyfileobj"? If so, does it need to be done every single time 
this line is executed? It would extraordinarily inefficient if that was 
the case.


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


Re: Question about math.pi is mutable

2015-11-08 Thread Marko Rauhamaa
Steven D'Aprano :

> On Sun, 8 Nov 2015 01:23 am, Marko Rauhamaa wrote:
>> Correct. That's not Python's fault, however. Python should not try to
>> placate the performance computing people. (Alas, it is now trying to
>> do just that with the introduction of static typing annotation.)
>
> That is factually incorrect.
>
> The motive behind the introduction of typing annotations is not "speed",
> but "correctness".

Oh, then I'm even more disappointed with type annotation.


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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 12:43, Marko Rauhamaa wrote:

BartC :


On 08/11/2015 11:50, Marko Rauhamaa wrote:


import shutil

class Source:
  def __init__(self):
  self.remaining = "hello world"

  def read(self, count):
  if count <= 0:
  return ""
  chunk, self.remaining = self.remaining[:count], self.remaining[count:]
  return chunk

class Dest:
  def write(self, stuff):
  print("<{}>".format(stuff))

shutil.copyfileobj(Source(), Dest())



OK, so here, it is necessary to resolve "copyfileobj" by seeing if
"shutil" is something that contains a name "copyfileobj" that happens
to be a method.

Is this the lookup you're talking about, and is it done using the
actual string "copyfileobj"? If so, does it need to be done every
single time this line is executed? It would extraordinarily
inefficient if that was the case.


No, what I'm talking about is that copyfileobj calls src.read() and
dst.write() without having any idea what kinds of objects src and dst
are. Thus, it will be difficult for a performance optimizer to get rid
of the dictionary lookups.


Sorry, you'll have to assume I'm very stupid.

What exactly is being looked up, and in what?

From what I can understand in your example:

* You are calling shutil.copyfileobj with two arguments, which happen to 
be instances of classes Source and Dest.


* Let's say these are known as src and dst inside .copyfileobj.

* .copyfileobj then calls methods src.read() dst.write().

* Each of these method calls has the form A.B() which seems to me to be 
little different from shutil.copyfileobj().


So to get back to what I was saying, does this lookup involving 
searching for method B in object A, and if so, does it actually do a 
search by name?


(Someone mentioned a precalculated hash, of "A", or of "src" or "dst", 
use used, but still, it's looking something up in a table, and a hash 
table lookup I believe still requires an string compare to check if 
you've got the right entry.)


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


Re: Question about math.pi is mutable

2015-11-08 Thread Marko Rauhamaa
Paul Rubin :

> Marko Rauhamaa  writes:
>> Point is, the consequences of "proper" use of const are so annoying even
>> standard library functions would rather grossly abuse it than tolerate
>> compiler warnings everywhere.
>
> I'm not sure what the C standard says about that example, but C++ is
> much stricter about those conversions, [...]

C++ gets const even more wrong than C, and const is the least of C++'s
problems.


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


Re: Question about math.pi is mutable

2015-11-08 Thread Marko Rauhamaa
Steven D'Aprano :

> So... you have no need for Python to be fast, and even less need for
> Python code to be correct...

Correct. If I didn't think so, I'd still be using Java instead of
Python.

> Or perhaps you mean that you don't need help writing correct code,
> because your code is perfect...

Python's noise-free syntax does more for code quality than compile-time
type checking.


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


Re: Question about math.pi is mutable

2015-11-08 Thread Marko Rauhamaa
BartC :

> On 08/11/2015 11:50, Marko Rauhamaa wrote:
>> 
>> import shutil
>>
>> class Source:
>>  def __init__(self):
>>  self.remaining = "hello world"
>>
>>  def read(self, count):
>>  if count <= 0:
>>  return ""
>>  chunk, self.remaining = self.remaining[:count], 
>> self.remaining[count:]
>>  return chunk
>>
>> class Dest:
>>  def write(self, stuff):
>>  print("<{}>".format(stuff))
>>
>> shutil.copyfileobj(Source(), Dest())
>> 
>
> OK, so here, it is necessary to resolve "copyfileobj" by seeing if
> "shutil" is something that contains a name "copyfileobj" that happens
> to be a method.
>
> Is this the lookup you're talking about, and is it done using the
> actual string "copyfileobj"? If so, does it need to be done every
> single time this line is executed? It would extraordinarily
> inefficient if that was the case.

No, what I'm talking about is that copyfileobj calls src.read() and
dst.write() without having any idea what kinds of objects src and dst
are. Thus, it will be difficult for a performance optimizer to get rid
of the dictionary lookups.


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


Re: Question about math.pi is mutable

2015-11-08 Thread Chris Angelico
On Sun, Nov 8, 2015 at 10:19 PM, BartC  wrote:
> I've never understood why this seems to be necessary in Python. Why do names
> have to be looked up? (I'm assuming this is searching by name in some sort
> of table.)

Yes, if by "searching" you include hash-table lookup. A CPython
dictionary is a *highly* optimized data structure, specifically
because it's used virtually everywhere (I understand Lua's "table"
type has similar optimizations for the same reason). In the common
case, where your names come from literal text in the module, the
strings used for the lookup will be interned constants, and their
hashes will have been precalculated and stored, so the lookup is
pretty easy. So it's a constant-time operation, and while that
constant may be larger than a simple offset-and-fetch, it's still
pretty fast in the overall scheme of things.

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


Re: Question about math.pi is mutable

2015-11-08 Thread Michael Torrie
On 11/08/2015 04:19 AM, BartC wrote:

>> That elegant dynamism comes at a cost: method lookup is not a constant
>> memory offset. Rather, it is a dictionary lookup.
> 
> I've never understood why this seems to be necessary in Python. Why do 
> names have to be looked up? (I'm assuming this is searching by name in 
> some sort of table.)
> 
> When a module is compiled, while the compiler can't see the definitions 
> inside the imported modules, it /will/ know all the names that appear in 
> this module, so it can organise them into fixed tables. Then the names 
> can be referred to by index. (I think LOAD_FAST does this.)
> 
> Or is eval() the culprit here by making most optimisations impossible?

Perhaps I'm misunderstanding what you're saying, here, but the reason a
lookup has to be performed is because python variables are not like C
variables. They aren't boxes per se.  They are names bound to objects.
so doing something like

a += 1

Actually assigns the name "a" to an entirely new object than the one it
had before, which, from the interpreters point of view, is in an
entirely different memory location.

Whereas in C, a variable is a box that's always at the same location, so
the name is simply not important, and at runtime variables have no
names.  Python is not like this.  names are important at runtime.  There
may be certain circumstances where the Python compiler could optimize
certain types of variable access (say if the variable was bound to
integers only) into C-style variables under the hood. But I don't think
the benefit would be that great.



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


Re: Question about math.pi is mutable

2015-11-08 Thread Steven D'Aprano
On Sun, 8 Nov 2015 09:40 pm, Bartc wrote:

> On 08/11/2015 02:59, Steven D'Aprano wrote:
>> On Sun, 8 Nov 2015 02:01 am, Bartc wrote:
>>
>>> Neither have the simplicity of concept of Pascal's 'const', which is
>>> just a named value. Not a variable that won't change once initialised,
>>> not a parameter that won't be changed nor any addressable location.)
>>
>> Unfortunately the concept of "named value" doesn't match well with
>> Python's design. That implies a separate compilation step which doesn't
>> fit well with Python's runtime semantics. Very little happens at
>> compile-time in Python that *must* happen at compile-time.
>>
>> I'm also not sure what difference you think there is between "named
>> value" and "variable that won't change once initialised".
> 
> This is what I mean about people not understanding it!

I'm pretty sure I understand what *I* mean by constant, and what Pascal
means by it, and why the Pascal meaning doesn't quite match what Python can
do. I'm not sure I understand what *you* mean, or why you think a "variable
that won't change" isn't good enough.


> In NASM terms, a named constant is like:
> 
>  daysinweek   equ   7   ; definition
> 
>  mov rax, daysinweek; using it, as immediate value
>  mov rbx, daysinweek*2  ; an a 'compile-term' expression
> ;   mov daysinweek,8   ; can't be done! Illegal syntax

In pseudo-Python, we have:

const daysinweek = 7  # let's just pretend it exists
x = daysinweek + 1  # this is fine
daysinweek = 8  # an error

Apart from the difference between compile-time and run-time, why would this
not be satisfactory?

Oh, and just to satisfy Ben, the determined monkey-patcher can write:

globals()['daysinweek'] = 8

if they really want to defeat the compiler. The idea is to avoid
*accidental* bindings.



> While a 'const' variable, C style, might be:
[...]

Why does your C code look like assembler?


> So in native code, a named value is not much different to a literal such
> as 7, or 3.14159. (But unlike C's #define, the name is a proper symbol
> with normal scope rules, and a type).
> 
> The distinction at the machine level can be blurred with some
> instructions sets where there might not be an immediate data option for
> some data widths or types. Also where named constants are applied to
> things such as strings, which necessarily use storage.

I am not interested in the limitations of low-level machine languages. They
have very little to say about what Python can or should do.


> In the language however, you will not be able to use the named constant
> as an lvalue, and you will usually be able to use it for compile-time
> constant folding and for dimensioning fixed-bound arrays and such.)

We're talking about Python, and how the concept of "const" might apply to a
Python-like language. Compile-time constant folding is not part of it,
because the constant itself might not exist at compile-time:

const START = time.time()

Fixed-bound arrays are irrelevant (neither lists nor arrays are
fixed-bounds; tuples are, but they are constructed at runtime, not compile
time). 


>> Python has a convention for "constants" -- all UPPERCASE names. The fact
>> that the convention exists is enough to prove that the concept
>> of "constant" is a useful one. The difference between Python's
>> pseudo-constants and (say) Pascal's actual constants is that in Python,
>> the burden of ensuring that neither you, nor any of the libraries you
>> call, modifies the "constant" falls on you, the user, whereas in Pascal
>> the compiler or interpreter performs that checking for you.
> 
> With a real named constant the check can always be done at compile-time.
> Unless you have a pure interpreter or some more elaborate way of
> executing source code.

Python has such a "more elaborate way" of executing source code:


exec("""
if condition:
import time
const START = time.time()
x = START + 1
""")




-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 11:30, Steven D'Aprano wrote:

On Sun, 8 Nov 2015 09:40 pm, Bartc wrote:



This is what I mean about people not understanding it!


I'm pretty sure I understand what *I* mean by constant, and what Pascal
means by it, and why the Pascal meaning doesn't quite match what Python can
do. I'm not sure I understand what *you* mean, or why you think a "variable
that won't change" isn't good enough.


I showed you what I mean. A named constant is a just a value - with a 
label. That value doesn't need to be stored in a 'box' anywhere, in 
exactly the same manner as values that can be written to (and therefore 
at risk of being overwritten).


But let me turn it around: why is it so important to use variables for 
this purpose?



In NASM terms, a named constant is like:

  daysinweek   equ   7   ; definition

  mov rax, daysinweek; using it, as immediate value
  mov rbx, daysinweek*2  ; an a 'compile-term' expression
;   mov daysinweek,8   ; can't be done! Illegal syntax


In pseudo-Python, we have:

const daysinweek = 7  # let's just pretend it exists
x = daysinweek + 1  # this is fine
daysinweek = 8  # an error

Apart from the difference between compile-time and run-time, why would this
not be satisfactory?


If that's all that's possible, that it will have to do. And might solve 
the OP's problem.


But for a true named constant, there is no actual assignment. It really 
is not necessary. 'daysinweek' is just a synonym for '7'.





While a 'const' variable, C style, might be:

[...]

Why does your C code look like assembler?


I mean the 'const' is C style. The assembly code is to highlight the 
difference between what C calls a const, and what I call a named constant.



I am not interested in the limitations of low-level machine languages. They
have very little to say about what Python can or should do.


OK, let's take a higher level one:

 const a = 2
 var   b = 3

 c = a+b

which might generate a byte-code like this:

  push_ci   2
  push_m[b]
  add
  pop_m [c]

Now apply this to Python byte-code. Can you not see the advantage of not 
having to deal with variable names, reference counts, garbage collection 
and all that?


I don't know what you had in mind for implementing the pretend 'const' 
in your Python example above. But if it takes the form of an extra 
runtime attribute, then all variable accesses will be slowed then if it 
is has to be checked for every assignment, and 'const' names won't be 
any faster.



In the language however, you will not be able to use the named constant
as an lvalue, and you will usually be able to use it for compile-time
constant folding and for dimensioning fixed-bound arrays and such.)


We're talking about Python, and how the concept of "const" might apply to a
Python-like language. Compile-time constant folding is not part of it,
because the constant itself might not exist at compile-time:

const START = time.time()


You're thinking in C terms again. The C 'const' really means 'read-only' 
and applies to ordinary variables. It has nothing to do with my named 
constants which are always known at compile-time


(That's if the definitions are visible. If not, then they will be known 
at the time the module they're in is compiled. Linking these is one of 
the problems in a Python implementation.)



Fixed-bound arrays are irrelevant (neither lists nor arrays are
fixed-bounds; tuples are, but they are constructed at runtime, not compile
time).


Think of a possible 'switch' statement then, and the values for its case 
labels.



Python has such a "more elaborate way" of executing source code:


exec("""
if condition:
 import time
 const START = time.time()
 x = START + 1
""")


(1) That is not a const but a variable with a read-only attribute. The 
expression after the "=" should itself be a constant expression or a 
literal value. (No reason why Python shouldn't have such an attribute, 
but that's different from what I'm talking about.)


(2) I assume that the contents of the string passed to exec() are first 
compiled to byte-code. Then that's the same as a normal compile, with 
the same problems of visibility and imparting its constant definitions 
to code that is compiled separately. (If the use 'exec' is more subtle, 
then we might as well give up!)


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


Re: Question about math.pi is mutable

2015-11-08 Thread Marko Rauhamaa
BartC :

>>> On 08/11/2015 11:50, Marko Rauhamaa wrote:
 
 import shutil

 class Source:
   def __init__(self):
   self.remaining = "hello world"

   def read(self, count):
   if count <= 0:
   return ""
   chunk, self.remaining = self.remaining[:count], 
 self.remaining[count:]
   return chunk

 class Dest:
   def write(self, stuff):
   print("<{}>".format(stuff))

 shutil.copyfileobj(Source(), Dest())
 
>
> What exactly is being looked up, and in what?
>
> [...]
>
> So to get back to what I was saying, does this lookup involving
> searching for method B in object A, and if so, does it actually do a
> search by name?

Yes, finding Source.read and Dest.write involves hash table lookups. In
fact, it's even a bit more involved: each method fetch consists of *two*
hash table lookups. First you have to check if the object has a match in
its individual lookup table and next if there is a match in the class's
lookup table.


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


Re: Question about math.pi is mutable

2015-11-08 Thread Chris Angelico
On Mon, Nov 9, 2015 at 12:42 AM, BartC  wrote:
> Sorry, you'll have to assume I'm very stupid.
>
> What exactly is being looked up, and in what?
>
> From what I can understand in your example:
>
> * You are calling shutil.copyfileobj with two arguments, which happen to be
> instances of classes Source and Dest.
>
> * Let's say these are known as src and dst inside .copyfileobj.
>
> * .copyfileobj then calls methods src.read() dst.write().
>
> * Each of these method calls has the form A.B() which seems to me to be
> little different from shutil.copyfileobj().
>
> So to get back to what I was saying, does this lookup involving searching
> for method B in object A, and if so, does it actually do a search by name?
>
> (Someone mentioned a precalculated hash, of "A", or of "src" or "dst", use
> used, but still, it's looking something up in a table, and a hash table
> lookup I believe still requires an string compare to check if you've got the
> right entry.)

The lookups I'm talking about happen pretty much anywhere. Firstly,
this function:

def f():
shutil.copyfileobj(src, dst)

looks up the global name 'shutil' (that's one dict lookup - module
globals are a dictionary), then performs an attribute lookup on the
resulting object with the name 'copyfileobj', then looks up the two
global names 'src' and 'dst'.

In fact[1], those strings can be found in f.__code__.co_names, and the
byte-code identifies them by their indices in that tuple. These are
str objects (note that this means they can be any legal Unicode
string; "шутил.цопыфилеобй(срц, дст)" is just as valid), and their
hashes will normally be precomputed to save time. Now, things are a
bit different with function-locals; the compiler always knows which
names they are, and it can compile things differently. Compare:

def f(src):
shutil.copyfileobj(src, dst)

Instead of looking up a global name 'src', this now looks up a local
name. They're identified by slot positions, so the compiler simply
knows that "src" is in slot #0, and instead of looking anything up,
simply says "load the thing in slot #0". There can also be other
levels of indirection, such as __getattr__ and __getattribute__, which
affect how stuff gets looked up. But otherwise, name lookups generally
involve poking a dict with a string and taking what comes back
(possibly replacing KeyError with NameError or AttributeError as the
case may be).

ChrisA

[1] Assuming we're using CPython, or something which uses the same
byte-code; this is NOT a language requirement - none of this is.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Question about math.pi is mutable

2015-11-08 Thread Marko Rauhamaa
Bartc :

> (In the case of Python, the main obstacle is that a constant name from
> inside an imported module is not visible when this module is compiled
> to byte-code. So it has to assume it can be anything.)

Which it can.

Optimizing for naive floating-point constants could be done but has
barely any significance in most Python code. Numeric computations are
carried out in separate native plugins.

Most Python code deals with encapsulated objects whose innards are
hidden and whose only semantics are defined by the access methods. New
implementations or derived objects can be plugged in transparently.

A case in point are the so-called file-like objects. They are a simple,
elegant concept. I can come up with new file-like objects without any
common pedigree with some predefined classes and incorporate them with a
lot of utility classes.

That elegant dynamism comes at a cost: method lookup is not a constant
memory offset. Rather, it is a dictionary lookup.


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


Re: Question about math.pi is mutable

2015-11-08 Thread Bartc

On 08/11/2015 02:59, Steven D'Aprano wrote:

On Sun, 8 Nov 2015 02:01 am, Bartc wrote:


Neither have the simplicity of concept of Pascal's 'const', which is
just a named value. Not a variable that won't change once initialised,
not a parameter that won't be changed nor any addressable location.)


Unfortunately the concept of "named value" doesn't match well with Python's
design. That implies a separate compilation step which doesn't fit well
with Python's runtime semantics. Very little happens at compile-time in
Python that *must* happen at compile-time.

I'm also not sure what difference you think there is between "named value"
and "variable that won't change once initialised".


This is what I mean about people not understanding it!

In NASM terms, a named constant is like:

daysinweek   equ   7   ; definition

mov rax, daysinweek; using it, as immediate value
mov rbx, daysinweek*2  ; an a 'compile-term' expression
;   mov daysinweek,8   ; can't be done! Illegal syntax

While a 'const' variable, C style, might be:

segment .rodata
monthsinyear:  ; definition
dd 12

mov rax,[monthsinyear] ; using it, as memory access
;   mov rbx,[monthsinyear*10]  ; can't be done!
mov [monthsinyear],6   ; can be done, but might give memory
   ; access errors if actually stored in
   ; protected memory. Usually in C,
   ; it isn't

So in native code, a named value is not much different to a literal such 
as 7, or 3.14159. (But unlike C's #define, the name is a proper symbol 
with normal scope rules, and a type).


The distinction at the machine level can be blurred with some 
instructions sets where there might not be an immediate data option for 
some data widths or types. Also where named constants are applied to 
things such as strings, which necessarily use storage.


In the language however, you will not be able to use the named constant 
as an lvalue, and you will usually be able to use it for compile-time 
constant folding and for dimensioning fixed-bound arrays and such.)



Python has a convention for "constants" -- all UPPERCASE names. The fact
that the convention exists is enough to prove that the concept
of "constant" is a useful one. The difference between Python's
pseudo-constants and (say) Pascal's actual constants is that in Python, the
burden of ensuring that neither you, nor any of the libraries you call,
modifies the "constant" falls on you, the user, whereas in Pascal the
compiler or interpreter performs that checking for you.


With a real named constant the check can always be done at compile-time. 
Unless you have a pure interpreter or some more elaborate way of 
executing source code.


(In the case of Python, the main obstacle is that a constant name from 
inside an imported module is not visible when this module is compiled to 
byte-code. So it has to assume it can be anything.)


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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 03:50, Steven D'Aprano wrote:

On Sun, 8 Nov 2015 01:23 am, Marko Rauhamaa wrote:



Your point of view is really down-to-earth. It's slightly analogous to
protesting against Unicode because you only ever need ASCII.


I don't think so, but in any case, Bart is *way* oversimplifying the
potential optimizations available. Function inlining depends on the
function being small enough that inlining it does more good than harm, but
it doesn't require that f never changes.


I didn't really have function in-lining in mind (although once you are 
sure a specific function will always be called, that is a possibility 
for the compiler).


There are plenty of optimisations available if you know you are calling 
a function, and the compiler can 'see' the source code:


* You don't need to check that 'f' in 'f(a,b,c)' is a function; it will be.

* You will know whether the number of arguments provided is correct or 
not, and make adjustments at compile-time if not


* Where keyword parameters are used, this can also all be sorted out at 
compile-time, rather than at runtime


* (And does Python still need to do a lookup for the name 'f'? I don't 
know; the CPython sources are hard to follow. But in my interpreters, 
this is never necessary at runtime.)


However, most functions will not be visible to the compiler because they 
are in imported modules. A certain amount of work can be done when a 
module is loaded, but this now starts to get complicated.



Even such simple things as constant folding are slightly controversial! If
you go back to older versions of Python, code like this:

 x = 1 + 1

actually performed the addition at runtime, instead of being compiled to:

 x = 2

Believe it or not, even something as simple as that remains controversial,


Actually, it's not so simple! If floating point expressions are 
involved, the results can be different between compiler and runtime, if 
the compilation is done on a separate machine. But this is only a 
problem is byte-code is distributed rather than sources.


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


Re: Question about math.pi is mutable

2015-11-08 Thread Marko Rauhamaa
BartC :

> On 08/11/2015 11:02, Marko Rauhamaa wrote:
>> That elegant dynamism comes at a cost: method lookup is not a constant
>> memory offset. Rather, it is a dictionary lookup.
>
> I've never understood why this seems to be necessary in Python. Why do
> names have to be looked up? (I'm assuming this is searching by name in
> some sort of table.)
>
> When a module is compiled, while the compiler can't see the
> definitions inside the imported modules, it /will/ know all the names
> that appear in this module, so it can organise them into fixed tables.
> Then the names can be referred to by index. (I think LOAD_FAST does
> this.)

Modules are not the issue. Barely any functions are invoked from the
modules. Rather, almost all invocations are object methods. (Of course,
modules are objects, too.) Methods belong to objects that can be
literally anything.

Consider, for example,

shutil.copyfileobj(src, dst[, length])

The shutil module has absolutely no idea what kind of objects src and
dst are. An example program:


import shutil

class Source:
def __init__(self):
self.remaining = "hello world"

def read(self, count):
if count <= 0:
return ""
chunk, self.remaining = self.remaining[:count], self.remaining[count:]
return chunk

class Dest:
def write(self, stuff):
print("<{}>".format(stuff))

shutil.copyfileobj(Source(), Dest())



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


Re: Question about math.pi is mutable

2015-11-08 Thread Chris Angelico
On Mon, Nov 9, 2015 at 4:54 AM, BartC  wrote:
> That would be true for locals as well. But as far as I can tell from the
> CPython source code, byte-codes uses an index to represent a local, which
> represents an entry into a linear table.
>
> I can't quite see why that can't be done for global names and for attributes
> too (ie. the names that follow a ".").

At compilation time, the set of local names is locked in permanently.
That's not true of any other namespace (except nonlocals, which are
still locals, just not yours). Attributes and global names (which are
attributes of the current module) can be added and removed
dynamically, so they can't be assigned to slots; attributes can even
be simulated via __getattr__ and __getattribute__.

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


Re: Question about math.pi is mutable

2015-11-08 Thread Ben Finney
BartC  writes:

> I've never understood why this seems to be necessary in Python. Why do
> names have to be looked up? (I'm assuming this is searching by name in
> some sort of table.)

No, it is literally looking the name up as a key in a namespace
dictionary — which is just like any other Python dictionary, but
nominated internally for use as the namespace dictionary.

The distinction is important, because like any other dictionary it can
change at run-time and the bindings between name and value can change,
can be added, and can be removed.

> When a module is compiled, while the compiler can't see the
> definitions inside the imported modules, it /will/ know all the names
> that appear in this module, so it can organise them into fixed tables.

Not true. The namespace can change dynamically, which is another way of
what people have been trying to tell you all through this thread.

The compiler *cannot* know what the names will be at every single point
they'll be looked un in the namespace dictionary. This dynamism of each
namespace is a Python feature.

-- 
 \  “It is … incumbent upon us to recognize that it is |
  `\inappropriate for religion to play any role in issues of state |
_o__)[of] a modern democracy.” —Lawrence M. Krauss, 2012-05-28 |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 21:00, Ben Finney wrote:

BartC  writes:


I've never understood why this seems to be necessary in Python. Why do
names have to be looked up? (I'm assuming this is searching by name in
some sort of table.)


No, it is literally looking the name up as a key in a namespace
dictionary — which is just like any other Python dictionary, but
nominated internally for use as the namespace dictionary.

The distinction is important, because like any other dictionary it can
change at run-time and the bindings between name and value can change,
can be added, and can be removed.


That part is not a problem.


When a module is compiled, while the compiler can't see the
definitions inside the imported modules, it /will/ know all the names
that appear in this module, so it can organise them into fixed tables.


Not true. The namespace can change dynamically, which is another way of
what people have been trying to tell you all through this thread.

The compiler *cannot* know what the names will be at every single point
they'll be looked un in the namespace dictionary. This dynamism of each
namespace is a Python feature.


Suppose this is the python program:

import m
a=10
b=20
c=30
m.f()

The set of global names the compiler knows will be ("m","a","b","c").

I don't believe code can remove these names (that would cause problems). 
You say the set of global names can be added to - after this lot, but I 
can't see that the first four are going to change.


Therefore these names could be referred to by index.

Attributes are harder because they are more of a free-for-all, but 
suppose you do have m.f().


"m" is easy, it's entry 0 in the global table for this module, so no 
lookup-by-name is needed. You examine it, and it's a module.


It's now necessary to find f within the global table for m. This is 
where it gets tricky if you want to avoid a lookup. And I expect you 
will say that any code can randomly add names within the global table of m.


But bear with me. Suppose the interpreter were to maintain a table for 
each static (not runtime) attribute encountered in the source code. The 
compile can produce empty tables for the attributes it's seen. In this 
case the table for "f" would be empty: (). The compiler will also 
produce a list of such tables for all attributes.


Here there is only one, and the "f" table will have index 0, which is 
what can be used within the byte-code.


The hard part would be in building and maintaining that table. When 
module m is loaded, let's say it defines function "f". Now that can be 
used to create the first entry in the attribute table for "f": ($m, 
$m.f). Here, $m is some internal reference to m, and $m.f is some 
internal reference to m.f().


Now back to resolving m.f(): we know the "m" part is module $m. For "f", 
it looks through its attribute table (remember it's index 0, so instant 
access), and there is only one entry. We're lucky as that entry's owner 
matches the "m." part of this access. So we know it refers to $m.f. No 
lookups by name needed in this case.


However not all random attributes will be neatly defined somewhere as 
functions or classes that will be listed in these little tables. So 
sometimes, an actual lookup will still be needed.


--
Bart C
--
https://mail.python.org/mailman/listinfo/python-list


Re: Question about math.pi is mutable

2015-11-08 Thread Ian Kelly
On Nov 8, 2015 12:01 PM, "BartC"  wrote:
>
> But then, you say that additional attributes, potentially millions of
different ones, can be invented at runtime. Although I don't see how it can
remove names that are part of the source code: if "A.B" is in the file,
then surely "A" and "B" always have to be present in some table or other.

Gratuitous example:

def factory(name):
class inner:
# stuff
inner.__name__ = name
return inner

One = factory('One')
Two = factory('Two')

# factory is no longer needed, so remove it from globals.
del factory
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 15:59, Michael Torrie wrote:

On 11/08/2015 04:19 AM, BartC wrote:


That elegant dynamism comes at a cost: method lookup is not a constant
memory offset. Rather, it is a dictionary lookup.


I've never understood why this seems to be necessary in Python. Why do
names have to be looked up? (I'm assuming this is searching by name in
some sort of table.)

When a module is compiled, while the compiler can't see the definitions
inside the imported modules, it /will/ know all the names that appear in
this module, so it can organise them into fixed tables. Then the names
can be referred to by index. (I think LOAD_FAST does this.)

Or is eval() the culprit here by making most optimisations impossible?


Perhaps I'm misunderstanding what you're saying, here, but the reason a
lookup has to be performed is because python variables are not like C
variables. They aren't boxes per se.  They are names bound to objects.
so doing something like

a += 1

Actually assigns the name "a" to an entirely new object than the one it
had before, which, from the interpreters point of view, is in an
entirely different memory location.


That would be true for locals as well. But as far as I can tell from the 
CPython source code, byte-codes uses an index to represent a local, 
which represents an entry into a linear table.


I can't quite see why that can't be done for global names and for 
attributes too (ie. the names that follow a ".").


Attributes are a more difficult because there can be multiple instances 
of each name, and Python won't know which one is meant, so it needs to 
be resolved at each use.


So in the case of A.B(), Python apparently looks up "B" in the names 
associated with object A (and also, someone said, with the class of 
which A is an instance if the first lookup fails).


I had in mind a different approach, where a table exists for each 
different attribute, which contains an entry for each owner class. 
Usually this table will be small, or will have just one entry, so is 
quick to search.


However, another feature of Python makes that impractical: the ability 
of any instance of a class to have arbitrary sets of attributes. There 
could be millions of such instances, all named "B".


Now, if methods could only be part of a class definition, then with 
A.B() rather than A.B, there will be a limited number of classes that 
could have a method "B", so the short table idea could work.


But then, A.B could be assigned the name of a function, which is then 
called using A.B(), the same as method-calling syntax!


So it looks like Python is stuck with its name lookups.

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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 18:01, Chris Angelico wrote:

On Mon, Nov 9, 2015 at 4:54 AM, BartC  wrote:

That would be true for locals as well. But as far as I can tell from the
CPython source code, byte-codes uses an index to represent a local, which
represents an entry into a linear table.

I can't quite see why that can't be done for global names and for attributes
too (ie. the names that follow a ".").


At compilation time, the set of local names is locked in permanently.
That's not true of any other namespace (except nonlocals, which are
still locals, just not yours). Attributes and global names (which are
attributes of the current module) can be added and removed
dynamically, so they can't be assigned to slots; attributes can even
be simulated via __getattr__ and __getattribute__.


Yes, that's yet another way that the language design makes things 
difficult (for those who want to streamline its implementation).


For most purposes, the set of attribute names that can follow a dot are 
limited and fixed, by the occurrences of such names in a source file. So 
they can be assigned a slot.


But then, you say that additional attributes, potentially millions of 
different ones, can be invented at runtime. Although I don't see how it 
can remove names that are part of the source code: if "A.B" is in the 
file, then surely "A" and "B" always have to be present in some table or 
other.


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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 09/11/2015 00:00, Ben Finney wrote:

BartC  writes:


Is this typical Python code? Creating global objects in other modules
(or writing all over essential data structures in a library module).


Not “creating global objects”, but changing the referent of a name in
some other module. Yes, that's quite a common technique. Does that
surprise you?


Changing the referent (I assume that just means assigning to it or 
updating the associated value) wouldn't be a problem. Provided the name 
was defined in that other module, because then it is a name the compiler 
would know about.


(And, more importantly, someone reading the code in that module would 
know about.)



If it surprises you, hopefully you can learn some more Python with this
new knowledge.


Yes, that it's more of a crazy language than it looks at first; I can 
write a simple module like this:


pass

which looks like an empty module, yet for all I know will end up contain 
hundreds of variables by the time it's run.


(I normally use my own language, that I call 'dynamic', but compared 
with Python it might as well be carved in stone!)


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


Re: Question about math.pi is mutable

2015-11-08 Thread Steven D'Aprano
On Sun, 8 Nov 2015 11:28 pm, Chris Angelico wrote:

> On Sun, Nov 8, 2015 at 10:19 PM, BartC  wrote:
>> I've never understood why this seems to be necessary in Python. Why do
>> names have to be looked up? (I'm assuming this is searching by name in
>> some sort of table.)
> 
> Yes, if by "searching" you include hash-table lookup. A CPython
> dictionary is a *highly* optimized data structure, specifically
> because it's used virtually everywhere (I understand Lua's "table"
> type has similar optimizations for the same reason). In the common
> case, where your names come from literal text in the module, the
> strings used for the lookup will be interned constants, and their
> hashes will have been precalculated and stored, so the lookup is
> pretty easy. So it's a constant-time operation, and while that
> constant may be larger than a simple offset-and-fetch, it's still
> pretty fast in the overall scheme of things.

*Usually*.

There are pathological cases -- if you're unlucky enough, or malicious
enough, to have a whole lot of names with the same hash value, the look-up
degrades to a linear search.

More importantly, consider the case of a function referring to a variable
named "spam". In principle, at least, it may need to:

- search the local namespace;
- search the namespace of one or more enclosing functions;
- search the global namespace;
- search the built-in namespace;

before locating the variable's value. In practice, most Python
implementations will provide at least one optimization: local variables are
recognised and searched using an offset-and-fetch model.

Similarly for method calls: spam.eggs needs to:

- search the instance dict and slots;
- search the class dict;
- search the dict for each additional superclass;

where searching involves more than just a hash table lookup. It also
involves checking the classes for __getattribute__ and __getattr__ methods,
checking for descriptors, and more. The whole lookup process is quite
complicated, and little of it can be done at compile time.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-08 Thread Steven D'Aprano
On Sun, 8 Nov 2015 11:39 pm, BartC wrote:


>> shutil.copyfileobj(Source(), Dest())
>> 
> 
> OK, so here, it is necessary to resolve "copyfileobj" by seeing if
> "shutil" is something that contains a name "copyfileobj" that happens to
> be a method.

Correct.

> Is this the lookup you're talking about, and is it done using the actual
> string "copyfileobj"? If so, does it need to be done every single time
> this line is executed? It would extraordinarily inefficient if that was
> the case.

That's not what Marko was referring to, but you are correct, it is done
using the string "copyfileobj". And it has to be done every single time,
since you cannot be sure that the lookup will always return the same
object, or even whether it will always succeed. For example, here is a
self-destructing method:


class X:
counter = 0
def method(self):
self.counter += 1
if self.counter == 3:
del X.method
msg = "This method will self-destruct in %d calls."
return msg % (3 - self.counter)


But you are wrong to describe this as "extraordinarily inefficient". It is
certainly efficient enough to be practical: inefficient or not, Python is
used for many thousands of practical applications. It is only about a
factor of 100 times slower than C or Java, and the PyPy optimizing compiler
averages ten times faster (and, occasionally, approaches or even exceeds
the speed of similar C or Java code). When performance is critical, you can
often locate the bottlenecks and turn that into C or Fortran code.

Ruby, which is even more flexible than Python in some ways, is even slower,
and yet even Ruby is still fast enough to be practical for many tasks.

And remember too that some of the speed of Java (and especially C) is gained
at the expense of:

- prohibiting the developer from doing certain things;
- restricting the range of values you can use;
- making significant assumptions about correctness;
- avoiding actually checking those assumptions;
- and in the case of C, by outright *ignoring the code you write* if you
inadvertently violate those assumptions.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-08 Thread Ben Finney
Chris Angelico  writes:

> Hmm, then I was misunderstanding what BartC was advocating. I didn't
> think it would *fail* in the presence of dynamic attributes, but
> merely *perform suboptimally* (and presumably worse than current
> CPython).

There isn't a way for the compiler to *know*, in all cases, whether
module attributes will be updated during the lifetime of the program
(short of, as pointed out elsewhere, running the entire program under
all possible conditions).

So the optimisation can't be applied by the compiler without risking
breaking perfectly valid code.

That is enough, IMO, to kill the proposal; if the compiler could break
*any* valid code, it's no longer a Python compiler.

-- 
 \   “If [a technology company] has confidence in their future |
  `\  ability to innovate, the importance they place on protecting |
_o__) their past innovations really should decline.” —Gary Barnett |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-08 Thread Ben Finney
Chris Angelico  writes:

> Testing/mocking is a completely separate consideration (eg you can
> inject a shadow for a built-in name)

Not for the purpose of making compiler optimisations, as BartC is
advocating.

The compiler definitely should not treat “is this code part of a test
suite?” as a relevant criterion for deciding what optimisation. We
should certainly not have a compiler that makes needless difference to
code behaviour under test conditions versus non-test conditions.

So, since those optimisations would cripple perfectly normal test code,
that should be sufficient to quash the desire to make them.

-- 
 \   “If you define cowardice as running away at the first sign of |
  `\   danger, screaming and tripping and begging for mercy, then yes, |
_o__)   Mr. Brave man, I guess I'm a coward.” —Jack Handey |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-08 Thread Ben Finney
BartC  writes:

> Is this typical Python code? Creating global objects in other modules
> (or writing all over essential data structures in a library module).

Not “creating global objects”, but changing the referent of a name in
some other module. Yes, that's quite a common technique. Does that
surprise you?

If it surprises you, hopefully you can learn some more Python with this
new knowledge.

-- 
 \ “We can't depend for the long run on distinguishing one |
  `\ bitstream from another in order to figure out which rules |
_o__)   apply.” —Eben Moglen, _Anarchism Triumphant_, 1999 |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-08 Thread Chris Angelico
On Mon, Nov 9, 2015 at 11:00 AM, Ben Finney  wrote:
> BartC  writes:
>
>> Is this typical Python code? Creating global objects in other modules
>> (or writing all over essential data structures in a library module).
>
> Not “creating global objects”, but changing the referent of a name in
> some other module. Yes, that's quite a common technique. Does that
> surprise you?

Changing the referent of an existing name, definitely. Creating new
names, not so much. You don't often reach into another module and
create a new attribute.

Testing/mocking is a completely separate consideration (eg you can
inject a shadow for a built-in name); if some Python implementation
has a fast path that gets defeated by "module.int = MagicInt", and it
causes the tests to run slower, so be it. Other than that, I can't
think of many cases (actually, can't think of any, off hand) where you
inject names into other modules.

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


Re: Question about math.pi is mutable

2015-11-08 Thread Ben Finney
Chris Angelico  writes:

> On Mon, Nov 9, 2015 at 11:26 AM, Ben Finney  
> wrote:
> > Chris Angelico  writes:
> >
> >> Testing/mocking is a completely separate consideration (eg you can
> >> inject a shadow for a built-in name)
> >
> > Not for the purpose of making compiler optimisations, as BartC is
> > advocating. […] since those optimisations would cripple perfectly
> > normal test code, that should be sufficient to quash the desire to
> > make them.
>
> But I distinguish between crippling *performance* and crippling
> *functionality*. If the compiler optimizations are defeated, so the
> test suite falls back on the slow path, that means your tests run
> slower. Unless you're testing the optimizer itself, this shouldn't be
> a problem.

You misunderstand me. I'm not saying the optimisations would be
crippled. I am saying that, in order to achieve those optimisations, the
*test code* would be crippled.

I am pointing out that the assumption necessary for the optimisation
BartC is advocating – the optimisation of module attributes to be
immutable after compilation – depends on crippling the *functionality*
needed for many uses, including test code uses.

Since the compiler should not be in the position of deciding whether
code is test code or not, it cannot use that criterion to decide whether
to enable or disable the optimisation.

So either the optimisation should never be enabled (my perference), or
test code will unwittingly be crippled by the assumptions needed for
that optimisation.

-- 
 \ “We are all agreed that your theory is crazy. The question that |
  `\  divides us is whether it is crazy enough to have a chance of |
_o__)being correct.” —Niels Bohr (to Wolfgang Pauli), 1958 |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-08 Thread Chris Angelico
On Mon, Nov 9, 2015 at 11:50 AM, Ben Finney  wrote:
> You misunderstand me. I'm not saying the optimisations would be
> crippled. I am saying that, in order to achieve those optimisations, the
> *test code* would be crippled.
>
> I am pointing out that the assumption necessary for the optimisation
> BartC is advocating – the optimisation of module attributes to be
> immutable after compilation – depends on crippling the *functionality*
> needed for many uses, including test code uses.
>
> Since the compiler should not be in the position of deciding whether
> code is test code or not, it cannot use that criterion to decide whether
> to enable or disable the optimisation.
>
> So either the optimisation should never be enabled (my perference), or
> test code will unwittingly be crippled by the assumptions needed for
> that optimisation.

Hmm, then I was misunderstanding what BartC was advocating. I didn't
think it would *fail* in the presence of dynamic attributes, but
merely *perform suboptimally* (and presumably worse than current
CPython). If it does indeed require crippling the functionality, then
I agree, this is a bad idea.

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


Re: Question about math.pi is mutable

2015-11-08 Thread Steven D'Aprano
On Mon, 9 Nov 2015 09:35 am, BartC wrote:

> Suppose this is the python program:
> 
> import m
> a=10
> b=20
> c=30
> m.f()
> 
> The set of global names the compiler knows will be ("m","a","b","c").

Wrong. Up to the line "c=30", the set of names the compiler can infer are m,
a, b and c. Once the line "m.f()" executes, *all bets are off*. The
compiler can no longer infer *anything* about those names. In principle,
m.f may have reached into the globals and deleted *any* of the names,
including itself.


> I don't believe code can remove these names (that would cause problems).

Of course names can be removed. There's even a built-in statement to do
so: "del".

Deleting names from namespaces is a moderately common thing to do.


> You say the set of global names can be added to - after this lot, but I
> can't see that the first four are going to change.

Of course they can change.


> Therefore these names could be referred to by index.

Perhaps. But that adds significant complexity to the compiler, and the
performance benefits *in practice* may not be as good as you imagine. After
all, there is usually far more to real programs than just getting and
setting names.

Nevertheless, such indexed name lookups do have the potential to save time,
and in fact that's what CPython already does with local variables. We can
get a *rough* indication of how big a difference this micro-optimization
makes by disabling it. Unfortunately, this only works in Python 2 -- in
Python 3, you can no longer defeat the local variable optimization.


def unopt():
from math import *  # Defeats the local variable optimization.
x = sin; x = cos; x = tan; x = exp; x = pi
x = e; x = trunc; x = log; x = hypot; x = sqrt
return

def opt():
from math import sin, cos, tan, exp, pi, e, trunc, log, hypot, sqrt
x = sin; x = cos; x = tan; x = exp; x = pi
x = e; x = trunc; x = log; x = hypot; x = sqrt
return

from timeit import Timer
t1 = Timer("unopt()", setup="from __main__ import unopt")
t2 = Timer("opt()", setup="from __main__ import opt")

# Best of five trials of 1,000,000 calls each.
print min(t1.repeat(repeat=5))
print min(t2.repeat(repeat=5))


When I run this code, I get

16.5607659817 seconds for unopt, and 3.58955097198 seconds for opt. That's a
significant difference. But remember that not all of that difference is due
to the name lookups (unopt also imports more stuff), and also remember that
this is a pretty unrealistic benchmark. Real functions do more than just
look up a variable name over and over.


> Attributes are harder because they are more of a free-for-all, but
> suppose you do have m.f().
> 
> "m" is easy, it's entry 0 in the global table for this module, so no
> lookup-by-name is needed. You examine it, and it's a module.
> 
> It's now necessary to find f within the global table for m. This is
> where it gets tricky if you want to avoid a lookup. And I expect you
> will say that any code can randomly add names within the global table of
> m.

Of course it can. It can even add names to builtins.

Oh, and you don't know that m is a module until you inspect it at runtime.
It could be any object.



> But bear with me. Suppose the interpreter were to maintain a table for
> each static (not runtime) attribute encountered in the source code. The
> compile can produce empty tables for the attributes it's seen. In this
> case the table for "f" would be empty: (). The compiler will also
> produce a list of such tables for all attributes.

I have no idea how well this implementation would work. My guess is that if
you look at, say, Nuitka, it may perform optimizations like this. (The aim
of Nuitka is to be a static optimizing compiler.) PyPy may do things like
this too, using a JIT optimizing compiler. PyPy is capable of far more than
such simple optimizations.

As I have argued all along, it is certainly not true that Python's
dynamicism prevents all such optimizations. It just makes them harder.


-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-08 Thread Chris Angelico
On Mon, Nov 9, 2015 at 11:26 AM, Ben Finney  wrote:
> Chris Angelico  writes:
>
>> Testing/mocking is a completely separate consideration (eg you can
>> inject a shadow for a built-in name)
>
> Not for the purpose of making compiler optimisations, as BartC is
> advocating.
>
> The compiler definitely should not treat “is this code part of a test
> suite?” as a relevant criterion for deciding what optimisation. We
> should certainly not have a compiler that makes needless difference to
> code behaviour under test conditions versus non-test conditions.
>
> So, since those optimisations would cripple perfectly normal test code,
> that should be sufficient to quash the desire to make them.

But I distinguish between crippling *performance* and crippling
*functionality*. If the compiler optimizations are defeated, so the
test suite falls back on the slow path, that means your tests run
slower. Unless you're testing the optimizer itself, this shouldn't be
a problem.

This is broadly the same kinds of optimizations that Fat Python is
playing with. Effectively, what it says is "I think that 'len' is this
object", and then it guards the fast path with a quick check for
validity. So if you go in and change something, the result is that the
slow path gets used instead.

The question then is whether it's worth the optimization effort. Will
the slow path be penalized more than the fast path gains? Will the
code complexity introduce more bugs? The same consideration comes up
in JavaScript/ECMAScript (where object attributes can also be created
dynamically), and I know some interpreters have been written to do a
slot-based lookup, so the concept does have at least some merit.

Personally, I'm dubious about the value of this in CPython; but I'm
willing to be persuaded.

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


Re: Question about math.pi is mutable

2015-11-08 Thread Ben Finney
BartC  writes:

> On 08/11/2015 21:00, Ben Finney wrote:
> > The namespace can change dynamically, which is another way of what
> > people have been trying to tell you all through this thread.
> >
> > The compiler *cannot* know what the names will be at every single
> > point they'll be looked un in the namespace dictionary. This
> > dynamism of each namespace is a Python feature.
>
> Suppose this is the python program:
>
> import m
> a=10
> b=20
> c=30
> m.f()
>
> The set of global names the compiler knows will be ("m","a","b","c").
>
> I don't believe code can remove these names (that would cause
> problems).

It may indeed cause problems. Those names can nevertheless be changed.

Names at module level are simply attributes on the module object. The
module can gain attributes, lose attributes, and its attributes can
chage; its namespace is just as mutable as any other object's namespace.

> You say the set of global names can be added to - after this lot, but
> I can't see that the first four are going to change.

You have not yet learned enough about the Python data model:

A module object has a namespace implemented by a dictionary object
(this is the dictionary referenced by the __globals__ attribute of
functions defined in the module). Attribute references are
translated to lookups in this dictionary, e.g., m.x is equivalent
to m.__dict__["x"]. A module object does not contain the code
object used to initialize the module (since it isn’t needed once
the initialization is done).



Any name can be deleted, just like any other reference, with the ‘del’
statement.

Any reference (including names) can be added or changed in a module
namespace like any other object's namespace.

> Attributes are harder because they are more of a free-for-all

Please understand that a module *is* an object, and a name in a module's
namespace *is* an attribute on that module.

Also, please *learn about* the way Python works; you have certainly been
here long enough to know how to look up answers in the documentation
instead of making ignorant assertions here.

-- 
 \   “What I resent is that the range of your vision should be the |
  `\ limit of my action.” —Henry James |
_o__)  |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 23:13, Dennis Lee Bieber wrote:

On Sun, 8 Nov 2015 18:58:36 +, BartC  declaimed the
following:


But then, you say that additional attributes, potentially millions of
different ones, can be invented at runtime. Although I don't see how it
can remove names that are part of the source code: if "A.B" is in the
file, then surely "A" and "B" always have to be present in some table or
other.


-=-=-=-=- module.py

class Something(object):
def __init__(self):
pass

-=-=-=-=- main.py

import module

module.remote = module.Something()
nonremote = module.remote
nonremote.x = "Looky here"
print module.remote.x
module.remote.x = 3.14
print nonremote.x
module.remote = None
print nonremote.x
print module.remote.x


Is this typical Python code? Creating global objects in other modules 
(or writing all over essential data structures in a library module).


If most code is going to be more sensible, then I mentioned an approach 
in my other post just over an hour ago. The idea there was to optimise 
attribute lookups when code is written with more restraint. (So defining 
functions, classes and attributes within classes in a boring manner.)



Where do you propose to "tableize" remote, nonremote, and x. "remote"
doesn't exist inside module.py until one executes main.py -- so it can't be


In your example, only attributes "remote" and "x" exist. But the tables 
for those will be empty as it is not practical to add in runtime-created 
attributes. Then, a conventional lookup would be needed.



optimized to when the compiler parses module.py (creating, in most cases a
bytecode module.pyc). You can't optimize it to main.py since (not shown in
my example) there may be another imported package that also imports module
and references module.remote -- and could even replace it with a new object
(in which case nonremote is still associated with the old object, not the
new one)


The tables would reflect the static layout of the attributes as defined 
in the source code. Since the source code is finite, the tables will be 
also (unlike runtime when a billion attributes could be created).


If your module.py code is tweaked like this:

 class Something(object):
x=0
def __init__(self):
pass

 remote=0

Then 'x' and 'remote' become static attributes that can now added to 
tables for fast lookup. Although this does require that these two are 
effectively 'declared'.


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


Re: Question about math.pi is mutable

2015-11-08 Thread BartC

On 08/11/2015 11:02, Marko Rauhamaa wrote:

Bartc :


(In the case of Python, the main obstacle is that a constant name from
inside an imported module is not visible when this module is compiled
to byte-code. So it has to assume it can be anything.)


Which it can.



That elegant dynamism comes at a cost: method lookup is not a constant
memory offset. Rather, it is a dictionary lookup.


I've never understood why this seems to be necessary in Python. Why do 
names have to be looked up? (I'm assuming this is searching by name in 
some sort of table.)


When a module is compiled, while the compiler can't see the definitions 
inside the imported modules, it /will/ know all the names that appear in 
this module, so it can organise them into fixed tables. Then the names 
can be referred to by index. (I think LOAD_FAST does this.)


Or is eval() the culprit here by making most optimisations impossible?

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


Re: Question about math.pi is mutable

2015-11-08 Thread Christian Gollwitzer

Am 08.11.15 um 08:45 schrieb Marko Rauhamaa:

Grant Edwards :


On 2015-11-07, Marko Rauhamaa  wrote:

"const" is a very ineffective tool that clutters the code and forces
you to sprinkle type casts around your code.


But it allows the compiler to warn you if you pass a pointer to a
read-only data to a function that expects a pointer to writable data.


Unfortunately, it doesn't:


#include 
#include 

int main()
{
 const char name[] = "Tom";
 char *p = strstr(name, "Tom");
 strcpy(p, "Bob");
 printf("name = %s\n", name);
 return 0;
}


 $ cc -o prog prog.c
 $ ./prog
 Bob

No warning.



That is strange. In C, I can see thet problem here, because it is 
impossible to define a const correct strstr. But in C++ I have expected 
that according to the overload, the const version of strstr would be 
selected (http://www.cplusplus.com/reference/cstring/strstr/ ) . Still:


apfelkiste:Tests chris$ cat prog.cpp
#include 
#include 

int main()
{
const char name[] = "Tom";
char *p = strstr(name, "Tom"); // this line should be an error
strcpy(p, "Bob");
printf("name = %s\n", name);
return 0;
}

apfelkiste:Tests chris$ g++ -Wall prog.cpp
apfelkiste:Tests chris$ ./a.out
Bus error: 10

It segfaults because on OSX, const can be stored in write-only memory.

apfelkiste:Tests chris$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr 
--with-gxx-include-dir=/usr/include/c++/4.2.1

Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin12.6.0
Thread model: posix


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


Re: Question about math.pi is mutable

2015-11-08 Thread Paul Rubin
Marko Rauhamaa  writes:
> Point is, the consequences of "proper" use of const are so annoying even
> standard library functions would rather grossly abuse it than tolerate
> compiler warnings everywhere.

I'm not sure what the C standard says about that example, but C++ is
much stricter about those conversions, and g++ does flag an error if
you compile that code with it.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Question about math.pi is mutable

2015-11-07 Thread Ben Finney
Bartc  writes:

> To my mind, Python allows far too much freedom in being able to change
> anything at any time.

You're welcome to that opinion. I don't see you present a reason why it
should affect anyone else's opinion of Python, though.

> Yet Python has to assume 100% of the time that it could have been
> changed. Think of the opportunities for optimising if the probability
> was 0%.

Such a pity that Python is missing all those opportunities for
widespread adoption, by not hewing closer to your preferences.

-- 
 \“That's the essence of science: Ask an impertinent question, |
  `\and you're on the way to the pertinent answer.” —Jacob |
_o__) Bronowski, _The Ascent of Man_, 1973 |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-07 Thread Ben Finney
Bartc  writes:

> On 07/11/2015 03:43, Ben Finney wrote:
> > Bartc  writes:
> >
> >> Is there no way then in Python to declare:
> >>
> >> pi = 3.141519 # etc
> >>
> >> and make it impossible to override?
> >
> > No, and it would be a bad thing if that were something a library author
> > could forbid.
> >
> > Python assumes the programmers using it are consenting adults. Doing
> > harmful things is difficult but not forbidden.
>
> But surely it can't hurt to ensure certain values can't be changed
> accidentally or maliciously?

The value ‘3.141519’ (in your example above) can't be changed. That
value will always be exactly the same, as long as the program is
running.

What I think you mean is “surely it can't hurt to ensure certain names
can never be bound to any value but their initial binding”.

On that I strongly disagree, for the reasons already discussed in this
thread: it arrogates to the library author the power to forbid patching
the library, which cripples extending, debugging, introspection, and a
host of other useful activities.

-- 
 \ “I object to doing things that computers can do.” —Olin Shivers |
  `\   |
_o__)  |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-07 Thread Bartc

On 07/11/2015 12:15, Ben Finney wrote:

Bartc  writes:


To my mind, Python allows far too much freedom in being able to change
anything at any time.


You're welcome to that opinion. I don't see you present a reason why it
should affect anyone else's opinion of Python, though.


Not just my option. From this 2010 paper for example ('High performance 
implementation of Python for CLI ...' by Antonio Cuni):


"As a language, Python is very hard to implement efficiently: the 
presence of highly dynamic constructs makes static analysis of programs 
extremely difficult, thus preventing ahead of time (AOT) compilers to 
generate efficient target code."



Yet Python has to assume 100% of the time that it could have been
changed. Think of the opportunities for optimising if the probability
was 0%.


Such a pity that Python is missing all those opportunities for
widespread adoption, by not hewing closer to your preferences.


Plenty of other people working on faster Pythons appear to have trouble 
with its being so dynamic.


(Earlier this year, I was upgrading my own language to be much more 
Python-like in its internal workings. But I gave it up because I was 
losing so many nice features that also made it easy to implement 
efficiently.


As one example of many, named constants (the 'const' feature earlier in 
the thread), were used for 'switch' statements. Without 'const', then I 
couldn't have a fast 'switch'.)


I suppose my coding style is just different from people who write 
Python. When I define a function f(), then it's always going to be 
function f and is never going to change. A call to such a function can 
therefore be streamlined.


If I ever need it to be dynamic, then I use a function pointer:

  g=f

f is still the static function, g is a now a reference to it, and is a 
little slower to call. But the /vast majority/ of function calls are 
going to be static.


--
Bartc

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


Re: Question about math.pi is mutable

2015-11-07 Thread Bartc

On 07/11/2015 14:23, Marko Rauhamaa wrote:

Bartc :



In my work, I currently use bash, Python and C. For many, many tasks,
bash is superior to Python. For others, Python can't compete with C. Yet
the vast gap between bash and C is nicely filled with Python.


The gap between Python and C is still pretty big!

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


Re: Question about math.pi is mutable

2015-11-07 Thread Laura Creighton
In a message of Sat, 07 Nov 2015 13:00:37 +, Bartc writes:

>Not just my option. From this 2010 paper for example ('High performance 
>implementation of Python for CLI ...' by Antonio Cuni):
>
>"As a language, Python is very hard to implement efficiently: the 
>presence of highly dynamic constructs makes static analysis of programs 
>extremely difficult, thus preventing ahead of time (AOT) compilers to 
>generate efficient target code."

Recall that my friend Anto is discussing 'why my phd thesis was hard
stuff, as I did this for PyPy' and not 'Python would be better if it
were easier to write fast compilers for it'. :)

Anto loves the dynamic nature of python.  It just makes pypy hard.

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


Re: Question about math.pi is mutable

2015-11-07 Thread Bartc

On 07/11/2015 11:35, Ben Finney wrote:

Bartc  writes:


On 07/11/2015 03:43, Ben Finney wrote:

Bartc  writes:


Is there no way then in Python to declare:

 pi = 3.141519 # etc

and make it impossible to override?


No, and it would be a bad thing if that were something a library author
could forbid.

Python assumes the programmers using it are consenting adults. Doing
harmful things is difficult but not forbidden.


But surely it can't hurt to ensure certain values can't be changed
accidentally or maliciously?


The value ‘3.141519’ (in your example above) can't be changed. That
value will always be exactly the same, as long as the program is
running.

What I think you mean is “surely it can't hurt to ensure certain names
can never be bound to any value but their initial binding”.

On that I strongly disagree, for the reasons already discussed in this
thread: it arrogates to the library author the power to forbid patching
the library, which cripples extending, debugging, introspection, and a
host of other useful activities.


Why would it stop introspection?

If the source is available, why would it stop anyone extending a library?

To my mind, Python allows far too much freedom in being able to change 
anything at any time. Imagine if the interfaces to Win32 API or to the 
Linux kernel could be turned upside down from one microsecond to the 
next, while programs are still running.


Take a simple function like thousands of others:

 def dull(x,y,z);
.
.
99.% of the time, the name 'dull' is not going to be bound to 
anything else, and it would just be called like this:


  dull(10,20,30)

Yet Python has to assume 100% of the time that it could have been 
changed. Think of the opportunities for optimising if the probability 
was 0%.


Perhaps if library authors want people tinkering with their code at 
runtime, they should mark it as such ('var', 'volatile' etc). Because 
most of us are quite happy with a boring, static library that is not 
likely to morph into something else!


--
Bartc

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


Re: Question about math.pi is mutable

2015-11-07 Thread Marko Rauhamaa
Bartc :

> Not just my option. From this 2010 paper for example ('High performance
> implementation of Python for CLI ...' by Antonio Cuni):
>
> "As a language, Python is very hard to implement efficiently: the
> presence of highly dynamic constructs makes static analysis of
> programs extremely difficult, thus preventing ahead of time (AOT)
> compilers to generate efficient target code."

Correct. That's not Python's fault, however. Python should not try to
placate the performance computing people. (Alas, it is now trying to do
just that with the introduction of static typing annotation.)

> Plenty of other people working on faster Pythons appear to have
> trouble with its being so dynamic.

That's, literally, their problem.

> As one example of many, named constants (the 'const' feature earlier
> in the thread), were used for 'switch' statements. Without 'const',
> then I couldn't have a fast 'switch'.)

Fast, fast, fast. We have plenty of fast programming languages. Python
should *not* sacrifice its dynamism (which the fast languages don't
have) for speed. Python is already fast enough for most programming
tasks.

In my work, I currently use bash, Python and C. For many, many tasks,
bash is superior to Python. For others, Python can't compete with C. Yet
the vast gap between bash and C is nicely filled with Python.

Those three golf clubs are all I need in my bag. Java, C#, go, C++ have
great merits. However, I really don't ever miss them.

(The one club I have special sentiments for is Scheme. I don't use it
professionally for, though, because its ecosystem is not quite developed
enough yet.)

> I suppose my coding style is just different from people who write
> Python. When I define a function f(), then it's always going to be
> function f and is never going to change. A call to such a function can
> therefore be streamlined.

Your point of view is really down-to-earth. It's slightly analogous to
protesting against Unicode because you only ever need ASCII.

You would be right in that Python programs hardly ever make use of or
directly depend on the degrees of freedom Python affords. They are used
every here and there, however, and, most imporantly, they make it
possible to define the semantics of the programming language in a sound,
concise manner. That way it is easier to implement Python, learn
Python and use Python correctly.

Imagine there was a national standard that defined that you could only
sell hatchets that split wood in a downward movement. You might argue
that hardly anyone swung a hatchet sideways, and it would be dangerous
anyway. However, that kind of a standard would make it very difficult to
manufacture the simple concept of a hatchet. The contraption would be
expensive, fragile, heavy and difficult to use even for the intended
up-down splitting purpose.

I wouldn't like Python to turn into such a contraption.


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


Re: Question about math.pi is mutable

2015-11-07 Thread Marko Rauhamaa
Marko Rauhamaa :

> In my work, I currently use bash, Python and C. For many, many tasks,
> bash is superior to Python. For others, Python can't compete with C.
> Yet the vast gap between bash and C is nicely filled with Python.

And, by the way, the introduction of the "const" keyword was maybe the
biggest mistake the C standardizers ever made. It turned out to be about
as useful as a mosquito buzzing at your ear, and equally persistent and
annoying.


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


Re: Question about math.pi is mutable

2015-11-07 Thread Bartc

On 07/11/2015 14:28, Marko Rauhamaa wrote:

Marko Rauhamaa :


In my work, I currently use bash, Python and C. For many, many tasks,
bash is superior to Python. For others, Python can't compete with C.
Yet the vast gap between bash and C is nicely filled with Python.


And, by the way, the introduction of the "const" keyword was maybe the
biggest mistake the C standardizers ever made. It turned out to be about
as useful as a mosquito buzzing at your ear, and equally persistent and
annoying.


(Yes, 'const' in C is a waste of time, and half the people using it 
don't appear to know what it means. Some people also like to use it 
practically everywhere so that you can no longer make out the actual 
code. The version in C++ is a more complicated form even further away 
from what people really want.


Neither have the simplicity of concept of Pascal's 'const', which is 
just a named value. Not a variable that won't change once initialised, 
not a parameter that won't be changed nor any addressable location.)


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


Re: Question about math.pi is mutable

2015-11-07 Thread Bartc

On 07/11/2015 03:43, Ben Finney wrote:

Bartc  writes:


Is there no way then in Python to declare:

pi = 3.141519 # etc

and make it impossible to override?


No, and it would be a bad thing if that were something a library author
could forbid.

Python assumes the programmers using it are consenting adults. Doing
harmful things is difficult but not forbidden.


But surely it can't hurt to ensure certain values can't be changed 
accidentally or maliciously?


Some dynamic languages (OK, I'm thinking of mine) simply allow you to write:

   const pi = 3.14159

Then this can't be changed, because it would be the equivalent of writing:

   3.14159 = 0

What would be the harm in this?

It's a very simple idea, yet many people and languages either don't like 
it or can't grasp it. Not even C has the feature, if you don't count 
using the crude #define for the purpose.


In the case of Python, it could have allowed 'constant folding', so that 
math.pi*2 need not be evaluated at runtime.


(Python however does make it quite difficult to add features like this. 
Mostly because such names are not visible across modules when compiling.


Also it is still possible to write math = some_other_module.)

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


Re: Question about math.pi is mutable

2015-11-07 Thread Grant Edwards
On 2015-11-07, Marko Rauhamaa  wrote:
> Marko Rauhamaa :
>
>> In my work, I currently use bash, Python and C. For many, many tasks,
>> bash is superior to Python. For others, Python can't compete with C.
>> Yet the vast gap between bash and C is nicely filled with Python.
>
> And, by the way, the introduction of the "const" keyword was maybe the
> biggest mistake the C standardizers ever made. It turned out to be about
> as useful as a mosquito buzzing at your ear, and equally persistent and
> annoying.

I take it you don't write embedded code that runs from ROM?  I do. The
const keyword is the most valuable addition to the C language since
the function prototype.  Without it, you used to have to jump through
all sorts of hoops to get read-only data placed into read-only memory.

-- 
Grant


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


Re: Question about math.pi is mutable

2015-11-07 Thread Marko Rauhamaa
Bartc :

> (Yes, 'const' in C is a waste of time, and half the people using it
> don't appear to know what it means.

It cannot mean anything meaningful; it's completely useless.

For example, what could one think of standard library functions whose
prototypes are:

   char *strstr(const char *haystack, const char *needle);

   int execve(const char *filename, char *const argv[],
  char *const envp[]);

Ok, enough of C.


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


Re: Question about math.pi is mutable

2015-11-07 Thread Marko Rauhamaa
Grant Edwards :

> I take it you don't write embedded code that runs from ROM? I do. The
> const keyword is the most valuable addition to the C language since
> the function prototype. Without it, you used to have to jump through
> all sorts of hoops to get read-only data placed into read-only memory.

If all you need is a linker directive that places data in a read-only
section, "const" is a very ineffective tool that clutters the code and
forces you to sprinkle type casts around your code.


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


Re: Question about math.pi is mutable

2015-11-07 Thread Mark Lawrence

On 07/11/2015 23:02, Bartc wrote:

On 06/11/2015 22:26, Thomas 'PointedEars' Lahn wrote:

Bartc wrote:
^
Please fix.


What's the problem?




He is the problem.  I assume it's because he thinks he's a dog, cat or 
some other animal.


--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

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


Re: Question about math.pi is mutable

2015-11-07 Thread Bartc

On 06/11/2015 22:26, Thomas 'PointedEars' Lahn wrote:

Bartc wrote:
^
Please fix.


What's the problem?


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


Re: Question about math.pi is mutable

2015-11-07 Thread Ben Finney
Bartc  writes:

> On 06/11/2015 22:26, Thomas 'PointedEars' Lahn wrote:
> > Bartc wrote:
> > ^
> > Please fix.
>
> What's the problem?

As far as I can tell, you're being asked to change that to your “real”
name, whatever that is supposed to mean.

I recommend you ignore that request; “Bartc” is fine as a name here,
IMO.

-- 
 \“Your [government] representative owes you, not his industry |
  `\   only, but his judgment; and he betrays, instead of serving you, |
_o__)if he sacrifices it to your opinion.” —Edmund Burke, 1774 |
Ben Finney

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


Re: Question about math.pi is mutable

2015-11-07 Thread Chris Angelico
On Sun, Nov 8, 2015 at 10:32 AM, Ben Finney  wrote:
> I recommend you ignore that request; “Bartc” is fine as a name here,
> IMO.

Given that LARTC means Linux Advanced Routing and Traffic Control, I'm
guessing Bartc is all about *BSD networking? :)

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


Re: Question about math.pi is mutable

2015-11-07 Thread Steven D'Aprano
On Sun, 8 Nov 2015 02:01 am, Bartc wrote:

> Neither have the simplicity of concept of Pascal's 'const', which is
> just a named value. Not a variable that won't change once initialised,
> not a parameter that won't be changed nor any addressable location.)

Unfortunately the concept of "named value" doesn't match well with Python's
design. That implies a separate compilation step which doesn't fit well
with Python's runtime semantics. Very little happens at compile-time in
Python that *must* happen at compile-time.

I'm also not sure what difference you think there is between "named value"
and "variable that won't change once initialised".

Python has a convention for "constants" -- all UPPERCASE names. The fact
that the convention exists is enough to prove that the concept
of "constant" is a useful one. The difference between Python's
pseudo-constants and (say) Pascal's actual constants is that in Python, the
burden of ensuring that neither you, nor any of the libraries you call,
modifies the "constant" falls on you, the user, whereas in Pascal the
compiler or interpreter performs that checking for you.

Besides, the Python convention is honoured more in theory than in practice.
We have math.pi, not math.PI.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-07 Thread Steven D'Aprano
On Sun, 8 Nov 2015 04:46 am, Marko Rauhamaa wrote:

> Bartc :
> 
>> (Yes, 'const' in C is a waste of time, and half the people using it
>> don't appear to know what it means.
> 
> It cannot mean anything meaningful; it's completely useless.
> 
> For example, what could one think of standard library functions whose
> prototypes are:
> 
>char *strstr(const char *haystack, const char *needle);
> 
>int execve(const char *filename, char *const argv[],
>   char *const envp[]);

Surely that is obvious? I don't speak much C, but I would expect that inside
the functions, const parameters can be read, but not assigned to. "*const"
is a mystery to me though.


> Ok, enough of C.

Amen to that.

If I had a dollar for every crime against computing committed because of C,
or enabled due to C's design decisions, I would be rich beyond the dreams
of avarice.

Fortunately, C is not the only other computer language, and we are by no
means limited to the two choices of the status quo (no constants in Python)
and what C does.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-07 Thread Grant Edwards
On 2015-11-07, Marko Rauhamaa  wrote:
> Grant Edwards :
>
>> I take it you don't write embedded code that runs from ROM? I do. The
>> const keyword is the most valuable addition to the C language since
>> the function prototype. Without it, you used to have to jump through
>> all sorts of hoops to get read-only data placed into read-only memory.
>
> If all you need is a linker directive that places data in a read-only
> section, "const" is a very ineffective tool that clutters the code and
> forces you to sprinkle type casts around your code.

But it allows the compiler to warn you if you pass a pointer to a
read-only data to a function that expects a pointer to writable data.

For those of us who occasionally make mistakes, such compiler warnings
are very useful.

-- 
Grant

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


Re: Question about math.pi is mutable

2015-11-07 Thread Steven D'Aprano
On Sun, 8 Nov 2015 01:23 am, Marko Rauhamaa wrote:

> Bartc :
> 
>> Not just my option. From this 2010 paper for example ('High performance
>> implementation of Python for CLI ...' by Antonio Cuni):
>>
>> "As a language, Python is very hard to implement efficiently: the
>> presence of highly dynamic constructs makes static analysis of
>> programs extremely difficult, thus preventing ahead of time (AOT)
>> compilers to generate efficient target code."
> 
> Correct. That's not Python's fault, however. Python should not try to
> placate the performance computing people. (Alas, it is now trying to do
> just that with the introduction of static typing annotation.)

That is factually incorrect.

The motive behind the introduction of typing annotations is not "speed",
but "correctness". Guido has expressed skepticism that typing annotations
can be used to improve the speed of Python programs, and has suggested that
the future of optimization is JIT compilers like PyPy rather than static
compilers like Nuitka.

[Aside: I have to disagree with Guido's thoughts on compilers. Even if JIT
compilers are ultimately faster for long-running code, they don't help much
for short-running code, and surely there is a lot of low-hanging fruit that
an optimizing compiler can perform. Victor Skinner is experimenting with a
version of CPython which, among other things, detects when built-ins have
not been modified, and can inline them for speed.]

If type annotations lead to faster code, that's a bonus, but it isn't why
they are being added to the language. They are added to improve correctness
and documentation, to enable type-checks to be performed by linters and
compile-time type-checkers.


>> Plenty of other people working on faster Pythons appear to have
>> trouble with its being so dynamic.
> 
> That's, literally, their problem.
> 
>> As one example of many, named constants (the 'const' feature earlier
>> in the thread), were used for 'switch' statements. Without 'const',
>> then I couldn't have a fast 'switch'.)
> 
> Fast, fast, fast. We have plenty of fast programming languages.

Yeah, but most of them suck. Why can't we have a fast programming language
that is as nice to use as Python? Why can't Python be fast?



> Python 
> should *not* sacrifice its dynamism (which the fast languages don't
> have) for speed. Python is already fast enough for most programming
> tasks.

Well, I don't know about anyone else, but I personally always want my
scripts and programs to run slower. I can't tell you how annoyed I was when
new-style classes became as fast or faster than old-style classes.

*wink*


[...]
>> I suppose my coding style is just different from people who write
>> Python. When I define a function f(), then it's always going to be
>> function f and is never going to change. A call to such a function can
>> therefore be streamlined.
> 
> Your point of view is really down-to-earth. It's slightly analogous to
> protesting against Unicode because you only ever need ASCII.

I don't think so, but in any case, Bart is *way* oversimplifying the
potential optimizations available. Function inlining depends on the
function being small enough that inlining it does more good than harm, but
it doesn't require that f never changes.

Perhaps Laura can confirm this, but I understand that PyPy can inline
functions. Simplified:

The compiler builds a fast path and a slow path, and a guard. If the
function is the one you expect, the interpreter takes the fast path, which
includes the inlined function. But if the function has been rebound, the
guard triggers, and the interpreter takes the slow path, which follows the
slow, dynamic implementation. In pseudo-code:

def spam():
result = eggs(x)

will compile as if it were written like this:

def spam():
if eggs is EXPECTED_EGGS:
# inline code
do_this()
do_that()
result = another_thing(x)
else:
result = eggs(x)


The compiler manages all the book-keeping for you, automatically, and as
functions grow and shrink in complexity, it will automatically decide which
ones can be inlined and which cannot. You write the simplest, most obvious
code which is easy to maintain, and the compiler managers the ugly
optimizations.


> You would be right in that Python programs hardly ever make use of or
> directly depend on the degrees of freedom Python affords.

That's certainly true. Every Python program pays a significant speed penalty
(perhaps as much as 10 x slower than it need be) for features which are
used by probably less than 1% of code.

The choice is not between "dynamic language" and "fast language". You can
have both. Smalltalk proves it. Javascript proves it. You just need smarter
compilers which can optimize the usual, non-dynamic cases while still
allowing dynamic code to work.

We often say that the reason Python is anything up to a factor of 100 times
slower than languages like Java is because Python is so dynamic, but 

Re: Question about math.pi is mutable

2015-11-07 Thread Random832
Steven D'Aprano  writes:
> Surely that is obvious? I don't speak much C, but I would expect that inside
> the functions, const parameters can be read, but not assigned to. "*const"
> is a mystery to me though.

There's a program (and now a website) called cdecl that can decode these:

char *const envp[]
declare envp as array of const pointer to char

In other words, the pointers in the array are const, but the array
itself (which is really a pointer, and it's generally regarded as
nonsense to make const first-level function arguments anyway, but enough
of that) is not, nor are the characters that the pointers point to.

There are various reasons I don't fully understand and are beyond the
scope of this argument regarding why it's not possible to assign a
pointer-to-pointer-to-char to a pointer-to-pointer-to-const-char, so the
argument isn't declared with the latter.

Unfortunately, while it handles simple function arguments, it (the
version on the website at least) apparently can't handle named or const
function arguments, otherwise you could paste the whole thing.

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


Re: Question about math.pi is mutable

2015-11-07 Thread Marko Rauhamaa
Grant Edwards :

> On 2015-11-07, Marko Rauhamaa  wrote:
>> "const" is a very ineffective tool that clutters the code and forces
>> you to sprinkle type casts around your code.
>
> But it allows the compiler to warn you if you pass a pointer to a
> read-only data to a function that expects a pointer to writable data.

Unfortunately, it doesn't:


#include 
#include 

int main()
{
const char name[] = "Tom";
char *p = strstr(name, "Tom");
strcpy(p, "Bob");
printf("name = %s\n", name);
return 0;
}


$ cc -o prog prog.c
$ ./prog
Bob

No warning.

Point is, the consequences of "proper" use of const are so annoying even
standard library functions would rather grossly abuse it than tolerate
compiler warnings everywhere.


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


Re: Question about math.pi is mutable

2015-11-06 Thread Steven D'Aprano
On Sat, 7 Nov 2015 09:26 am, Thomas 'PointedEars' Lahn wrote:
^

> Bartc wrote:
> ^
> Please fix.

Why? There's nothing wrong with somebody signing their posts "Bartc". It is
no more silly than somebody calling themselves "PointedEars". Please stop
trying to enforce non-existent rules about internet identities on others.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-06 Thread Steven D'Aprano
On Sat, 7 Nov 2015 09:19 am, Thomas 'PointedEars' Lahn wrote:

> It is certainly possible for attributes of (instances of) new-style
> classes (starting with Python 3.2 at the latest) to be read-only by
> declaring them a property that does not have a setter, or one that has a
> setter that throws a specific exception (here: the former):
> 
> #--
> class SafeMath(object):
> def __init__ (self):
> from math import pi
> self._pi = pi
> 
> @property
> def pi (self):
> return self._pi

The obvious problem with that is that it is trivially easy for the coder to
set self._pi to change the value of self.pi.

Here's a version that at first seems promising:

py> def builder():
... from math import pi as PI
... def pi(self):
... return PI
... return pi
...
py> class MathLib(object):
... pi = property(builder())
...
py> mathlib = MathLib()
py> mathlib.pi
3.141592653589793
py> mathlib.pi = 3.12
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: can't set attribute

There's no _pi accessible that somebody might change. If you dig into the
property object itself, you eventually get to the cell object containing
the value for pi:

py> MathLib.pi.fget.__closure__[0]


but there doesn't appear to be any way to manipulate the cell internals to
change the value. But you don't need to:

py> MathLib.pi = property(lambda self: 4.2)
py> mathlib.pi
4.2


A determined coder can change nearly anything done in pure Python code.

*Personally*, I too would like Python to have some equivalent of (say)
Pascal `const`, names which cannot be rebound once assigned to the first
time. Not to prevent determined coders from changing things, but to avoid
*accidental* changes done in error.



-- 
Steven

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


Re: Question about math.pi is mutable

2015-11-06 Thread Terry Reedy

On 11/6/2015 5:26 PM, Thomas 'PointedEars' Lahn wrote:

Bartc wrote:



import math

math.pi=0

print (math.pi)

In Python, presumably 'pi' is just another variable, and variables can
be written to.


“pi” is the name of an attribute of the module object referred to by “math”.


(Perhaps math.pi would be better off as a function.)


Perhaps not.  Calling a function includes an overhead that one does not want
in already costly floating-point calculations.

In my opinion, mathematical constants should be implemented as constants
(non-overwritable, non-deletable, throwing exceptions when attempting to do
either) but apparently the authors of math.py disagree.


One of multiple discussions of the 'constants' idea.
bugs.python.org/issue1465406
It is mostly about speed.

--
Terry Jan Reedy


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


Re: Question about math.pi is mutable

2015-11-06 Thread Thomas 'PointedEars' Lahn
Thomas 'PointedEars' Lahn wrote:

> In theory, it should be possible to substitute “math” with a reference to
> an object that acts as a proxy for the original “math” module object but
> whose base class declares the attributes for all the constants read-only.

#!/usr/bin/env python3
#---

import importlib

class MyMath(object):
def getter_factory (prop):
def getter (self):
return getattr(importlib.__import__("math", globals(), locals(),
[prop], 0), prop)
return getter

pi = property(getter_factory("pi"), lambda self, val: None,
lambda self: None)
e = property(getter_factory("e"), lambda self, val: None,
lambda self: None)
inf = property(getter_factory("inf"), lambda self, val: None,
lambda self: None)
nan = property(getter_factory("nan"), lambda self, val: None,
lambda self: None)

def __getattr__ (self, name):
return getattr(importlib.__import__("math", globals(), locals(),
[name], 0), name, None)

math = MyMath()

print(math.pi, math.e, math.inf, math.nan)

math.pi = 42
math.e = 42
math.inf = 42
math.nan = 42

print(math.pi, math.e, math.inf, math.nan)
print(math.ceil(2.41))
#---

Using property() instead of decorators here was intended to achieve DRY by 
using a loop, but I could not find a way to define class attributes 
dynamically.  Suggestions?

-- 
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.
-- 
https://mail.python.org/mailman/listinfo/python-list


  1   2   >