[Edu-sig] re: Types and true division (was Re: strange output)

Kirby Urner urnerk@qwest.net
Thu, 10 Oct 2002 10:12:50 -0700


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
>

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:
 >>> 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
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