Re: [Edu-sig] Explaining Classes and Objects

From: edu-sig-bounces@python.org [mailto:edu-sig-bounces@python.org] On Behalf Of Kirby Urner Sent: Monday, June 13, 2005 9:14 AM
[... del...]
The average beginner isn't going to know any programming, so why not start with class/object right from the top?
The Objects First approach has gained popularity among educators and seems to have become a sort of fashion. The idea is, indeed, to start teaching introductory programming with objects and even classes first. My experience is that the Objects First approach is difficult for instructors and students alike. Classes are not a feasible choice to start with because they are a most complex structure in a programming language that builds on knowledge of virtually anything else. Also, starting with classes significantly delays the study of very fundamental language elements. I have seen introductory books that postpone the simple yet indispensable decision structures and loops until as the second half of the book! Postponing basic control structures for so late in a course may deprive students from having fun with writing small yet self-contained and interesting programs. Speaking of myself, if I, when I as a beginner programmer did not know much of control structures until the second part on my course, I would not find programming very interesting. With a dynamic language as Python, it is tempting to try a Statements First approach to introductory programming. This approach may consist of (1) statement-by-statement execution in interactive mode of the Python interpreter and (2) writing statements directly within a module and executing them in file input mode. The learning benefits of interactive programming are indisputable. However, learning how to program by writing modules that are plain sequences of statements may be detrimental to the student's ability to design and write well-structured programs. Python is a language that offers a reasonable *Middle Way* between the Objects First and Statements First approaches. The Middle Way consists of (1) using functions from the very beginning to encapsulate code and structure programs, and (2) introducing control structures as early as possible, but ONLY AS PARTS OF WELL STRUCTURED FUNCTIONS. The Middle Way allows students to write interesting and well-structured programs early in the course, and prepares the ground for classes and objects in the second part of the course.
My approach is to start with a lot of a rule-based numeric sequences (the above generates square numbers): triangular numbers, Fibonacci numbers, other polyhedral numbers. This means writing a bunch of free-standing functions.
I do something similar. I start with *sets* with functions. My first program is not hello world, but a module of two Fahrenheit-Celsius converter functions: F2C and C2F (these are not pure functions and do input/print). A transition from modules (that comprise functions but not upper-level statements) to classes comes quite natural at a later stage of the course.
What I come to is it's easier to think of objects as something you use, as primitives in the language, within procedural flows.
Indeed, using built-in objects is simpler than defining and using classes. Still, the concept of objects needs two underlying concepts: variables and method (function) calls. Object variables are not so trivial because object assignment is a reference assignment and therefore creates aliases. Method calls require understanding of arguments and return values. Thus, it is beneficial to study functions, variables, and controls structures for a while, before coming to built-in objects. Personally I believe that lists, dictionaries, and strings offer a great opportunity to introduce objects. There a lot of interesting methods that can be explored interactively and that can be used to write interesting programs. Introducing objects with GUIs is OK, but GUI objects seem to offer fewer opportunities for interactive exploration than lists, dictionaries, and strings. I cover class definitions as a last theme in my CS1 with Python course. The continuation is CS2 with Java, an entirely class-oriented course. No CS2 student has ever complained that classes seem unnatural or difficult to understand. This is because, I believe, classes come at the right time - after all underlying concepts have been well understood. Atanas Radenski mailto:radenski@chapman.edu http://www.chapman.edu/~radenski/ It takes a lot of time to be a genius, you have to sit around so much doing nothing, really doing nothing -- Gertrude Stein

Classes are not a feasible choice to start with because they are a most complex structure in a programming language that builds on knowledge of virtually anything else.
We agree on a lot of points. Because just about any decent Python script makes use of core data structures, such as the list, even if only as a range() return, dot-notation starts to be relevant right from the top. Explaining dot-notation as thing.action(inputs) identifies these "things" as the objects, with dot-notation being a postfix notation for calling, setting and getting.
Indeed, using built-in objects is simpler than defining and using classes. Still, the concept of objects needs two underlying concepts: variables and method (function) calls. Object variables are not so trivial because object assignment is a reference assignment and therefore creates aliases. Method calls require understanding of arguments and return values. Thus, it is beneficial to study functions, variables, and controls structures for a while, before coming to built-in objects.
Yes, but I still need to explain dot-notation, even in the early days of just doing simple functions. Indeed, I might argue that the simplest intro to conditional flow might be the if clause in list comprehension syntax, i.e. now that we're comfortable with generating in the form [f(x) for x in range(n)], let's now add ... if x%2] or some such. However, the idea of "a list object" should already be in place by this time, i.e. we've looked at [].sort() and so on. Why I'm not so concerned about the fine points of passing by reference, aliases and like that is I'm confidant that class/object thinking is already engrained, simply through exposure to Aristotelian taxonomies. Kids visit the zoo. They understand "cat family" inheriting "mammalian" characteristics, under the kingdom of "animal" (which excludes spinach). So there's your class hierarchy, generic blueprints vs. instances, and individual state variables. Now express that in dot-notation e.g. thetiger.yawns(). In other words, go to the roots of the metaphor and forget about the nitpicky details of computer languages. Come back to that later, but get enough of the concepts to make dot-notation comfortable very early in the game. I'm a philo major, not a CS major, which may account for my willingness to "forget about ... computer languages" from time to time (whenever convenient).
Personally I believe that lists, dictionaries, and strings offer a great opportunity to introduce objects. There a lot of interesting methods that can be explored interactively and that can be used to write interesting programs. Introducing objects with GUIs is OK, but GUI objects seem to offer fewer opportunities for interactive exploration than lists, dictionaries, and strings.
I'm inclined to agree. On the other hand, I see a need to instill in newcomers that visualization is going to be part of what's coming. They want some assurance up front that graphical content won't be ignored. So sometimes I feel pulled towards GUI-based examples ala John Zelle's graphics.py simply because I know students *want* to go there, and I'm reluctant to resist them. That being said, I don't like doing *only* GUI-based examples. Anyway, IDLE is a GUI, so if you're doing shell in IDLE, you're ipso facto using a GUI (the same could be said of an x-term window).
I cover class definitions as a last theme in my CS1 with Python course. The continuation is CS2 with Java, an entirely class-oriented course. No CS2 student has ever complained that classes seem unnatural or difficult to understand. This is because, I believe, classes come at the right time - after all underlying concepts have been well understood.
Atanas Radenski mailto:radenski@chapman.edu http://www.chapman.edu/~radenski/
I think this is a viable and likely-to-be-popular approach. Use Python for a first year, then switch gears and get more heavily into OO at the same time, say with Java or C# or... Some will encourage Jython (which I have no problem with -- wish I had more time to play with it). My own framework is based in somewhat different assumptions: pre-college students trying to avoid learning everything twice, once *with* dot-notation and once without. My working hypothesis: the class/object metaphor is useful enough to merit inclusion of dot-notation in mainstream K-12 mathematics. For example, if you want to invert a matrix, write thematrix.invert() -- presuming its invertible. Or you can still write thematrix**(-1) too if you like (operator overloading at your service). So in my course, we're learning about matrices, vectors, polynomials, integers modulo N *as objects*. It's a "programming to learn" course, i.e. the use of Python is a means to an end: a stronger conceptual grasp of various core mathematical ideas, algorithms, ways of approaching a problem. We have yet to clearly differentiate between CS and traditional mathematics at this level (that comes later, when it comes time to specialize). Kirby

Kirby Urner wrote:
Classes are not a feasible choice to start with because they are a most complex structure in a programming language that builds on knowledge of virtually anything else.
We agree on a lot of points.
Because just about any decent Python script makes use of core data structures, such as the list, even if only as a range() return, dot-notation starts to be relevant right from the top. Explaining dot-notation as thing.action(inputs) identifies these "things" as the objects, with dot-notation being a postfix notation for calling, setting and getting.
Yes, but I still need to explain dot-notation, even in the early days of just doing simple functions.
You might try: "These names don't just exist in some primordial soup. There has to be a place they get stored. There is a bit of "magic": import __main__ a = 24 print a, __main__.a __main__.a = 365 print a, __main__.a And even: print a, __main__.a, __main__.__main__.a Now everything is dot notation, with some of the "thing." stuff assumed. Eventually you'll have to say locacal variables don't really work like that, but they are close. --Scott David Daniels Scott.Daniels@Acm.Org

You might try: "These names don't just exist in some primordial soup. There has to be a place they get stored. There is a bit of "magic": import __main__ a = 24 print a, __main__.a __main__.a = 365 print a, __main__.a
And even:
print a, __main__.a, __main__.__main__.a
After which I might go:
dir(__main__) ['__builtins__', '__doc__', '__main__', '__name__', 'a'] dir(__builtins__)
That'd connect back to Laura's focus on exception handling -- clearly the Error related content in __builtins__ is significant.
type(ArithmeticError) <type 'classobj'> dir(ArithmeticError) ['__doc__', '__getitem__', '__init__', '__module__', '__str__'] ArithmeticError.__module__ 'exceptions' EnvironmentError.__module__ 'exceptions'
import exceptions dir(exceptions)
Now everything is dot notation, with some of the "thing." stuff assumed. Eventually you'll have to say locacal variables don't really work like that, but they are close.
universe.milkyway.sun.earth.hawaii.maui is another way to introduce dot-notation. It's about progressively zooming in, or out, through a succession of progressively more, or less, encompassing domains. This gets us back to the root class/object metaphor, which allows us to appreciate the ordinary interaction of any two objects as involving encapsulation, polymorphism and message-passing i.e. the original SmallTalk paradigm. Kirby
--Scott David Daniels Scott.Daniels@Acm.Org
participants (3)
-
Kirby Urner
-
Radenski, Atanas
-
Scott David Daniels