Re: [Python-Dev] Adventures with Decimal

I'd like to respond to a few people, I'll start with Greg Ewing: Greg writes:
I don't see how it helps significantly to have just the very first step -- turning the input into numbers -- be exempt from this behaviour. If anything, people are going to be even more confused. "But it can obviously cope with 1.1000000000000000001, so why does it give the wrong answer when I add something to it?"
As I see it, there is a meaningful distinction between constructing Decimal instances and performing arithmatic with them. I even think this distinction is easy to explain to users, even beginners. See, it's all about the program "doing what you tell it to". If you type in this: x = decimal.Decimal("1.100000000000000000000000000003") as a literal in your program, then you clearly intended for that last decimal place to mean something. By contrast, if you were to try passing a float to the Decimal constructor, it would raise an exception expressly to protect users from "accidently" entering something slightly off from what they meant. On the other hand, in Python, if you type this: z = x + y then what it does is completely dependent on the types of x and y. In the case of Decimal objects, it performs a "perfect" arithmetic operation then rounds to the current precision. The simple explanation for users is "Context affects *operations*, but not *instances*." This explains the behavior of operations, of constructors, and also explains the fact that changing precision doesn't affect the precision of existing instances. And it's only 6 words long.
But I also found it interesting that, while the spec requires the existence of a context for each operation, it apparently *doesn't* mandate that it must be kept in a global variable, which is the part that makes me uncomfortable.
Was there any debate about this choice when the Decimal module was being designed?
It shouldn't make you uncomfortable. Storing something in a global variable is a BAD idea... it is just begging for threads to mess each other up. The decimal module avoided this by storing a SEPARATE context for each thread, so different threads won't interfere with each other. And there *is* a means for easy access to the context objects... decimal.getcontext(). Yes, it was debated, and the debate led to changing from a global variable to the existing arrangement. ------ As long as I'm writing, let me echo Nick Coghlan's point:
The fact that the BDFL (and others, me included) were at least temporarily confused by the ability to pass a context in to the constructor suggests there is an interface problem here.
The thing that appears to be confusing is that you *can* pass a context in to the Decimal constructor, but that context is then almost completely ignored.
Yeah... I agree. If you provide a Context, it should be used. I favor changing the behavior of the constructor as follows: def Decimal(data, context=None): result = Existing_Version_Of_Decimal(data) if context is None: result = +result return result In other words, make FULL use of the context in the constructor if a context is provided, but make NO use of the thread context when no context is provided. ------ One final point... Thanks to Mike Cowlishaw for chiming in with a detailed and well-considered explanation of his thoughts on the matter. -- Michael Chermside
participants (1)
-
Michael Chermside