D
David MacQuigg
I'm concerned that with all the focus on obj$func binding, &closures,
and other not-so-pretty details of Prothon, that we are missing what
is really good - the simplification of classes. There are a number of
aspects to this simplification, but for me the unification of methods
and functions is the biggest benefit.
All methods look like functions (which students already understand).
Prototypes (classes) look like modules. This will make teaching OOP
much simpler, especially for the students and professional engineers
(non-CIS) that I am most concerned about. I teach electronic design
tools, not programming. Current plans are to include some basic
Python, no OOP. If I could add OOP with another 4 hours, I would do
it.
I've written a proposal for a prototype syntax that I believe captures
the essense of what is good in Prothon, while not departing too
radically from Python. see PrototypeSyntax.htm at
http://ece.arizona.edu/~edatools/Prothon/ I would like to get
feedback from Python experts on the potential problems with this
syntax. The major question is automatic translation of existing Python
programs to the new syntax. I'm one of those users who would not give
up the existing libraries in Python, no matter how good some
alternative language may be.
I would also like to get feedback from users on what they like or
dislike about this proposal. I will summarize this feedback in the
"Pros and Cons" section of the proposal.
Below are some excerpts from the syntax proposal. Please see the link
above for better formatting.
-- Dave
Proposed Prototype Syntax
=========================
< snip >
Example of Simplified Classes ( Prototypes )
============================================
Animal --> Mammal --> Feline --> Cat
------- ------- ------- -------
numAnimals numMammals numFelines numCats
home genus
__init__() __init__() __init__() __init__()
.sound .sound
.name
show() show() show() show()
talk() talk()
proto Animal(object): # Inherit from the primitive object.
numAnimals = 0
home = "Earth"
....
<see the "OOP Chapter" at http://ece.arizona.edu/~edatools/Prothon/
for the complete example.>
....
proto Cat(Feline):
numCats = 0
__init__ n = "unknown", s = "Meow" ):
Feline.__init__()
Cat.numCats += 1
.name = n # Set instance variables.
.sound = s
show ): # Define a "static method".
Feline.show()
print " Cats:", Cat.numCats
talk ):
print "My name is ...", .name
print "I am a %s from %s" % (.genus, .home)
Mammal.talk() # Call an unbound function.
print __self__ ### Diagnostic check.
cat1 = Cat() # Create instance.
with cat1: # Modify instance variables.
home = "Tucson"
genus = "feline"
name = "Garfield"
My name is ... Garfield
I am a feline from Tucson
Mammal sound: Meow
Changes from Current Python
===========================
-- Keyword class is changed to proto.
-- All methods have the same form, identical to a simple function.
-- Function header lines are re-arranged. def --> : Parentheses are
optional.
-- self is replaced with a leading dot, and eliminated from the arg
list.
-- Current instance is available if ever needed via __self__
-- Instances can have their attributes modified in a with block.
Benefits of Proposed Syntax
===========================
-- Unification of all function forms ( bound, unbound, static, class,
lambda ). All will have the same form as a normal function
definition. This will make it easier to teach OOP. Students will
already understand functions and modules. OOP is a small step up. A
prototype will look just like a module ( except for the instance
variables ). See Parallels between Prototypes and Modules below.
-- Using an explicit __self__ variable avoids the magic first
argument, and makes it easier to explain instance variables. See the
sections below comparing a brief explanation of instance variables in
Python vs the simplified form. A full presentation of OOP, like pages
295-390 in Learning Python, 2nd ed. will likely be 1/2 the number of
pages. Not only is the basic presentation simpler, but we can
eliminate a lot of discussion of lambda functions, static methods,
etc.
-- All attributes of a prototype ( both data and functions ) will be
in a neat column, making it easier to find a particular attribute when
visually scanning a program. Understanding the structure of a program
will be almost as quick as seeing a UML diagram.
-- Lambda keyword will be gone. An anonymous function using normal
function syntax can be extremely compact. ( :x,y:x+y )
-- Method definitions will be less cluttered and less typing with
__self__ as a hidden variable.
-- Changing numerous attributes of an instance will be more
convenient. ( need use case )
-- Migration of Python programs to Prothon will be automatic and
reliable. ???
Pros and Cons of the Proposed Syntax
====================================
Classlessness
Con: The proposed syntax is not purely classless. This is important
because ... ???
Unification of Methods and Functions
Pro1: Less to learn.
Con1: Experts don't care. Beginners don't need advanced method
syntax.
Pro2: Replace lambdas with standard function syntax.
Con2: ???
Explicit __self__
Pro1: Allows the unification of methods and functions.
Con1: ???
Pro2: Explanation of instance variables is simpler.
Con2: Using __self__ instead of a special first argument is less
explicit.
Pro3: Less typing and less clutter in method definitions.
Con3: Can use "s" or "_" instead of "self" to minimize typing and
clutter.
"Assignment" Syntax for Function Definitions
Pro1: See all the variables at a glance in one column.
Con1: ???
Pro2: Emphasize the similarity between data and functions as
attributes of an object.
Con2: ???
Symbol instead of def Keyword
Pro: Allows lambda functions to be included in the unification.
Con: Symbols are never as clear as keywords.
With Block
Pro: Saves typing the object name on each line.
Con: Making it too easy to modify prototypes after they have been
created will lead to more undisciplined programming.
Issues relevant to teaching OOP
===============================
Parallels between Prototypes and Modules
----------------------------------------
Ninety percent of what students need to know about prototypes is
already understood from their study of functions and modules. Even
some tricky issues are best explained by comparing to a parallel
situation with modules.
< snip >
Explanation of Instance Variables in Python
-------------------------------------------
""" Some of the variables inside the functions in a class have a
self. prefix. This is to distinguish local variables in the function
from "instance variables". These instance variables will be found
when the function is called, by searching the instance which called
the function. The way this works is that calling the function from an
instance causes that instance to be passed as the first argument to
the function call. So if you call cat1.talk(), that is equivalent to
Cat.talk(cat1) If you call cat1.set_vars( "Garfield", "Meow"), that is
equivalent to Cat.set_vars(cat1, "Garfield", "Meow")
The "current instance" argument is auto-magically inserted as the
first argument, ahead of any other arguments that you may provide in
calling a method that is "bound" to an instance. Note: The
distinction between instances and classes is important here. If you
call a function from a class, that function is not bound to any
instance, and you have to supply the instance explicitly in the first
argument ( Cat.talk(cat1) )
The variable name self is just a convention. As long as you put the
same name in the first argument as in the body of the definition, it
can be self or s or even _ The single underscore is handy if you
want to maximally suppress clutter. """
Explanation of Simplified Instance Variables
--------------------------------------------
""" Some of the variables inside the functions in a prototype have a
leading dot. This is to distinguish local variables in the function
from "instance variables". When a function is called from an instance
( cat1.talk() ) a special global variable __self__ is automatically
assigned to that instance ( __self__ = cat1 ) Then when the function
needs an instance variable ( .sound ) it uses __self__ just as if you
had typed it in front of the dot ( __self__.sound ) The leading dot
is just an abbreviation to avoid typing __self__ everywhere. """
========== END ==============
and other not-so-pretty details of Prothon, that we are missing what
is really good - the simplification of classes. There are a number of
aspects to this simplification, but for me the unification of methods
and functions is the biggest benefit.
All methods look like functions (which students already understand).
Prototypes (classes) look like modules. This will make teaching OOP
much simpler, especially for the students and professional engineers
(non-CIS) that I am most concerned about. I teach electronic design
tools, not programming. Current plans are to include some basic
Python, no OOP. If I could add OOP with another 4 hours, I would do
it.
I've written a proposal for a prototype syntax that I believe captures
the essense of what is good in Prothon, while not departing too
radically from Python. see PrototypeSyntax.htm at
http://ece.arizona.edu/~edatools/Prothon/ I would like to get
feedback from Python experts on the potential problems with this
syntax. The major question is automatic translation of existing Python
programs to the new syntax. I'm one of those users who would not give
up the existing libraries in Python, no matter how good some
alternative language may be.
I would also like to get feedback from users on what they like or
dislike about this proposal. I will summarize this feedback in the
"Pros and Cons" section of the proposal.
Below are some excerpts from the syntax proposal. Please see the link
above for better formatting.
-- Dave
Proposed Prototype Syntax
=========================
< snip >
Example of Simplified Classes ( Prototypes )
============================================
Animal --> Mammal --> Feline --> Cat
------- ------- ------- -------
numAnimals numMammals numFelines numCats
home genus
__init__() __init__() __init__() __init__()
.sound .sound
.name
show() show() show() show()
talk() talk()
proto Animal(object): # Inherit from the primitive object.
numAnimals = 0
home = "Earth"
....
<see the "OOP Chapter" at http://ece.arizona.edu/~edatools/Prothon/
for the complete example.>
....
proto Cat(Feline):
numCats = 0
__init__ n = "unknown", s = "Meow" ):
Feline.__init__()
Cat.numCats += 1
.name = n # Set instance variables.
.sound = s
show ): # Define a "static method".
Feline.show()
print " Cats:", Cat.numCats
talk ):
print "My name is ...", .name
print "I am a %s from %s" % (.genus, .home)
Mammal.talk() # Call an unbound function.
print __self__ ### Diagnostic check.
cat1 = Cat() # Create instance.
with cat1: # Modify instance variables.
home = "Tucson"
genus = "feline"
name = "Garfield"
My name is ... Garfield
I am a feline from Tucson
Mammal sound: Meow
Changes from Current Python
===========================
-- Keyword class is changed to proto.
-- All methods have the same form, identical to a simple function.
-- Function header lines are re-arranged. def --> : Parentheses are
optional.
-- self is replaced with a leading dot, and eliminated from the arg
list.
-- Current instance is available if ever needed via __self__
-- Instances can have their attributes modified in a with block.
Benefits of Proposed Syntax
===========================
-- Unification of all function forms ( bound, unbound, static, class,
lambda ). All will have the same form as a normal function
definition. This will make it easier to teach OOP. Students will
already understand functions and modules. OOP is a small step up. A
prototype will look just like a module ( except for the instance
variables ). See Parallels between Prototypes and Modules below.
-- Using an explicit __self__ variable avoids the magic first
argument, and makes it easier to explain instance variables. See the
sections below comparing a brief explanation of instance variables in
Python vs the simplified form. A full presentation of OOP, like pages
295-390 in Learning Python, 2nd ed. will likely be 1/2 the number of
pages. Not only is the basic presentation simpler, but we can
eliminate a lot of discussion of lambda functions, static methods,
etc.
-- All attributes of a prototype ( both data and functions ) will be
in a neat column, making it easier to find a particular attribute when
visually scanning a program. Understanding the structure of a program
will be almost as quick as seeing a UML diagram.
-- Lambda keyword will be gone. An anonymous function using normal
function syntax can be extremely compact. ( :x,y:x+y )
-- Method definitions will be less cluttered and less typing with
__self__ as a hidden variable.
-- Changing numerous attributes of an instance will be more
convenient. ( need use case )
-- Migration of Python programs to Prothon will be automatic and
reliable. ???
Pros and Cons of the Proposed Syntax
====================================
Classlessness
Con: The proposed syntax is not purely classless. This is important
because ... ???
Unification of Methods and Functions
Pro1: Less to learn.
Con1: Experts don't care. Beginners don't need advanced method
syntax.
Pro2: Replace lambdas with standard function syntax.
Con2: ???
Explicit __self__
Pro1: Allows the unification of methods and functions.
Con1: ???
Pro2: Explanation of instance variables is simpler.
Con2: Using __self__ instead of a special first argument is less
explicit.
Pro3: Less typing and less clutter in method definitions.
Con3: Can use "s" or "_" instead of "self" to minimize typing and
clutter.
"Assignment" Syntax for Function Definitions
Pro1: See all the variables at a glance in one column.
Con1: ???
Pro2: Emphasize the similarity between data and functions as
attributes of an object.
Con2: ???
Symbol instead of def Keyword
Pro: Allows lambda functions to be included in the unification.
Con: Symbols are never as clear as keywords.
With Block
Pro: Saves typing the object name on each line.
Con: Making it too easy to modify prototypes after they have been
created will lead to more undisciplined programming.
Issues relevant to teaching OOP
===============================
Parallels between Prototypes and Modules
----------------------------------------
Ninety percent of what students need to know about prototypes is
already understood from their study of functions and modules. Even
some tricky issues are best explained by comparing to a parallel
situation with modules.
< snip >
Explanation of Instance Variables in Python
-------------------------------------------
""" Some of the variables inside the functions in a class have a
self. prefix. This is to distinguish local variables in the function
from "instance variables". These instance variables will be found
when the function is called, by searching the instance which called
the function. The way this works is that calling the function from an
instance causes that instance to be passed as the first argument to
the function call. So if you call cat1.talk(), that is equivalent to
Cat.talk(cat1) If you call cat1.set_vars( "Garfield", "Meow"), that is
equivalent to Cat.set_vars(cat1, "Garfield", "Meow")
The "current instance" argument is auto-magically inserted as the
first argument, ahead of any other arguments that you may provide in
calling a method that is "bound" to an instance. Note: The
distinction between instances and classes is important here. If you
call a function from a class, that function is not bound to any
instance, and you have to supply the instance explicitly in the first
argument ( Cat.talk(cat1) )
The variable name self is just a convention. As long as you put the
same name in the first argument as in the body of the definition, it
can be self or s or even _ The single underscore is handy if you
want to maximally suppress clutter. """
Explanation of Simplified Instance Variables
--------------------------------------------
""" Some of the variables inside the functions in a prototype have a
leading dot. This is to distinguish local variables in the function
from "instance variables". When a function is called from an instance
( cat1.talk() ) a special global variable __self__ is automatically
assigned to that instance ( __self__ = cat1 ) Then when the function
needs an instance variable ( .sound ) it uses __self__ just as if you
had typed it in front of the dot ( __self__.sound ) The leading dot
is just an abbreviation to avoid typing __self__ everywhere. """
========== END ==============