re: Types and true division (was Re: strange output)
Indeed, Art, I'm sick and tired of you.
And I, believe or not, truly wish that weren't so.
You did not respond to my explanation of the division change using the substitutibility rule. It's a technical issue, whether or not you understand it.
I did, in effect. By stating on a number of occasions that I understand that the issue goes beyond the first take of the non-programmer. Have you responding in any serious way to my point about a potentially harmeful side effect. In the year over which this has been discussed. Is my point that fundamenatlly unworthy of reply? The form of your replies and non-replies indicates a position that it is. I respectfully disagree. Did *you* learn to program with Python? Art
Indeed, Art, I'm sick and tired of you.
And I, believe or not, truly wish that weren't so.
That makes two of us.
You did not respond to my explanation of the division change using the substitutibility rule. It's a technical issue, whether or not you understand it.
I did, in effect. By stating on a number of occasions that I understand that the issue goes beyond the first take of the non-programmer.
But do you understand the issue of substitutability?
Have you responding in any serious way to my point about a potentially harmeful side effect. In the year over which this has been discussed.
And what would that side effect be? What's the benefit of 1/2==0?
Is my point that fundamenatlly unworthy of reply? The form of your replies and non-replies indicates a position that it is.
You rarely rise above talking about your emotions on the issue, which makes it impossible to have a reasonable discussion.
I respectfully disagree.
Did *you* learn to program with Python?
Can you rephrase that as a direct question (or comment) instead of sarcasm? --Guido van Rossum (home page: http://www.python.org/~guido/)
I appreciate the opportunity to respond further. But we need to try to understand and find some tolerance for the different languages with which we speak about these issues. Understand that I am the first to admit that I have nothing to contribute to these kinds of conversations from a technical point of view. But learning to program, and learning to program in particular with Python, is an experience. That experience - and what I've taken (so far) from it - is one that I am not only prepared, but it seems, anxious, to talk about. And like many, I feel that you anticipate that experience amazing well. The word "fun" always rightfully crops up in a discussion about the Python experience. That I have and have had fun with it is nothing unusual. But perhaps there is a little bit unusual with how "ground zero" was my starting point, and how far I've come. Only because Python is still young. Others have and I trust and hope many others will share that experience in the future.
And what would that side effect be? What's the benefit >of 1/2==0?
Provides the signal and the reminder of the importance of giving attention to the underlying numeric typing scheme. Not a complicated or brilliant point. But real, experientially, IMO. Art
[Arthur] >>> Arthur write: >>> Have you responding in any serious way to my point about a >>> potentially harmeful side effect. In the year over which this has >>> been discussed. [Guido] >> And what would that side effect be? What's the benefit >of 1/2==0? [Arthur] > > Provides the signal and the reminder of the importance of giving attention > to the underlying numeric typing scheme. Not a complicated or brilliant > point. But real, experientially, IMO. I can only presume that you also opposed 2**1024 returning a long rather than raising an error and dictionary iteration for the same reason. With respect to your experience that may be a real point. With respect to language design it seems totally inane. Ceiling tiles falling on my head might remind me that I need regular building maintenance and my engine locking up might remind me that I need oil changes, but that's no reason to design a building so that ceiling tiles fall more quickly or cars to be less tolerant to operator abuse. I don't understand how getting what you want instead of an error could be considered a 'potentially harmful side effect' of a language change. It seems like the logical extension of this theory is that we should make compilers illegal so that people will be spared the agony of not understanding parallel execution, stack tables, and register reuse. -- Christopher A. Craig <list-python-edu@ccraig.org> The memory management on the PowerPC can be used to frighten small children. - Linus Torvalds
[Arthur] >>> Arthur write: >>> Have you responding in any serious way to my point about a >>> potentially harmeful side effect. In the year over which this has >>> been discussed. [Guido] >> And what would that side effect be? What's the benefit >of 1/2==0? [Arthur] > > Provides the signal and the reminder of the importance of giving attention > to the underlying numeric typing scheme. Not a complicated or brilliant > point. But real, experientially, IMO.
I can only presume that you also opposed 2**1024 returning a long rather than raising an error and dictionary iteration for the same reason.
No comprenda. (Isn't it a *little* refreshing to have someone say that so candidly on these lists?) But I would say it is a *significant* no comprenda. Apparently I have not *experienced* the issues you raise as sigifcant - yet. But I take the point that you disagree with me. And I believe that Michael Williams is willingly to acknowledge that as much as he might dislike with my tone of voice, in the end we have little more than a small disagreement about emphasis. But if you were prefer to conclude that I am talking total nonsense - your privilege. Why do you think Python was let out into the world this fundamentally broken, if the issue is as obvious as all that? Art
At 12:14 PM 10/10/2002 -0400, Arthur wrote:
And what would that side effect be? What's the benefit >of 1/2==0?
Provides the signal and the reminder of the importance of giving attention to the underlying numeric typing scheme. Not a complicated or brilliant point. But real, experientially, IMO.
Art
dir('__builtins__') which'd then give you a long alphabetized list of 57 functions, many having to do with strings. Just seeing copy (and deepcopy?) among
I don't find this on-the-face-of-it persuasive, as then any counter-intuitive wrinkle X in any language (any "wart") could be justified as "reminding the newbie to give attention to X". Let's just admit that *any* language, out of the box, is going to contain a number of "gotchas" -- things that regularly confuse newbies and occasionally even bite a seasoned programmer on the butt. Then the question is whether these gotchas are unnecessary quirks, our essential characteristics that make it *worth a newbie's while* to bang his or her head against a few times. In the case of copy(), I'd say we're dealing with an essential characteristic: Python uses referents to objects, and to assign a name is to hand one end of a string to a label (a variable name), where the other end of the string attaches to a place in memory which houses the object itself. When you go x = obj(); y = x, you're giving another string to y, but both y and x have the *same* fish on the end of their respective hooks. Now you're saying: by including copy() as a built-in, you'd signify to the newbie that there's something deeply necessary about having copy() in the picture. Apparently x = y isn't going to do the job. And you're saying, by having 2/3 return 0, you're likewise cluing the newbie to something deep: number types. However, it presumes a lot of a newbie that they'd be able to deduce anything deep from the presence of copy(). Indeed, few newbies even realize there's a way to dump a list of builtin functions to the screen, as dir() returns ['__builtins__', '__doc__', '__name__'] You'd have to already know enough to go: those 57 (now 59) would be unlikely to trigger some involved thought process about the name/object model in Python. That's entirely a retrospective view, i.e. you have to *already know* these basics to muse to yourself about the importance of copy(). Of course you may be presuming that we're using some tutorial, which takes us through the built-ins. But if that's the case, then this same tutorial could be about drumming home the name/object model, and the importance of copy() could be leveraged to drum home the essentiality of *importing* to Python, i.e. "the ability to copy or clone an object is critical in some situations, yet for generic objects, this ability must be imported". In other words, we can turn your argument around and say *not* including copy() reminds the newbie that knowing how to import is absolutely critical to getting full functionality -- the built-in stuff is *not* going to get you everything you need (no built-in trig either, which all those physics students will definitely need). About div, the technical point is that all the operators *except* div, return very close to equivalent answers, even if the types differ. In this sense, it matters less for + - and * whether the arguments are floats, longs or integers. Since there're no explicit type declarations in Python (as there are in C, from which the original div behavior derives), just eyeballing code is *not* necessarily going to make div's behavior unambiguous, even if you're a pro. So in this case, I'd say we're dealing with a "gotcha" that it doesn't pay to beat your head against. It's still a problem even after you master it -- when reading others' code (don't always think about what it's like to read and understand your own). Going to / and // makes division unambiguous again. The former forces a floating point treatment, the latter an integer treatment. An interesting question, to me, is how a built-in rational number type might fit into this scheme. As I understand the current PEP, we're looking at again altering / such that it returns a rational type in some circumstances. My suggestion is that we follow J's example and use lowercase 'r' (or some other letter) as part of the name of a rational, just as we use 1e1 to name a float. Then, have / return a rational if and only if both arguments are rationals, otherwise stick to the planned behavior of returning a float. This would preserve pre-existing code and make rationals phase in without much disruption. Plus we're not going back to "ambiguous results" because the rational result, though of a different "type", would be essentially equivalent to the corresponding floating type return value. In other words 3/2 returns 1.5 or, if a=rat(3) and b=rat(2), then a/b returns 3r2, and float(3r2) returns 1.5 Kirby
Student Z from from Planet Y has just installed Python over IGSL [Inter Galactic Subscriber Lines]. They might at first be a little confused...
1 / 2 0 help(/) SyntaxError: invalid syntax help("/") no Python documentation found for '/' 1 / 2.0 0.5
Python always has deeply considered, intelligent reasons for doing everything it does. So what can we do to make visitors from Planet Y feel more welcome ? More examples..
/ SyntaxError: invalid syntax * SyntaxError: invalid syntax + SyntaxError: invalid syntax - SyntaxError: invalid syntax
Since typing a command function alone like is obviously not 'pragramming', why not just return some help about each function? This need not disturb Python's design philosphy and decisions, but, simply a serious proposal to provide valuable common sense help at the beginning and when the context is in no doubt. Are there good Pythonic reasons was this can or should not be done? ./Jason
Are there good Pythonic reasons was this can or should not be done?
It never occurred to me that you would not have the tutorial handy. --Guido van Rossum (home page: http://www.python.org/~guido/)
[Kirby]
Going to / and // makes division unambiguous again. The former forces a floating point treatment, the latter an integer treatment.
An interesting question, to me, is how a built-in rational number type might fit into this scheme. As I understand the current PEP, we're looking at again altering / such that it returns a rational type in some circumstances.
That's not my (current) preference.
My suggestion is that we follow J's example and use lowercase 'r' (or some other letter) as part of the name of a rational, just as we use 1e1 to name a float.
Right.
Then, have / return a rational if and only if both arguments are rationals, otherwise stick to the planned behavior of returning a float.
Exactly.
This would preserve pre-existing code and make rationals phase in without much disruption. Plus we're not going back to "ambiguous results" because the rational result, though of a different "type", would be essentially equivalent to the corresponding floating type return value. In other words 3/2 returns 1.5 or, if a=rat(3) and b=rat(2), then a/b returns 3r2, and float(3r2) returns 1.5
Except I don't like the 3r2 notation very much. In my version it would become 3/2r, or 3r/2; parsed as 3 / 2r and 3r / 2, respectively. And I'd also support 1.5r as a way to spell the same value. --Guido van Rossum (home page: http://www.python.org/~guido/)
At 02:36 PM 10/10/2002 -0400, Guido van Rossum wrote:
Except I don't like the 3r2 notation very much. In my version it would become 3/2r, or 3r/2; parsed as 3 / 2r and 3r / 2, respectively.
Not clear if you mean 3r is by itself a rational (=3/1) as in:
a = 3r a/2r 3/2
or would that be 3/2r ? Entering 3r/2 on a command line looks to me like an invocation of division between a rational (3r) and an integer (2), and so would return 1.5 (float), i.e.
3r/2 1.5
And I'd also support 1.5r as a way to spell the same value.
Makes sense. I get confused when I try to see / used both as an operator, and as part of the name of a number. Not sure if that's what you're doing. Would you go:
1.5 .__rational__() 3/2r 3/2r .__float__() 1.5
Perhaps you could do a short dialog in Python along the lines of: >>> a = 3r2 >>> b = 1r2 >>> a * b 3r4 >>> float(a*b) 0.75 >>> a + 2 5r2 >>> a / 2 3r4 showing how it'd look in your implementation. Note: I'm deviating from the policy that rat / int --> float in the last line. Not sure if this is a good idea. Maybe: int / int --> float (float//float --> int) float / int --> float (int//int --> int) rat / int --> rat (?) (rat//rat --> int) rat / float --> float rat / rat --> rat In other words, maybe it makes sense for / to coerce an int or a long into a rat if the other arg is a rat. This wouldn't break code, as rat is a new type that couldn't get created by old pre-rat code. Coercion: rat(3.1) --> 31/10r (?) rat(2) --> 2r float(2/3r) --> 0.66666666666666663 rat() or rational() ? Kirby
Except I don't like the 3r2 notation very much. In my version it would become 3/2r, or 3r/2; parsed as 3 / 2r and 3r / 2, respectively.
Not clear if you mean 3r is by itself a rational (=3/1)
Yes.
as in:
a = 3r a/2r 3/2
or would that be 3/2r ?
It would probably print that, yes.
Entering 3r/2 on a command line looks to me like an invocation of division between a rational (3r) and an integer (2), and so would return 1.5 (float), i.e.
3r/2 1.5
Why? A binary operator involving an int or long and a rational should return a rational, IMO -- the int or long can always be cast to rational, and the result is exact.
And I'd also support 1.5r as a way to spell the same value.
Makes sense.
I get confused when I try to see / used both as an operator, and as part of the name of a number. Not sure if that's what you're doing.
You can see it either way and it doesn't make any difference for the outcome. Just like we write negative numbers as -3 which is technically the minus operator applied to the positive constant 3, or complex constants as 2+1j which is technically a float constant plus an irrational constant.
Would you go:
1.5 .__rational__() 3/2r
I'm not sure I'd like to add __rational__ to all numeric types to convert things into rationals. I'm also not sure that converting arbitrary floats to rationals should be a standard conversion.
3/2r .__float__() 1.5
Definitely, but please write that as float(3/2r).
Perhaps you could do a short dialog in Python along the lines of:
>>> a = 3r2 >>> b = 1r2 >>> a * b 3r4 >>> float(a*b) 0.75 >>> a + 2 5r2 >>> a / 2 3r4
showing how it'd look in your implementation.
I have no implementation. :-) But it would look like this:
a = 3/2r b = 1/2r a * b (3/2r) float(a*b) 0.75 a + 2 (5/2r) a / 2 3/4r
(I'm not sure about the parens, but complex uses them in a similar situation.)
Note: I'm deviating from the policy that rat / int --> float in the last line. Not sure if this is a good idea. Maybe:
int / int --> float (float//float --> int) float / int --> float (int//int --> int) rat / int --> rat (?) (rat//rat --> int) rat / float --> float rat / rat --> rat
Exactly. int/rat should also be a rat.
In other words, maybe it makes sense for / to coerce an int or a long into a rat if the other arg is a rat. This wouldn't break code, as rat is a new type that couldn't get created by old pre-rat code.
Right.
Coercion:
rat(3.1) --> 31/10r (?)
I don't like this, but maybe it's okay. It's up to the rat() constructor though, the float needn't know anything about this.
rat(2) --> 2r float(2/3r) --> 0.66666666666666663
Right.
rat() or rational() ?
I think rat() is good -- after all I shortened 'dictionary' to 'dict'... --Guido van Rossum (home page: http://www.python.org/~guido/)
I have no implementation. :-)
You mean there's more to it than just imagining what goes on at the command line? :-D
But it would look like this:
a = 3/2r b = 1/2r a * b (3/2r) float(a*b) 0.75 a + 2 (5/2r) a / 2 3/4r
OK, this is clear. Personally I like 3/2r better than 3r/2. It's as if the r keeps the / from operating -- as long as we're in lowest terms, e.g. I assume you'd go: >>> 4/8r (1/2r) The only thing that nags is using two symbols instead of one to signify a type. Complex (1j1) and float (1e1) get away with one symbol, which is why 3r2 was somewhat appealing (but the r tends to get lost).
(I'm not sure about the parens, but complex uses them in a similar situation.)
Note: I'm deviating from the policy that rat / int --> float in the last line. Not sure if this is a good idea. Maybe:
int / int --> float (float//float --> int) float / int --> float (int//int --> int) rat / int --> rat (?) (rat//rat --> int) rat / float --> float rat / rat --> rat
Exactly. int/rat should also be a rat.
Yes, in retrospect this is clear to me.
In other words, maybe it makes sense for / to coerce an int or a long into a rat if the other arg is a rat. This wouldn't break code, as rat is a new type that couldn't get created by old pre-rat code.
Right.
Coercion:
rat(3.1) --> 31/10r (?)
I don't like this, but maybe it's okay. It's up to the rat() constructor though, the float needn't know anything about this.
In J, there's number-naming using p and x where 1p2 means 1*math.pi**2 (translating to Python) and 1x3 means 1*math.e**3. So 1p1 is just math.pi. x: is the operator for converting to rational (like rat(n)), and you get the following: x: 1p1 NB. = rat(math.pi) 1285290289249r409120605684 x: 1x1 NB. = rat(math.e) 6157974361033r2265392166685 I find that interesting, even if Python chooses not to go there.
rat(2) --> 2r float(2/3r) --> 0.66666666666666663
Right.
rat() or rational() ?
I think rat() is good -- after all I shortened 'dictionary' to 'dict'...
rat() sounds good. I suppose fract() would be another option, but of course math purists (and I suppose computer scientists) prefer "rational numbers" to "fractions" as the name of the number type. Kirby
"Kirby Urner" <urnerk@qwest.net> writes:
The only thing that nags is using two symbols instead of one to signify a type. Complex (1j1) and float (1e1) get away with one symbol, which is why 3r2 was somewhat appealing (but the r tends to get lost).
Technically, you're only using one symbol. You could specify a rational with an integral value with just 'r'. I should have a reference implementation that does this on Sourceforge by next Tuesday. -- Christopher A. Craig <list-python@ccraig.org> "Parity is for farmers." Seymour Cray on his machines lack of parity "I guess farmers buy a lot of computers." Seymour Cray on including parity
At 09:52 AM 10/11/2002 -0400, Christopher A. Craig wrote:
"Kirby Urner" <urnerk@qwest.net> writes:
The only thing that nags is using two symbols instead of one to signify a type. Complex (1j1) and float (1e1) get away with one symbol, which is why 3r2 was somewhat appealing (but the r tends to get lost).
Technically, you're only using one symbol. You could specify a rational with an integral value with just 'r'.
You could, if there's only a numerator, as in 2r. But 3/2r contains two symbols signifying type, whereas 3r2 contains only one. I feel I can live with either option. 3r/2 I don't really like, but I see it as an operation rat/int returning 3/2r or (3/2)r or something (I like the r as the final symbol in the number name, as L used to be for longs). Kirby
"Kirby Urner" <urnerk@qwest.net> writes:
(I like the r as the final symbol in the number name, as L used to be for longs).
Kirby
It's my understanding that that is exactly what Guido is proposing. He is, I believe, proposing that the regular expression ([0-9]*)r define a rational number with the integral value of the parenthesized group. So, much like present CPython where -3 actually defines the integer three and then negates it and 1+2j defines the integer 1 and the complex (0+2j) and adds them, 3/2r would define the integer 3 and the rational (2/1)r and then divide them to get (3/2)r (This could, of course, be optimized to a real definition by a different/future compiler). -- Christopher A. Craig <list-python@ccraig.org> "It's the one thing I understand, I guess." Bill Gates, about BASIC
At 02:10 PM 10/11/2002 -0400, Christopher A. Craig wrote:
"Kirby Urner" <urnerk@qwest.net> writes:
(I like the r as the final symbol in the number name, as L used to be for longs).
Kirby
It's my understanding that that is exactly what Guido is proposing.
OK, so I think we're on the same page then. It's still two extra symbols (both / and r) vs. one (r) to write 1/2r versus 1r2, and it takes even more symbols to write (1/2)r. I like J's economy, but I can see 1/2r as a very viable alternative. As you say, it has much in common with 1+2j, where you need both + and j (two symbols) to signify complex. An argument for 1r2 is that 1e2 sets a precedent. But 1j2 is not legal in Python, as it is in J, so the consistency is shakier (not as *much* precedent). Another point: With longs, I can use either upper or lower case l, which isn't so readable in code, as lowercase l looks like 1. But r and R are clearly not numbers. So I assume the following would likewise be legal: >>> 1/2R (1/2)r or maybe that's 1/2r -- not sure which. Kirby
I know this isn't the place for this, but the conversation is a lot of fun. If I were creating a canonical form for input-output, it would be based around <simple-rational> ::= <simple-non-rational-numeral>R | <simple-non-rational-numeral>r <rational-numeral> ::= <simple-rational> | <simple-rational> / <simple-non-rational-numeral> where the "/..." part is optional and one might even relax the denominator <simple-non-rational-numeral> constraint in an input stream. Note that 1.5e-3r/17 would be a valid input, but the canonical output of its value is more likely to be "3r/34000". In expressions, the "/" would just be a "/" and everything works as expected for "/". -- orcmid ------------------ Dennis E. Hamilton http://NuovoDoc.com/ mailto:dennis.hamilton@acm.org tel. +1-206-932-6970 cell +1-206-779-9430 The Miser Project: http://miser-theory.info/ AIIM DMware: http://DMware.info/ -----Original Message----- From: edu-sig-admin@python.org [mailto:edu-sig-admin@python.org]On Behalf Of Kirby Urner Sent: Friday, October 11, 2002 11:24 To: Christopher A. Craig Cc: edu-sig@python.org Subject: Re: [Edu-sig] Re: rationals [ ... ] I like J's economy, but I can see 1/2r as a very viable alternative. As you say, it has much in common with 1+2j, where you need both + and j (two symbols) to signify complex. An argument for 1r2 is that 1e2 sets a precedent. But 1j2 is not legal in Python, as it is in J, so the consistency is shakier (not as *much* precedent). Another point: With longs, I can use either upper or lower case l, which isn't so readable in code, as lowercase l looks like 1. But r and R are clearly not numbers. So I assume the following would likewise be legal: >>> 1/2R (1/2)r or maybe that's 1/2r -- not sure which. Kirby _______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
[Apologies if this rational number issue is a dead horse; I've just joined the discussions recently. I've included some possible thoughts about perception from novice users. -Doug] Guido van Rossum wrote:
rat() or rational() ?
I think rat() is good -- after all I shortened 'dictionary' to 'dict'...
You could also use ratio(), but rat() does seem to go with pythons better.
int / int --> float (float//float --> int) float / int --> float (int//int --> int) rat / int --> rat (?) (rat//rat --> int) rat / float --> float rat / rat --> rat
At first glance, this table seemed to create an asymmetry. Before the introduction of rationals, it seemed that / was a "float" division operator and produced only floats regardless of the operands (a good thing). And // was an "int" operator and produced only ints. There are two ways around the apparent assymetry: 1 - result type is based on operator, or 2 - is based on a hierarchy of the operands. I see now that the proposal is to do both, with the following assumptions. Method 1. // is the "integer" division operator. If we define a "rational" division operator (maybe represented by ///, or maybe not defined syntactically) to return rats and only rats, regardless of input types:
int /// int => rat float /// int => rat rat /// int => rat
Method 2. The result type of "/" is based on a hierarchy of the "highest" precision type. The heirarchy (apparently) is: int -> rational -> float which does match the original table. (Although the hierarchy seems arbitrary since rational seems to have higher precision than float). If you define a rational division operator, and state this hierarchy, then the asymmetry goes away. (Although, I'm not sure where to put imaginary and scientific representations). Further asymmetries are found in examining other operators. For example, a beginner might guess: float * float --> float int * int --> float float * int --> float rat * int --> rat rat * float --> float rat * rat --> rat And even worse: float ** float -> int (by making the analogy "if / ==> *, then // ==> **"). I am assuming that the other operators will be based on hierarchy only (I assume the one above). That is: rat * float --> float float * int --> float rat * int --> rat As far as interactively displaying rationals goes, the "r" and parens seem unnecessary and could lead to confusion. We humans will parse it correctly. Although, if you wanted to be able to cut output and paste it as input, then you woud want to keep the input and output formats the same. -Doug
--Guido van Rossum (home page: http://www.python.org/~guido/)
-- Douglas S. Blank, Assistant Professor dblank@brynmawr.edu, (610)526-6501 Bryn Mawr College, Computer Science Program 101 North Merion Ave, Park Science Bld. Bryn Mawr, PA 19010 dangermouse.brynmawr.edu
I'm fortunate enough to get to talk with Guido in person several times per decade <wink>. We've talked about Python's division many times, and, indeed, I share the blame for Python's original decision to make 1/2 == 0, since Guido picked my brain about numerics at the time, and we both thought "well, it's good enough in C, and rationals didn't work that well in ABC, so what the heck ...". In all the conversations I've ever had with him on the topic, neither Sherwood nor Pausch came up. Arthur, you've been told that more times than I can keep track of, but you still bring them up endlessly. Yes, what they said caught Guido's attention at the time, but no, they've had nothing to do with this since then. Any mention of them now is at best irrelevant. Kirby has managed to gain an excellent understanding of the real issues with division in Python (perhaps because he's listening?): [Kirby Urner]
... About div, the technical point is that all the operators *except* div, return very close to equivalent answers, even if the types differ. In this sense, it matters less for + - and * whether the arguments are floats, longs or integers. Since there're no explicit type declarations in Python (as there are in C, from which the original div behavior derives), just eyeballing code is *not* necessarily going to make div's behavior unambiguous, even if you're a pro. So in this case, I'd say we're dealing with a "gotcha" that it doesn't pay to beat your head against. It's still a problem even after you master it -- when reading others' code (don't always think about what it's like to read and understand your own).
Going to / and // makes division unambiguous again. The former forces a floating point treatment, the latter an integer treatment.
In a polymorphic language without explict type declarations, allowing z = x / y to lose catastrophic amounts of information silently was simply a Bad Idea, and more so for accomplished programmers than for newbies. Along the way, we changed Python 2.2 so that x**y no longer raised an exception when x and y happen to be integers and y < 0, and for exactly the same reasons. They have nothing to do with newbies, apart that from giving a bizarre result for sensible inputs isn't truly helpful to anyone.
Only because Python is still young. Others have and I trust and hope many others will share that experience in the future.
And what would that side effect be? What's the benefit >of 1/2==0?
Provides the signal and the reminder of the importance of giving attention to the underlying numeric typing scheme.
Hello! This model assumes that the programmer believes that division between integers is possible. *grin* Seriously though, some other languages hold division as a very strict and dangerous thing. Standard ML, for example, takes its types darn seriously: it doesn't even allow division between integers using '/'! ### - 1.0 / 2.0; val it = 0.5 : real - ; - ; - 1 / 2; stdIn:18.3 Error: overloaded variable not defined at type symbol: / type: int - ; - ; - 1 div 2; val it = 0 : int - ; - ; - 1.0 div 2.0; stdIn:23.5-23.8 Error: overloaded variable not defined at type symbol: div type: real ### (SML's prompt character is '- ', which is visually confusing...) ML'ers use a separate DIV operator that explicitely does truncation between integers. So that is one potential future that Python could have turned toward, but all this typing does feel a bit like bondage. If we really want to teach typing concepts, I don't think Python's the language to do this. Should a programming languages abstract the numeric model of the machine away from the programmer? In the case of Python, it looks like the answer is leaning toward "yes", especially since it already has long integers and complex numbers (and probably rationals soon!) as basic types that the programmer can use. My feeling is that Python division doesn't have to reflect what the machine is doing underneath. At long as we explain to folks that Python is an abstraction on top of the machine, I don't think it will cause long-term harm. The big problem is if we just use just Python alone to teach how computers work: that would be an extraordinarily unbalanced view! If we want to show people the real details about computation, then we really should be doing this in combination with a low-level language like MIPS assembly. Have you thought about doing something like this? Best of wishes to you!
Danny - I think your argument holds together perfectly were there in fact an underlying unification of types in Python. There is not. Getting a conscious awareness of the practical issues involved remains a practical necessity for working in Python - irrespective of the div operator behavior. At least if you are doing anything related to numerics. And thanks for all your help to me and others as we try to contend with these things. Art ----- Original Message ----- From: "Danny Yoo" <dyoo@hkn.eecs.berkeley.edu> To: "Arthur" <ajs@ix.netcom.com> Cc: <edu-sig@python.org> Sent: Thursday, October 10, 2002 2:22 PM Subject: Re: [Edu-sig] re: Types and true division (was Re: strange output)
Only because Python is still young. Others have and I trust and hope many others will share that experience in the future.
And what would that side effect be? What's the benefit >of 1/2==0?
Provides the signal and the reminder of the importance of giving attention to the underlying numeric typing scheme.
Hello!
This model assumes that the programmer believes that division between integers is possible. *grin*
Seriously though, some other languages hold division as a very strict and dangerous thing. Standard ML, for example, takes its types darn seriously: it doesn't even allow division between integers using '/'!
### - 1.0 / 2.0; val it = 0.5 : real - ; - ; - 1 / 2; stdIn:18.3 Error: overloaded variable not defined at type symbol: / type: int - ; - ; - 1 div 2; val it = 0 : int - ; - ; - 1.0 div 2.0; stdIn:23.5-23.8 Error: overloaded variable not defined at type symbol: div type: real ###
(SML's prompt character is '- ', which is visually confusing...)
ML'ers use a separate DIV operator that explicitely does truncation between integers. So that is one potential future that Python could have turned toward, but all this typing does feel a bit like bondage. If we really want to teach typing concepts, I don't think Python's the language to do this.
Should a programming languages abstract the numeric model of the machine away from the programmer? In the case of Python, it looks like the answer is leaning toward "yes", especially since it already has long integers and complex numbers (and probably rationals soon!) as basic types that the programmer can use.
My feeling is that Python division doesn't have to reflect what the machine is doing underneath. At long as we explain to folks that Python is an abstraction on top of the machine, I don't think it will cause long-term harm.
The big problem is if we just use just Python alone to teach how computers work: that would be an extraordinarily unbalanced view! If we want to show people the real details about computation, then we really should be doing this in combination with a low-level language like MIPS assembly. Have you thought about doing something like this?
Best of wishes to you!
I think your argument holds together perfectly were there in fact an underlying unification of types in Python.
There is not.
But there will be in Python 3000. --Guido van Rossum (home page: http://www.python.org/~guido/)
participants (11)
-
Arthur -
Danny Yoo -
Dennis E. Hamilton -
Dethe Elza -
Douglas S. Blank -
Guido van Rossum -
Jason Cunliffe -
Kirby Urner -
list-python-edu@ccraig.org -
list-python@ccraig.org -
Tim Peters