[Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Laura Creighton
Any chance of adding Decimal to the list of things that are also
acceptable for things annotated float?

Laura
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Stefan Mihaila

Hey guys,

Could someone clarify for me why it is a good idea to have map return an 
iterator
that is iterable multiple times and acts as an empty iterator in 
subsequent iterations?


> r = range(10)
> list(r) == list(r)
True
> a=map(lambda x:x+1, [1,2,3])
> list(a) == list(a)
False

Wouldn't it be safer for everyone if attempting to traverse some map 
iterator
a second time would just throw a runtime error rather than act as an 
empty iterator? Or am I missing

something obvious?

I understand that chaining functional operators like map/reduce/filter 
is fairly common and
not materializing intermediate computation can improve performance in 
some cases (or even turn infinite
into finite computation), but I also find myself running into 
non-obvious bugs because of this.

Maybe it's just python2 habits, but I assume I'm not the only one
carelessly thinking that "iterating over an input a second time will 
result in the same thing as the first time (or raise an error)".


What would you say is a good practice to avoid accidentally passing the 
result of a map to a function traversing its inputs multiple times?
I assume there needs to be an agreement on these things for larger 
codebases.


Should the caller always materialize the result of a map before passing 
it elsewhere? Or should the callee always materialize its inputs before 
using them?
Or should we just document whether the function traverses its input only 
once, such as through some type annotation
("def f(x: TraversableOnce[T]")? If we refactor `f' such that it used to 
traverse `x' only once, but now traverses it twice, should we

go and update all callers? Would type hints solve this?

More obvious assumption errors, such as "has a method called __len__" 
throw a runtime error thanks to duck typing, but

more subtle ones, such as this one, are harder to express.

Thanks,
Stefan
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread R. David Murray
On Tue, 13 Oct 2015 14:59:56 +0300, Stefan Mihaila  
wrote:
> Maybe it's just python2 habits, but I assume I'm not the only one
> carelessly thinking that "iterating over an input a second time will 
> result in the same thing as the first time (or raise an error)".

This is the way iterators have always worked.  The only new thing is that
in python3 some things that used to be iter*ables* (lists, usually) are
now iter*ators*.  Yes it is a change in mindset *with regards to those
functions* (and yes I sometimes find it annoying), but it is actually
more consistent than it was in python2, and thus easier to generalize
your knowledge about how python works instead of having to remember
which functions work which way.  That is, if you need to iterate it
twice, turn it into a list first.

--David
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Random832
"R. David Murray"  writes:

> On Tue, 13 Oct 2015 14:59:56 +0300, Stefan Mihaila
>  wrote:
>> Maybe it's just python2 habits, but I assume I'm not the only one
>> carelessly thinking that "iterating over an input a second time will 
>> result in the same thing as the first time (or raise an error)".
>
> This is the way iterators have always worked.

It does raise the question though of what working code it would actually
break to have "exhausted" iterators raise an error if you try to iterate
them again rather than silently yield no items.

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Raymond Hettinger

> On Oct 13, 2015, at 4:21 AM, Laura Creighton  wrote:
> 
> Any chance of adding Decimal to the list of things that are also
> acceptable for things annotated float?

>From Lib/numbers.py:

## Notes on Decimal
## 
## Decimal has all of the methods specified by the Real abc, but it should
## not be registered as a Real because decimals do not interoperate with
## binary floats (i.e.  Decimal('3.14') + 2.71828 is undefined).  But,
## abstract reals are expected to interoperate (i.e. R1 + R2 should be
## expected to work if R1 and R2 are both Reals).

That is still true:

Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "copyright", "credits" or "license()" for more information.
>>> from decimal import Decimal
>>> Decimal('3.14') + 2.71828
Traceback (most recent call last):
  File "", line 1, in 
Decimal('3.14') + 2.71828
TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'


Raymond Hettinger

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Zachary Ware
On Tue, Oct 13, 2015 at 10:26 AM, Random832  wrote:
> "R. David Murray"  writes:
>
>> On Tue, 13 Oct 2015 14:59:56 +0300, Stefan Mihaila
>>  wrote:
>>> Maybe it's just python2 habits, but I assume I'm not the only one
>>> carelessly thinking that "iterating over an input a second time will
>>> result in the same thing as the first time (or raise an error)".
>>
>> This is the way iterators have always worked.
>
> It does raise the question though of what working code it would actually
> break to have "exhausted" iterators raise an error if you try to iterate
> them again rather than silently yield no items.

You mean like this?

>>> m = map(int, '1234')
>>> list(m)
[1, 2, 3, 4]
>>> next(m)
Traceback (most recent call last):
  File "", line 1, in 
StopIteration

It just happens that 'list()' and 'for ...' handle StopIteration for you.

-- 
Zach
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread R. David Murray
On Tue, 13 Oct 2015 11:26:09 -0400, Random832  wrote:
> "R. David Murray"  writes:
> 
> > On Tue, 13 Oct 2015 14:59:56 +0300, Stefan Mihaila
> >  wrote:
> >> Maybe it's just python2 habits, but I assume I'm not the only one
> >> carelessly thinking that "iterating over an input a second time will 
> >> result in the same thing as the first time (or raise an error)".
> >
> > This is the way iterators have always worked.
> 
> It does raise the question though of what working code it would actually
> break to have "exhausted" iterators raise an error if you try to iterate
> them again rather than silently yield no items.

They do raise an error: StopIteration.  It's just that the iteration
machinery uses that to stop iteration :).

And the answer to the question is: lots of code.  I've written some:
code that iterates an iterator, breaks that loop on a condition, then
resumes iterating, breaking that loop on a different condition, and so
on, until the iterator is exhausted.  If the iterator restarted at the
top once it was exhausted, that code would break.

--David
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Random832
"R. David Murray"  writes:
> On Tue, 13 Oct 2015 11:26:09 -0400, Random832  wrote:
>> It does raise the question though of what working code it would actually
>> break to have "exhausted" iterators raise an error if you try to iterate
>> them again rather than silently yield no items.
>
> They do raise an error: StopIteration.  It's just that the iteration
> machinery uses that to stop iteration :).

I meant a real error and you know it, both of you. StopIteration is an
exception in the technical sense that it can be raised and caught, but
it's not an error because it is used for normal control flow. In the
plain english meaning of the word, it isn't even an exception.

> And the answer to the question is: lots of code.  I've written some:
> code that iterates an iterator, breaks that loop on a condition, then
> resumes iterating, breaking that loop on a different condition, and so
> on, until the iterator is exhausted.  If the iterator restarted at the
> top once it was exhausted, that code would break

I'm not suggesting restarting at the top (I've elsewhere suggested that
many such methods would be better as an *iterable* that can be restarted
at the top by calling iter() multiple times, but that's not the same
thing). I'm suggesting raising an exception other than StopIteration, so
that this situation can be detected. If you are writing code that tries
to resume iterating after the iterator has been exhausted, I have to
ask: why?

I suppose the answer is the same reason people would deliberately raise
StopIteration in the ways that PEP479 breaks - because it works and is
easy. But that wasn't a reason not to deprecate that.

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Random832
> From Lib/numbers.py:
>
> ## Notes on Decimal
> ## 
> ## Decimal has all of the methods specified by the Real abc, but it should
> ## not be registered as a Real because decimals do not interoperate with
> ## binary floats (i.e.  Decimal('3.14') + 2.71828 is undefined).  But,
> ## abstract reals are expected to interoperate (i.e. R1 + R2 should be
> ## expected to work if R1 and R2 are both Reals).

Why?

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Chris Angelico
On Wed, Oct 14, 2015 at 3:08 AM, Random832  wrote:
> If you are writing code that tries
> to resume iterating after the iterator has been exhausted, I have to
> ask: why?

A well-behaved iterator is supposed to continue raising StopIteration
forever once it's been exhausted. I don't know how much code actually
depends on this, but it wouldn't be hard to make a wrapper that raises
a different exception instead:

class iter:
_orig_iter = iter
def __init__(self, thing):
self.iter = self._orig_iter(thing)
self.exhausted = False
def __iter__(self): return self
def __next__(self):
if self.exhausted: raise RuntimeError("Already exhausted")
try: return next(self.iter)
except StopIteration:
self.exhausted = True
raise

Play with that, and see where RuntimeErrors start coming up. I suspect
they'll be rare, but they will happen.

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Laura Creighton
In a message of Tue, 13 Oct 2015 08:38:07 -0700, Raymond Hettinger writes:
>
>
>> On Oct 13, 2015, at 4:21 AM, Laura Creighton  wrote:
>> 
>> Any chance of adding Decimal to the list of things that are also
>> acceptable for things annotated float?
>
>>From Lib/numbers.py:
>
>## Notes on Decimal
>## 
>## Decimal has all of the methods specified by the Real abc, but it should
>## not be registered as a Real because decimals do not interoperate with
>## binary floats (i.e.  Decimal('3.14') + 2.71828 is undefined).  But,
>## abstract reals are expected to interoperate (i.e. R1 + R2 should be
>## expected to work if R1 and R2 are both Reals).
>
>That is still true:
>
>Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19) 
>[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
>Type "copyright", "credits" or "license()" for more information.
 from decimal import Decimal
 Decimal('3.14') + 2.71828
>Traceback (most recent call last):
>  File "", line 1, in 
>Decimal('3.14') + 2.71828
>TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'
>
>
>Raymond Hettinger

I take it that is a 'no'.  I merely worry about what hapens if people
start relying upon the fact that a float annotation 'will handle all
the numbers I care about' to the forgotten Decimal users such as
myself.

Laura
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Random832
Chris Angelico  writes:
> A well-behaved iterator is supposed to continue raising StopIteration
> forever once it's been exhausted.

Yes, and that is *precisely* the behavior that causes the problem under
discussion. My question was what code depends on this.

> Play with that, and see where RuntimeErrors start coming up. I suspect
> they'll be rare, but they will happen.

My theory is that most circumstances under which this would cause a
RuntimeError are indicative of a bug in the algorithm consuming the
iterator (for example, an algorithm that hasn't considered iterators and
expects to be passed an iterable it can iterate from the top more than
once), rather than the current behavior being relied on to produce
the intended end result.

This is essentially the same argument as PEP 479 - except there it was
at least *easy* to come up with code which would rely on the old
behavior to produce the intended end result.

About the only example I can think of is that the implementation of
itertools.zip_longest would have to change.

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Chris Angelico
On Wed, Oct 14, 2015 at 3:49 AM, Random832  wrote:
> My theory is that most circumstances under which this would cause a
> RuntimeError are indicative of a bug in the algorithm consuming the
> iterator (for example, an algorithm that hasn't considered iterators and
> expects to be passed an iterable it can iterate from the top more than
> once), rather than the current behavior being relied on to produce
> the intended end result.
>
> This is essentially the same argument as PEP 479 - except there it was
> at least *easy* to come up with code which would rely on the old
> behavior to produce the intended end result.

Yeah. Hence my suggestion of a quick little replacement for the iter()
function (though, on second reading of the code, I realise that I
forgot about the two-arg form; changing 'thing' to '*args' should fix
that though) as a means of locating the actual cases where that
happens.

Hmm. Actually, this kinda breaks if you call it multiple times.
Calling iter() on an iterator should return itself, not a wrapper
around self. So, new version:

class iter:
_orig_iter = iter
def __new__(cls, *args):
if len(args)==1 and isinstance(args[0], cls):
# It's already a wrapped iterator. Return it as-is.
return args[0]
return super().__new__(cls)
def __init__(self, *args):
if hasattr(self, "iter"): return # Don't rewrap
self.iter = self._orig_iter(*args)
self.exhausted = False
def __iter__(self): return self
def __next__(self):
if self.exhausted: raise RuntimeError("Already exhausted")
try: return next(self.iter)
except StopIteration:
self.exhausted = True
raise

I don't have any code of mine that would be broken by this
implementation of iter(). Doesn't mean it isn't buggy in ways I
haven't spotted, though. :)

ChrisA
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Chris Jerdonek
On Tue, Oct 13, 2015 at 8:26 AM, Random832  wrote:
> "R. David Murray"  writes:
>
>> On Tue, 13 Oct 2015 14:59:56 +0300, Stefan Mihaila
>>  wrote:
>>> Maybe it's just python2 habits, but I assume I'm not the only one
>>> carelessly thinking that "iterating over an input a second time will
>>> result in the same thing as the first time (or raise an error)".
>>
>> This is the way iterators have always worked.
>
> It does raise the question though of what working code it would actually
> break to have "exhausted" iterators raise an error if you try to iterate
> them again rather than silently yield no items.

What about cases where not all of the elements of the iterator are
known at the outset?  For example, you might have a collection of
pending tasks that you periodically loop through and process.
Changing the behavior would result in an error when checking for more
tasks instead of no tasks.

--Chris
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Sven R. Kunze

On 13.10.2015 17:38, Raymond Hettinger wrote:

Traceback (most recent call last):
   File "", line 1, in 
 Decimal('3.14') + 2.71828
TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'


Reminds me of 'int' and 'long'. Different but almost the same.

Best,
Sven
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread R. David Murray
On Tue, 13 Oct 2015 12:08:12 -0400, Random832  wrote:
> "R. David Murray"  writes:
> > On Tue, 13 Oct 2015 11:26:09 -0400, Random832  
> > wrote:
> >
> > And the answer to the question is: lots of code.  I've written some:
> > code that iterates an iterator, breaks that loop on a condition, then
> > resumes iterating, breaking that loop on a different condition, and so
> > on, until the iterator is exhausted.  If the iterator restarted at the
> > top once it was exhausted, that code would break
> 
> I'm not suggesting restarting at the top (I've elsewhere suggested that
> many such methods would be better as an *iterable* that can be restarted
> at the top by calling iter() multiple times, but that's not the same
> thing). I'm suggesting raising an exception other than StopIteration, so
> that this situation can be detected. If you are writing code that tries
> to resume iterating after the iterator has been exhausted, I have to
> ask: why?

Because the those second &c loops don't run if the iterator is already
exhausted, the else clause is executed instead (or nothing happens,
depending on the code).

Now, likely such code isn't common (so I shouldn't have said "lots"),
but the fact that I've done it at least once, maybe twice (but I can't
remember what context, it was a while ago), argues it isn't vanishingly
uncommon.

--David
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Terry Reedy

On 10/13/2015 7:59 AM, Stefan Mihaila wrote:


Could someone clarify for me ...


This list, pydev, short for 'python development', is for discussing 
development of future releases of CPython.  Your question should have 
been directed to python-list, where it would be entirely on topic.



--
Terry Jan Reedy

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Steven D'Aprano
On Tue, Oct 13, 2015 at 11:26:09AM -0400, Random832 wrote:
> "R. David Murray"  writes:
> 
> > On Tue, 13 Oct 2015 14:59:56 +0300, Stefan Mihaila
> >  wrote:
> >> Maybe it's just python2 habits, but I assume I'm not the only one
> >> carelessly thinking that "iterating over an input a second time will 
> >> result in the same thing as the first time (or raise an error)".
> >
> > This is the way iterators have always worked.
> 
> It does raise the question though of what working code it would actually
> break to have "exhausted" iterators raise an error if you try to iterate
> them again rather than silently yield no items.

Anything which looks like this:


for item in iterator:
if condition: 
break
do_this()
...
for item in iterator:
do_that()


If the condition is never true, the iterator is completely processed by 
the first loop, and the second loop is a no-op by design.

I don't know how common it is, but I've written code like that.

Had we been designing the iterator protocol from scratch, perhaps we 
might have had two exceptions:

class EmptyIterator(Exception): ...
class StopIteration(EmptyIterator): ...

and have StopIteration only raised the first time you call next() on an 
empty iterator. But would it have been better? I don't know. I suspect 
not. I think that although it might avoid a certain class of errors, it 
would add complexity to other situations which are currently simple.


-- 
Steve
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Raymond Hettinger

> On Oct 13, 2015, at 9:16 AM, Random832  wrote:
> 
>> ## 
>> ## Decimal has all of the methods specified by the Real abc, but it should
>> ## not be registered as a Real because decimals do not interoperate with
>> ## binary floats (i.e.  Decimal('3.14') + 2.71828 is undefined).  But,
>> ## abstract reals are expected to interoperate (i.e. R1 + R2 should be
>> ## expected to work if R1 and R2 are both Reals).
> 
> Why?

Q.  Why is Python the way it is?
A.   Because Guido said so ;-)

IIRC, the answer is that we were being conservative with possibly unintended 
operations between types with differing precision and with differing notions of 
what numbers could be exactly representable.

We could have (and still could) make the choice to always coerce to decimal 
(every float is exactly representable in decimal).  Further, any decimal float 
or binary float could be losslessly coerced to a Fraction, but that probably 
isn't what you really want most of the time.  I think people who work in 
decimal usually want to stay there and people who work with binary floating 
point want to stay there as well (invisible coercions being more likely to 
cause pain than relieve pain).


Raymond


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Rationale behind lazy map/filter

2015-10-13 Thread Graham Gower
On 14 October 2015 at 09:59, Steven D'Aprano  wrote:
> On Tue, Oct 13, 2015 at 11:26:09AM -0400, Random832 wrote:
>> "R. David Murray"  writes:
>>
>> > On Tue, 13 Oct 2015 14:59:56 +0300, Stefan Mihaila
>> >  wrote:
>> >> Maybe it's just python2 habits, but I assume I'm not the only one
>> >> carelessly thinking that "iterating over an input a second time will
>> >> result in the same thing as the first time (or raise an error)".
>> >
>> > This is the way iterators have always worked.
>>
>> It does raise the question though of what working code it would actually
>> break to have "exhausted" iterators raise an error if you try to iterate
>> them again rather than silently yield no items.
>
> Anything which looks like this:
>
>
> for item in iterator:
> if condition:
> break
> do_this()
> ...
> for item in iterator:
> do_that()
>
>
> If the condition is never true, the iterator is completely processed by
> the first loop, and the second loop is a no-op by design.
>
> I don't know how common it is, but I've written code like that.
>

I wrote code like this yesterday, to parse a file where there were
multiple lines of one type of data, followed by multiple lines of
another type of data.

I can think of more complex examples including two (or more) iterators
where one might reasonably do similar things. E.g. file 1 contains
data, some of which is a subset of data in file 2, both of which are
sorted. And during parsing, one wishes to match up the common
elements.

-Graham
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Steven D'Aprano
On Tue, Oct 13, 2015 at 04:37:43PM -0700, Raymond Hettinger wrote:

> We could have (and still could) make the choice to always coerce to 
> decimal (every float is exactly representable in decimal).  Further, 
> any decimal float or binary float could be losslessly coerced to a 
> Fraction, but that probably isn't what you really want most of the 
> time.  I think people who work in decimal usually want to stay there 
> and people who work with binary floating point want to stay there as 
> well (invisible coercions being more likely to cause pain than relieve 
> pain).

Further to what Raymond says, if anyone wants to persue this further, 
and wants to argue for such automatic promotion of float to Decimal (or 
vice versa), I think a good place to start would be a survey of other 
languages with a numeric tower. How do they handle similar situations?


-- 
Steve
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Random832
Steven D'Aprano  writes:

> On Tue, Oct 13, 2015 at 04:37:43PM -0700, Raymond Hettinger wrote:
>
>> We could have (and still could) make the choice to always coerce to 
>> decimal (every float is exactly representable in decimal).  Further, 
>> any decimal float or binary float could be losslessly coerced to a 
>> Fraction, but that probably isn't what you really want most of the 
>> time.  I think people who work in decimal usually want to stay there 
>> and people who work with binary floating point want to stay there as 
>> well (invisible coercions being more likely to cause pain than relieve 
>> pain).
>
> Further to what Raymond says, if anyone wants to persue this further, 
> and wants to argue for such automatic promotion of float to Decimal (or 
> vice versa), I think a good place to start would be a survey of other 
> languages with a numeric tower. How do they handle similar situations?

I believe that in Scheme (which AIUI is where the term "numeric tower"
comes from) has a notion of "exact" and "inexact" numbers. A "flonum"
(float) would be an inexact number. And any operation between exact and
inexact numbers (including e.g. min and max, even if the exact number
wins) gives an inexact result.

A Decimal, though, could be regarded as an exact number (a special kind
of rational) or an inexact number (another kind of floating point). I
suspect some people who use them intend them one way and others intend
the other (especially since Fraction lacks a good way to format the
value in decimal notation).

If they are both inexact, then it doesn't much matter which one they're
promoted to, since they're both implementation details of the abstract
type "inexact real number". AIUI many implementations don't *actually*
have any other implementations of "inexact real number" except flonum,
and those that do just have them as a rational fraction with an
"inexact" flag set, but the spec does allow it.

Implementing a scheme-style exact/inexact numeric tower also suggests
more ABCs.

___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Chris Barker - NOAA Federal
 I merely worry about what happens if people
> start relying upon the fact that a float annotation 'will handle all
> the numbers I care about' to the forgotten Decimal users such as
> myself.

Well, that's what you get in exchange for "type safety".

Which is exactly why I'm concerned about widespread use of type
annotations. Might as well use a static language :-(

- CHB



>
> Laura
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: 
> https://mail.python.org/mailman/options/python-dev/chris.barker%40noaa.gov
___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 0484 - the Numeric Tower

2015-10-13 Thread Stephen J. Turnbull
Chris Barker - NOAA Federal writes:
 > Laura Creighton writes:

 > > I merely worry about what happens if people
 > > start relying upon the fact that a float annotation 'will handle all
 > > the numbers I care about' to the forgotten Decimal users such as
 > > myself.
 > 
 > Well, that's what you get in exchange for "type safety".

AIUI, the point of type annotations is that some use cases benefit *a
lot* from machine-parsable type information, not that type annotation
is a universally good idea in itself.  It's not type *safety* that's
the aim here.  It's type *auditability*.  If it were about "safety",
annotations would be in the interpreter, not in a separate, optional
application.

 > Which is exactly why I'm concerned about widespread use of type
 > annotations. Might as well use a static language :-(

No, no way would this satisfy static typing advocates.  Optional,
remember?

In Python, widespread use of type annotations that messes up Decimal
users would be un-Pythonic (infringes the "consenting adults"
principle).

Yes, Laura is going to run into modules that functions that have a
"float" or "Real" annotation that will complain about Decimal when
Decimal works perfectly well in that function.  Not everybody will use
annotations according to BDFL Original Intent.  But if perfectly
normal usage of Decimal or whatever runs into type annotation abuse,
and you can't simply refuse to run the type checker, I will bet that
Guido himself will be your champion.[1]

Footnotes: 
[1]  I'm not channeling anybody here, that's a statement of my
personal assessment of the real risk.  And of course it may have no
effect on the developers who use type annotations in that way, but
this is no different from any other hard to work around programming
practice.


___
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com