What If..... Strong Types
brueckd at tbye.com
brueckd at tbye.com
Wed Jun 19 17:55:40 CEST 2002
On Wed, 19 Jun 2002, Don Garrett wrote:
> brueckd at tbye.com wrote:
> > I never understood all the hooplah over ints not being classes. I've only
> > ever seen a handful of cases where it might be useful, and lots of cases
> > where it'd get abused, but some people really seem to want it.
> My desire for it is simple desire for orthagonality. The curse of a CS
> background, I guess. But I'm curious, how could you really abuse it?
Well, if you can subclass an int, for example, you can then override
and/or extend its behavior, but since the behavior of ints is pretty well
understood you're begging for bugs if your subclass does anything
non-obvious (e.g. you override addition to coerce non-integers differently
than Python normally would, or you extend subtraction to include some side
effect). In general, too magical and subtle for me!
The reason I asked, BTW, is because from time to time I play with Ruby and
nearly _every_ time somebody says they prefer Ruby over Python they
include the 'ints are types, not classes!' argument on their list, even
though they generally have no use for ints as classes, so whenever I hear
that I'm curious to know if they really need it or not. ;-)
> > You might not consider it important, but it'd break a lot of _my_ code, so
> > it'd be important to me! :) Python doesn't force you to use all its
> > dynamic abilities, but I regard that as one of the tools of the Python
> > toolbox, so yes, I'd be hurt by its removal.
> What kinds of code would it break? That's what I'm trying to understand. I
> find that my code doesn't take advantage of these features at all.
> I use function pointers a lot, but I never change/add/delete methods
> at run time, and I always define all members in __init__, even if it's
> just to a default value (or None). Whenever I start to do anything else,
> it feels hacky and hard to follow. Obviously other people feel
Dynamically adding and removing methods isn't something I do too often,
but when I do it's usually plugging in different callback methods for
others to use. For example, I've used it as a convenient way to manage
signal/event handling - if an object temporarily needs to be able to
ignore a particular type of event I'll plug in a do-nothing handler. This
isn't always the best approach, of course, but when it is it works well
because the event source doesn't need to know whether or not the object is
ignoring events, and the object itself doesn't need a separate flag or
variable to track that state either - it's just a part of the object
What I use much more often is dynamically adding/removing data members. A
common example is when an object is processed by different components in a
larger workflow, especially when the components in the workflow are not
decided until (or can change during) runtime. Rather than have each
component wrap the object up inside another object so it can add state
information, I can just add that to the object itself, and remove those
bits of info as processing by that component is complete and the object is
moving on to another component.
A simpler example is when it's convenient to use the presence of an object
attribute as an indicator that some work has been accomplished. Say you
have a Package object that represents a FedEx package to be shipped
somewhere, but you often have to weigh it first.
One approach is to not even define a weight member variable until I've
weighed the package, and I can test to see if I've weighed it already by
checking for the presence of that variable. The alternative is to define a
weight variable up front and then initialize it to some dummy value, e.g.
-1. I believe that when I do this, though, it is more because of my
"upbringing" in other languages rather than it being a good idea. Does the
package really weigh -1? No. Worse, to make it be "good code" I'll
probably define -1 to be NOT_WEIGHED or something, and check against it so
I'm not using magic numbers.
If I can break away from my previous language habits, the former approach
often makes more sense than the latter, especially when not all modes of
processing the package would require the package to be weighed (customer
BigCorp just gets charged a flat rate, for example, so the weight member
variable would never be used at all perhaps).
The scenarios in which dynamic object modification works best are ones in
which it's convenient to think of the "type" of the object as one that
evolves over its lifetime, or one that reacts to its use. IOW, the object
may not even _have_ a type that is completely definable at compile time.
It's sometimes hard for me to model my objects this way because of having
had to always do it the other (completely statically defined) way, but
when this approach works the solutions are often quite elegant and
straightforward (btw - I believe that a good portion of bugs and program
cruftiness is related to forcing the programmer to clearly define, up
front, what the complete type of the object is. In many cases this forces
the programmer to make decisions without enough information, in others it
is too constricting, and in others it's just too tedious to make the
programmer worry about all those details, and in all cases general
More information about the Python-list