'isa' keyword

  • Thread starter talin at acm dot org
  • Start date
T

talin at acm dot org

Although I realize the perils of even suggesting polluting the Python
namespace with a new keyword, I often think that it would be useful to
consider defining an operator for testing whether or not an item is a
member of a category.

Currently, we have the 'in' operator, which tests for membership within
a container, and that works very well -- in particular, it allows such
membership tests to be expressed in very natural way. So for example,
whereas in C++ I always have to say:

if (dependencies.find( name ) != dependencies.end())

in Python I can simply say:

if name in dependencies:

....which is much more readable and intuitive. At the same time,
however, I recognize that there is a logical difference between
membership in a container, and membership in a category. For example,
although a bear is a member of the class of mammals, it doesn't make as
much to say "if bear in mammal". Similarly, you wouldn't want to use
the 'in' keyword as a replacement for isinstance(), i.e. "if name in
str".

I propose the word 'isa' because the term 'isa hierarchy' is commonly
used to indicate a tree of types. So the syntax would look like this:

if bear isa mammal:
if name isa str:

(I suppose it would look prettier to put a space between "is" and "a",
but there are many obvious reasons why you don't want "a" to be a
keyword!)

The "isa" operator would of course be overloadable, perhaps by an
accessor functions called __isa__, which works similarly to
__contains__. The potential uses for this are not limited to
isinstance() sugar, however. For example:

if image isa gif:
elif image isa jpeg:
elif image isa png:

In this case, we're not testing for object identity (which tests if two
variables are referring to the same object), or even object equivalence
(which tests of two objects are of equal value), nor are we testing for
membership within a container -- instead we're testing for membership
with a type hierarchy, where 'type' can be defined to mean whatever the
programmer wants.

Of course, at this point, I am sure that someone will point out that I
should be using method overloading and inheritance rather than explicit
testing of types. However, try writing an efficient __cmp__ function
solely by method overloading -- or any other function that deals with
more two object argument, where the action to be taken depends on the
combination of types of both arguments. This can be solved with
multi-method dispatch, but such methods are complex, non-standard, and
have somewhat dubious performance characteristics. Its generally faster
and simpler to dispatch based on the type of one of the arguments, and
then test the types of the other arguments.
 
P

Paul Rubin

talin at acm dot org said:
membership within a container -- instead we're testing for membership
with a type hierarchy, where 'type' can be defined to mean whatever the
programmer wants.

Well, if "type" means a (possibly infinite) set of objects, then you
can use "in". E.g, "3 in int".
 
F

Fuzzyman

Although I realize the perils of even suggesting polluting the Python
namespace with a new keyword, I often think that it would be useful to
consider defining an operator for testing whether or not an item is a
member of a category.

Currently, we have the 'in' operator, which tests for membership within
a container, and that works very well -- in particular, it allows such
membership tests to be expressed in very natural way. So for example,
whereas in C++ I always have to say:

if (dependencies.find( name ) != dependencies.end())

in Python I can simply say:

if name in dependencies:

...which is much more readable and intuitive. At the same time,
however, I recognize that there is a logical difference between
membership in a container, and membership in a category. For example,
although a bear is a member of the class of mammals, it doesn't make as
much to say "if bear in mammal". Similarly, you wouldn't want to use
the 'in' keyword as a replacement for isinstance(), i.e. "if name in
str".

I propose the word 'isa' because the term 'isa hierarchy' is commonly
used to indicate a tree of types. So the syntax would look like this:

if bear isa mammal:
if name isa str:

What's the difference between this and ``isinstance`` ?


Best Regards,

Fuzzy
http://www.voidspace.org.uk/python
 
P

phil hunt

The "isa" operator would of course be overloadable, perhaps by an
accessor functions called __isa__, which works similarly to
__contains__. The potential uses for this are not limited to
isinstance() sugar, however. For example:

if image isa gif:
elif image isa jpeg:
elif image isa png:

What's wrong with:

if image.isa(gif):
elif image.isa(jpeg):
elif image.isa(png):

In short, I see no need to add further complexity to Python's
grammar.

It could be argued of course, that an OOPL should allow methods to
be sent with a grammar:

receiver selector argument

(which is almost what Smalltalk does), but you're not arguing for
that (and I'm not sure it would work with the rest of python's
grammar).
 
S

Steve Holden

phil said:
What's wrong with:

if image.isa(gif):
elif image.isa(jpeg):
elif image.isa(png):

In short, I see no need to add further complexity to Python's
grammar.

It could be argued of course, that an OOPL should allow methods to
be sent with a grammar:

receiver selector argument

(which is almost what Smalltalk does), but you're not arguing for
that (and I'm not sure it would work with the rest of python's
grammar).
Even if it did it might mangle operator precedence in the same way
SmallTalk did, which I always felt was one of the least attractive
features" of the language.

I don't think a change to a message-passing paradigm would necessarily
benefit Python at this stage. Some people are still under the
misapprehension that message-passing is a fundamental of object-oriented
programming because of Smalltalk, but they are wrong.

The addition of an "isa" operator would be an unnecessary addition of
pure syntactic sugar.

regards
Steve
 
D

D H

talin said:
Although I realize the perils of even suggesting polluting the Python
namespace with a new keyword, I often think that it would be useful to
consider defining an operator for testing whether or not an item is a
member of a category.

It's a good idea but not likely to be added to python, at least not til
python 3000 comes out with type checking. The default way is "if
isinstance(image, jpeg)".
Also there is "if image |isa| jpeg:" using one of the various python
hacks out there:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122

But since Python doesn't have interfaces or type checking today, there
really is not much need for isa or isinstance anyway, but you might use
hasattr or try/except instead: http://www.canonical.org/~kragen/isinstance/
 
T

Terry Hancock

On 1 Sep 2005 00:52:54 -0700, "talin at acm dot org"
<[email protected]> wrote:
What's the difference between this and ``isinstance`` ?

Other than proposing a keyword operator instead of a function,
apparently nothing.

isinstance() even checks for subclasses, if I'm not mistaken,
so the semantics should be identical.

I must confess that an "isa" operator sounds like it would
have been slightly nicer syntax than the isinstance() built-in
function. But not enough nicer to change, IMHO.

Terry
 
R

Rocco Moretti

Terry said:
I must confess that an "isa" operator sounds like it would
have been slightly nicer syntax than the isinstance() built-in
function. But not enough nicer to change, IMHO.

Especially conidering that checking parameters with "isinstance" is
considered bad form with Python's duck typing.
 
P

phil hunt

Even if it did it might mangle operator precedence in the same way
SmallTalk did, which I always felt was one of the least attractive
features" of the language.

That's certainly a point of view; another is that Smalltalk
simplified things by making all operators the saem priority. For
those that don't know smalltalk, in that language:

a + b * c

means:

(a + b) * c
I don't think a change to a message-passing paradigm

I'm not talking about a change in *paradigm* merely a change in
*syntax*; this:

receiver selector argument

would mean the same as the current Python:

receiver.selector(argument)

so it is purely a matter of aesthetics which is preferred. Havcing
said that, I don't see a big benefit in changing Python's syntax in
this way.
would necessarily
benefit Python at this stage. Some people are still under the
misapprehension that message-passing is a fundamental of object-oriented
programming because of Smalltalk, but they are wrong.

I don't see how it can reasonably said that STK has
"message-passing" but other OOPLs don't. Consider these code
fragments:

Smalltalk:
receiver selector: argument

C++ or Java:
receiver.selector(argument);

Python:
receiver.selector(argument)

PHP:
$receiver->selector($argument)

(I'm not sure if the last one is right since I've not done much OO
stuff in PHP)

These all mean essentially the same thing so how can one be "message
passing" and the others not?
 
T

talin at acm dot org

Thanks for all the respones :) I realized up front that this suggestion
is unlikely to gain approval, for reasons eloquently stated above.
However, there are still some interesting issues raised that I would
like to discuss.

Let me first respond to a few of the comments:
What's the difference between this and ``isinstance`` ?

What's the difference between 'in' and 'has_key()"? 1) Its shorter and
more readable, 2) it can be overridden to mean different things for
different container types.
What's wrong with:
if image.isa(gif):
elif image.isa(jpeg):
elif image.isa(png):

That forces the classification logic to be put into the instance,
rather than in the category. With the "in" keyword, the "__contains__"
function belongs to the container, not the contained item, which is as
it should be, since an item can be in multiple containers.
Especially conidering that checking parameters with "isinstance" is
considered bad form with Python's duck typing.

Here's an example where the strict OOP style of programming breaks
down. I'll use SCons as an example. In SCons, there is a "Depends"
function that can take a filename, a list of filenames, or a build
target (which is a python object). So the logic looks like this:

def Depends( target ):
if isinstance( target, str ):
...
elif isinstance( target, list ):
...
elif isinstance( target, BuildTarget ):
...
else: error

You can't use method overloading here, because you are dealing with
builtin python objects (except for the BuildTarget).

I can think of several different cases where you would have to resort
to logic like this:
-- Where you are trying to distinguish between built-n python types
-- Where you are trying to distinguish between types that are created
by another, independent module and which you can't modify
-- Where you are trying to do multi-method dispatch logic.

As an example of the latter, imagine a music sequencer application that
edits a stream of Midi events. Lets suppose that there are various
"classes" of events:

Note On
Note Off
Aftertouch
Pitchbend
Control Change

In addition, lets suppose that we have a variety of different ways of
editing these events:

"Piano Roll" Editor - edits in horizontal "piano roll" form
"Drum Machine" editor - notes are placed on a grid
Event List Editor - a text list of events
Music Notation Editor - uses conventional notes and staves

All of these editors operate on the same underlying data, which is a
stream of events. Each of these editors has a "repaint" function to
render the stream of events. So the rendering of the event depends
*both* on the class of the event, and the class of the editor.

So you could organize it this way:

class PianoRollEditor:
def repaint( event ):
if isinstance( event, Note ): # draw note
elif isinstance( event, Aftertouch ): # draw
...etc

You could also invert the logic (which is somewhat clumsier):

class Note:
def repaint( context ):
if isinstance( context, PianoRollEditor ): ...
etc...

Now, I realize that some folks have built multi-method dispatch systems
for Python (I did one myself at one point.) However, these tend to be
somewhat slow and clunky without language support (and no, I am not
asking for Python to become Dylan or CLOS.) But it would be nice to
know if there was a cleaner way to solve the above problems...
 
S

Steve Holden

phil said:
That's certainly a point of view; another is that Smalltalk
simplified things by making all operators the saem priority. For
those that don't know smalltalk, in that language:

a + b * c

means:

(a + b) * c




I'm not talking about a change in *paradigm* merely a change in
*syntax*; this:

receiver selector argument

would mean the same as the current Python:

receiver.selector(argument)
Aah, I see. I had assumed that "selector" was always going to be an
operator. 3 . (+ 4) does indeed seem very "SmallTalkative". I don't
think that Python method (or attribute) selection bears any relationship
to SmallTalk message-passing, but I hope you will feel free to enlighten me.
so it is purely a matter of aesthetics which is preferred. Havcing
said that, I don't see a big benefit in changing Python's syntax in
this way.
Me neither. And I can see positive disbenefits, like it would confuse
the hell out of most people :)
I don't see how it can reasonably said that STK has
"message-passing" but other OOPLs don't. Consider these code
fragments:

Smalltalk:
receiver selector: argument

C++ or Java:
receiver.selector(argument);

Python:
receiver.selector(argument)

PHP:
$receiver->selector($argument)

(I'm not sure if the last one is right since I've not done much OO
stuff in PHP)

These all mean essentially the same thing so how can one be "message
passing" and the others not?
Sorry, they don't all mean "essentially the same thing" at all. It seems
to me you are looking at SmallTalk in entirely too superficial a light.
In SmallTalk, control structures aren't syntactic primitives, they are
also examples of message-passing, so code blocks are sent as messages to
objects. Python eschews such obscurity and (IMHO) gains clarity by so
doing. But that is, of course, a matter of opinion.

Also, remember that just because two expressions in different languages
"mean the same thing "doesn't mean they are implemented using the same
techniques.

I would contend (if backed into a corner) that there is a significant
difference between passing the arguments 3 and 4 to a "+" operator
(which is what Python and most other languages implementing standard
ideas of operator precedence do) and sending the message "+ 4" to the
integer 3 (which is effectively what SmallTalk does).

Of course, I realise that you can argue that the two are equivalent in
the sense that they perform the same computation. But SmallTalk's choice
led to the loss of operator precedence, which is something that is
pretty fundamental to mathematics. Also Python allows much more
flexibility by hard-wiring operators and allowing alternatives to be
considered (if the left operand doesn't have an "__add__" method then
try to use the right operand's "__radd__" method). SmallTalk doesn't
have any parallel to this that I can think of.

Also, try seeing what the mathematicians have to say about a language where

a + b * c

means

(a + b) * c

Of course it isn't only mathematicians who are taught to us the
precedence rules, so I contend that SmallTalk would seem
counter-intuitive in a "Programming for Everyone" context as well. It
seems to me that Guido's primary achievement with Python's design is to
provide a language that allows the expression of object-oriented
paradigms in a way that seems natural even to people who are new to
object-oriented concepts.

I'm glad you haven't done much object-oriented stuff in PHP, because its
object-oriented paradigm is about as sensible as Perl's (which is to say
it was a bolt-on extension that resulted in an extremely unnatural mode
of expression). The fact that people can write object-oriented code in
these languages is a testament to the flexibility of human thought
rather than a benefit of the languages' design.

I speak as one who was partly, and in a minor way, responsible for
implementing the SmallTalk system on the Perq architecture back in the
1980's. (Mario Wolczko did the real work). So it's not that I've just
looked at SmallTalk and find it odd. It's just that it treats
expressions in a way which ultimately appear to seem counter-intuitive
in contexts like arithmetic expressions.

regards
Steve
 
B

Bengt Richter

It's a good idea but not likely to be added to python, at least not til
python 3000 comes out with type checking. The default way is "if
isinstance(image, jpeg)".
Also there is "if image |isa| jpeg:" using one of the various python
hacks out there:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122

But since Python doesn't have interfaces or type checking today, there
really is not much need for isa or isinstance anyway, but you might use
hasattr or try/except instead: http://www.canonical.org/~kragen/isinstance/

I recently experimented with an ast-rewriting importer, and I suspect could
set up a configurable importer that would recognize '|isa|' (or with any other
legal binary op in place of '|'). Maybe '**' would stand out in
"if image **isa** jpeg" and reduce processing since it's less commonly used
than e.g., + or -. OTOH, the latter would permit unary operator definitions
as well, e.g., "-inv- mx" could translate to mx**-1 meaning

Sub((UnarySub(Name('inv')), Name('mx')))

int the ast is translated to opmod.inv(mx) replacing the above with

CallFunc(Getattr(Name('opmod'), 'inv'), [Name('mx')], None, None)

You could just write a module so that names to use would be given by

[name for name in dir(opmod) if not name.startswith('_') and callable(getattr(opmod, name)]

and then have the importer do that when given the module as config info, and look
for the names, e.g., 'inv' in an ast subtree context as above, or for "left -isa- right"
look for

Sub((Sub((Name('left'), Name('isa'))), Name('right')))

and rewite it as

CallFunc(Getattr(Name('opmod'), 'isa'), [Name('left'), Name('right')], None, None)

My recent post was doing 'a/b' => safediv(a, b) in a similar fashion,
which gives me the feeling that -xx- as custom infix operator would
work for a lot of contexts. BTW, the ast for "left |isa| right" is

Bitor([Name('left'), Name('isa'), Name('right')])

which probably makes it faster to recognize. Obviously subtrees not
involving the specal op names would be ignored.

I don't know if ast-rewriting on the fly during customizable import
excites anyone, or if those who understand what I'm doing would just
rather I didn't post about it "devant les enfants" ;-)

Regards,
Bengt Richter
 
D

Devan L

talin said:
Thanks for all the respones :) I realized up front that this suggestion
is unlikely to gain approval, for reasons eloquently stated above.
However, there are still some interesting issues raised that I would
like to discuss.

Let me first respond to a few of the comments:


What's the difference between 'in' and 'has_key()"? 1) Its shorter and
more readable, 2) it can be overridden to mean different things for
different container types.

Your analogy doesn't apply to non dictionaries. In any case, nothing
stops you from writing your own has_key() method for a different
container type. Likewise, if you made an isa keyword, it would just
call a method to have the traits you described above. You could write
your own method to see if it was an instance of the class, but it would
end up being more or less similar to isinstance().
 
P

phil hunt

Aah, I see. I had assumed that "selector" was always going to be an
operator. 3 . (+ 4) does indeed seem very "SmallTalkative". I don't
think that Python method (or attribute) selection bears any relationship
to SmallTalk message-passing, but I hope you will feel free to enlighten me.

Let's consider the Python example first.

You have two classes A and B. Each has a method called 'selector'.

When the line of code above is executed, the Python virtual machine
decides whether (receiver) is a member of A or B, and then executed
one of A.selector() or B.selector() depending on which it is.
Whichever function is executed, it is passed with (reciever) as the
"self" argument so that the correct data is operated on.

And now let's consider the Smalltalk example. How does it do it?
Essentially it does *exactly the same thing*.

(Yes, I know there are many differneces in detail between how
Snalltalk and Python work, but they are only *details*; the
fundamental idea governing how these two object-oriented languages
work is the same).
Sorry, they don't all mean "essentially the same thing" at all. It seems
to me you are looking at SmallTalk in entirely too superficial a light.

OK, allow me to reprase it. Imagine a language ith the semantics of
Python but the syntax of C++ or PHP or Smalltalk (or Lisp for that
matter). It would still basically be Python, wouldn't it?
In SmallTalk, control structures aren't syntactic primitives, they are
also examples of message-passing, so code blocks are sent as messages to
objects. Python eschews such obscurity and (IMHO) gains clarity by so
doing. But that is, of course, a matter of opinion.

I agree, that's a major point of departure between Python and
Smalltalk.
Also, remember that just because two expressions in different languages
"mean the same thing "doesn't mean they are implemented using the same
techniques.

Of course not.

CPython and JPython are different implementations, but they are
still the same language (mostly).
I would contend (if backed into a corner) that there is a significant
difference between passing the arguments 3 and 4 to a "+" operator
(which is what Python and most other languages implementing standard
ideas of operator precedence do) and sending the message "+ 4" to the
integer 3 (which is effectively what SmallTalk does).

In both python and smalltalk you can override the operator to mean
what you want, so I disagree that there is any fundamental
difference. Why do you think there is?
Of course, I realise that you can argue that the two are equivalent in
the sense that they perform the same computation. But SmallTalk's choice
led to the loss of operator precedence, which is something that is
pretty fundamental to mathematics.

Surely that's a separate issue, one purely of syntax. Imagine two
languages:

(* (+ a b) c)

and:

(a + b) * c

These both mean the same thing, they just say it differently.
Also Python allows much more
flexibility by hard-wiring operators and allowing alternatives to be
considered (if the left operand doesn't have an "__add__" method then
try to use the right operand's "__radd__" method). SmallTalk doesn't
have any parallel to this that I can think of.

You're right; in Smalltalk you'd have to code that functionality in
the method for the left-hand object.
Of course it isn't only mathematicians who are taught to us the
precedence rules, so I contend that SmallTalk would seem
counter-intuitive in a "Programming for Everyone" context as well.

Probably.

However consider that a language (e.g. C++) may have lots of
operators, e.g: & && | || << >> <= >= < > ^ % etc. Is there an
obvious natural order of precedence for all these? I suspect that
many C++ programmers couldn't put all its operators in the correect
order.
I speak as one who was partly, and in a minor way, responsible for
implementing the SmallTalk system on the Perq architecture back in the
1980's.

What's Perq?
(Mario Wolczko did the real work). So it's not that I've just
looked at SmallTalk and find it odd. It's just that it treats
expressions in a way which ultimately appear to seem counter-intuitive
in contexts like arithmetic expressions.

I personally didn't find it odd, it felt quite natural to me.
 
S

Steve Holden

phil said:
Let's consider the Python example first.

You have two classes A and B. Each has a method called 'selector'.

When the line of code above is executed, the Python virtual machine
decides whether (receiver) is a member of A or B, and then executed
one of A.selector() or B.selector() depending on which it is.
Whichever function is executed, it is passed with (reciever) as the
"self" argument so that the correct data is operated on.

And now let's consider the Smalltalk example. How does it do it?
Essentially it does *exactly the same thing*.

(Yes, I know there are many differneces in detail between how
Snalltalk and Python work, but they are only *details*; the
fundamental idea governing how these two object-oriented languages
work is the same).
It's the differences we are talking about. All you have said above is
that Python and SmallTalk both use late-binding to resolve names,
allowing them to implement polymorphic behavior.
OK, allow me to reprase it. Imagine a language ith the semantics of
Python but the syntax of C++ or PHP or Smalltalk (or Lisp for that
matter). It would still basically be Python, wouldn't it?
I'm not sure I understand this. You appear to be saying, in essence,
"they are all programming languages, so despite the fact that they work
slightly differently the similarity is we can write programs in them all".
I agree, that's a major point of departure between Python and
Smalltalk.
Right, but it's precisely SmallTalk's message-passing techniques that
allow this to work. Of course Python can create code blocks with
compiler.compile(), but this is not mainstream, and Python has so many
more-useful mechanisms to implement program control that using code
objects as data is correctly regarded as being ion the boundaries of
language voodoo.
Of course not.

CPython and JPython are different implementations, but they are
still the same language (mostly).
That we can agree on. But both differ substantially from SmallTalk.
In both python and smalltalk you can override the operator to mean
what you want, so I disagree that there is any fundamental
difference. Why do you think there is?
Because in Python the interpreter has hard-wired code associated with
each operator. This code examines the left- and right-hand operands,
calling various methods on them if they exist.

In SmallTalk the operator is the first element of a message sent to the
left-hand operand, and if the object (or one of its superclasses) has no
method corresponding with the operator then a "don't understand
operator" exception is raised.

In other words, the differences aren't purely syntactic.
Surely that's a separate issue, one purely of syntax. Imagine two
languages:

(* (+ a b) c)

and:

(a + b) * c

These both mean the same thing, they just say it differently.
Of course the point of Reverse Polish notation is precisely to avoid the
need for parentheses, but we'll overlook that. I've tried to explain
that SmallTalk expressions don;t have precedence because there is no way
in the language to implement operator precedence, and that's because of
the underlying message-passing paradigm of the SmallTalk virtual machine.
You're right; in Smalltalk you'd have to code that functionality in
the method for the left-hand object.
Correct!


Probably.

However consider that a language (e.g. C++) may have lots of
operators, e.g: & && | || << >> <= >= < > ^ % etc. Is there an
obvious natural order of precedence for all these? I suspect that
many C++ programmers couldn't put all its operators in the correect
order.
Indeed, and that's why the use of explicit parentheses is a good
defensive technique. But your average consumer of CP4E is going to be
confused if the try to print 3 + 4 * 5 and get 35 instead of 23. Unless
arithmetic teaching has changed so radically since my schooling that
people don't understand BODMAS (Brackets, Of, Division, Multiplication,
Addition, Subtraction) or the various other acronyms used to teach basic
precedence.
What's Perq?
It was an early workstation built by the Three Rivers company.
Bit-mapped graphics, many of the characteristics of the Xerox Dorado,
but at a price researchers could afford. Its original operating system
had many similarities with Mac OS9 (no pre-emptive scheduling!), but in
the UK ICL produced a UNIX port called Pnix for it, and it was used by
many projects funded by the Science Research Council.

The Burroughs disk drive was infamous because the drive belt (this 30MB
drive was around 2 feet in diameter ...) would periodically slip off the
motor, and you'd have to open up the cabinet to reposition it.

The Perq eventually became so despised by the computer science community
in the UK, despite its advanced design, for the trouble it caused - the
problem above was only one of its many unreliabilities, that after I
left Manchester University and went to work for Sun Microsystems the
Comp Sci department invited me back to play the John Cleese role in a
sketch that began "I would like to complain about this Perq, what I
purchased from this very Research Council not half an hour ago," and
ended up with me smashing the machine with a mallet, and remarking "Now
that's what I call a dead Perq". You can imagine the rest.
I personally didn't find it odd, it felt quite natural to me.
Maybe it's you that's odd, then. Or me :) But you've convinced me you
know enough about SmallTalk to understand that there are indeed some
significant differences between it and Python.

regards
Steve
 
D

Dennis Lee Bieber

Of course the point of Reverse Polish notation is precisely to avoid the
need for parentheses, but we'll overlook that. I've tried to explain

That wasn't RPN either -- it was prefix notation a la LISP... The
parens are probably there to delimit the range of a potentially none
dyadic operator (ack! my ancient APL is showing)

RPN would have been: a b + c *
--
 
C

Colin J. Williams

Rocco said:
Especially conidering that checking parameters with "isinstance" is
considered bad form with Python's duck typing.
Rocco,

Could you elaborate on that please?

Colin W.
 
A

Antoon Pardon

Op 2005-09-03 said:
Sorry, they don't all mean "essentially the same thing" at all. It seems
to me you are looking at SmallTalk in entirely too superficial a light.
In SmallTalk, control structures aren't syntactic primitives, they are
also examples of message-passing, so code blocks are sent as messages to
objects.

That doesn't seem that important to me. Should python eventually
acquire annonymious blocks, python could do the same.
Python eschews such obscurity and (IMHO) gains clarity by so
doing. But that is, of course, a matter of opinion.

Also, remember that just because two expressions in different languages
"mean the same thing "doesn't mean they are implemented using the same
techniques.

But it is the meaning, that defines the language, not the
implementation. So if two expression mean the same thing,
they are essentially the same thing.
I would contend (if backed into a corner) that there is a significant
difference between passing the arguments 3 and 4 to a "+" operator
(which is what Python and most other languages implementing standard
ideas of operator precedence do) and sending the message "+ 4" to the
integer 3 (which is effectively what SmallTalk does).

Again you are looking at an implemantation detail, not at the meaning.

And you are wrong about python. In python you don't pass 3 and 4 to
the "+" operator. You select the __add__ method of the integer 3
which you give the argument 4. Yes I know this is a bit simplified.
Of course, I realise that you can argue that the two are equivalent in
the sense that they perform the same computation. But SmallTalk's choice
led to the loss of operator precedence, which is something that is
pretty fundamental to mathematics.

Smalltalk could have solved that without any significant change in
implementation. Should smalltalk have decided that mathematic
expression were just syntactic sugar for messages passed to
object, a solution like in python could have been possible.
e.g. the arithmetic methods could have been called:

@add, @sub, @mul, @div.

An expression like 3 + 4 * 5 could then first internally be translated
into 3 @add (4 @mul 5) and thus would be treated just as the expression
3 + (4 * 5) is treated now in smalltalk. This has nothing to do with
the choice in paradigma, but with the choice of how much syntactix sugar
you are willing to allow on top of your paradigma.
Also Python allows much more
flexibility by hard-wiring operators and allowing alternatives to be
considered (if the left operand doesn't have an "__add__" method then
try to use the right operand's "__radd__" method). SmallTalk doesn't
have any parallel to this that I can think of.

Smalltalk assumes that there is some total order in the number class
systems, and that classes that are low in this relation can be converted
to a class that is higher. So when you implement an arithmetic class,
you should decide where your class belongs and then when you implement
an operator, you should first check to see the argument is not higher
classified, if it is you should convert your object to the same class
and send the converted object the same method and argument.

It is not as flexible as python, but it mostly worked.
 
R

Rocco Moretti

Colin said:
Could you elaborate on that please?

I'm not sure if you're familiar with duck typing or not, so I'll
summarize it briefly. (More detail can be found by others in the c.l.py
archive.)

"Duck typing" takes its name from the expression "If it looks like a
duck, walks like a duck, and quacks like a duck, it's a duck." That is,
the essence of an object is not its provenance, but its behaviour. This
arises in part from Python being dynamically typed - you don't have to
match the type of an object in order to pass it as a parameter.

For example, say you had a function:

def fun(alist):
for item in alist:
doworkon(item)

The intended use of the function is for it to be passed a list, but you
don't have to pass a list - it works just fine with a tuple, an
iterator, a generator, a file object, a dictionary, or in fact any user
defined class - all that's needed is for an appropriately defined
__iter__ or __getitem__ member.

Now if you use isinstance, you mess that up:

def boring(alist):
if isinstance(alist, list):
for item in alist:
doworkon(item)
else:
raise TypeError

This will only work with a bona fide list, and choke on the other
objects - even objects intended by the programmer to act like a list.

Python functions are much more flexible if you don't go checking if an
object is of a particular type. It makes things like using proxies,
wrappers and mock objects much easier.

Best practices in Python call for using a parameter and catching when it
doesn't behave properly, not prophylactically checking types. Python
programmers can go months to years without using isinstance. It doesn't
make sense to make it any easier.

P.S. In the OP's case, where it was desired to distinguish between being
passed a string and being passed a list of strings, the approach used is
probably sub-optimal. It would likely be better to have the function
always take a "list", and convert all the fun('string') calls to
fun(['string']) calls.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,245
Members
46,839
Latest member
MartinaBur

Latest Threads

Top