Thursday, February 09, 2006

Processing Notes, 8 February 2006

Last night's lecture topic was shape grammars. Since we spent much of the time on background and theory, my Processing reflections are skimpy-er.

Method listing: I tend to find the sophisticated code completion features of environments like Eclipse to be overkill, but one specific tidbit would help novices learning to program with Processing: Method listing, or being able to see a list of all the methods defined on an object. Don't bother with changing what I'm typing — no one ever wants that — but instead follow another common interface metaphor: Select a bit of code, right-click, [Processing parses that tab's AST-and-thinks,] and then show a list of methods in the context menu. Oh and if you don't have a right mouse button, stop drinking the koolaid.

This is important for Java-specific classes, since Sun goes through great effort to bury and obscure the JDK documentation. Kinda like their API... (Thank you javadocs.org.) Coping with inconsistent naming schemes is another good reason (.println() for “print line” but .printMatrix() for “print matrix”). And lastly, method listing would encourage better software design, as the names chosen for methods will be more visible by “trickling up.”

Arrays as primitives: The newer releases of the Sun's JDK reveal one of the early design mistakes in Java, since arrays have become progressively more like proper high-level data types. Processing should embrace this by providing someArray.length() as a pseudo-method on arrays (note the parens), instead of the inconsistent someArray.length. For novices, inconsistency details matter.

Duck typing: Not so much a Processing enhancement, but my crying over another in a long line of student questions about the utter madness of teaching novices un-duck typed languages:

Student: Why do we have to cast what comes out of the vector?
Lecturer: Because Java is a overly typed language.
Student: Huh?
Lecturer: Because it's faster. Or something.
Student: But don't we usually ignore performance problems while learning to program...?
Lecturer: /cries

On on that cheery note, that's it for this week.

Friday, February 03, 2006

Teaching Interfaces

A recent comment on Toxi's blog asked about techniques for teaching novice programmers about interfaces, in the context of the Processing development environment. My approach starts by taking a step back from Java's OO biases, and asking about interfaces in general. Contrary to Sun's marketing, interfaces are not best understood as a gentler version of C++'s multiple inheritance. Instead they are a language construct for explicitly representing an object's Contract. A class implementing an interface is guaranteed to provide "at least" a certain sort of behavior, by which we mean "methods."

Considered as a syntax for specifying class contracts, we've found a decent metaphor for teaching: It is quite natural for students to understand the necessities of Contract, and even to understand interfaces as a restriction on "freedom." An object is free to behave in any way it likes, as long as it does at least X, Y, and Z... Three behaviors the rest of the world is expecting of the object.

Please forgive my blurring of "class" and "object" above. This reveals another of my software writing biases, this time for prototype-based languages. Here even my cherished Ruby falls short. Prototype-based languages make no distinction between "classes" and "instances." Everything is just an "object." Create a new object by cloning a already-existing one, and then customize its behavior by dynamically adding methods and data. It is the context of how an object is used that determines its "abstract-ness." If one only ever clones an object but doesn't use it, that object is effectively an abstract class.

While prototype-based design can be quite a leap for OO programmers accustomed to the C++/Java way of doing things, it is actually quite easy to teach novices. Since prototype objects are closer simulacra for physical objects, we needn't use such stretched teaching metaphors. No more "classes are blueprints," and "instances are houses."

Imagine being able to shrug off awkward explanations of both the static keyword and the new operator, without any significant loss in elegance or expressiveness. I would love to see Processing do prototype-based OOP.

Thursday, February 02, 2006

Processing Notes, 1 February 2006

Last night's lecture on genetic algorithms:

Be wary of method argument names: When writing code for students, try not to give method arguments the same names as the outer scoped variables. This is difficult to explain but easy to demonstrate:


void func(int width, int height) {
    // do something with width and height
}
// later
int boxw = getBoxWidth();
int HEIGHT = getAnotherHeight();
func(boxw, HEIGHT);


is more instructive than:


void func(int width, int height) {
    // do something with width and height
}
// later
int width = getBoxWidth();
int height = getAnotherHeight();
func(width, height);


Again this may seem overly subtle, but the former style gives a visual cue to groking variable scopes.

Function side-effects: Methods that return values should have few — ideally zero — side effects. Novice programmers are comfortable with the "formula" metaphor from high school algebra, but side effects will tempt this metaphor to bite back.

And now two more features for Processing to help in teaching programming to designers and architects:

Comparable and casting: High level array sorting and inserts are provided by the Java Comparable interface. Since Java is overly typed, implementing this interface almost always requires casting. Object casting is an absolutely brutal concept to teach. Instead Processing should provide a method in all classes called "toNumber()" which converts an instance into a numeric representation. All classes should by default implement Comparable, and should by default implement "compareTo()" as:


int compareTo(Object o) {
    ProcessingObject processingObject = (ProcessingObject) o; // cry...
    if (toNumber() < processingObject.toNumber()) {
        return -1;
    }
    else if (toNumber() > processingObject.toNumber()) {
        return +1;
    }
    else {
        return 0;
    }
}


Programmers could just override "toNumber()" in their subclasses, and then "Arrays.sort()" would work magically. Sorting by a numeric representation of an instance is by far the most prevalent.

Random array elements: Selecting a random element from an array or Collection is a common idiom, but also a obscure, bug-ridden one. Implementing it requires students to understand zero-based array indexing (as opposed to natural one-based), float to int conversion for the index and pseudo-random numbers. Processing should implement an additional "faux-method" on arrays like "array.randomElement()" that does:

return ar[(int) (random() * ar.length)];

Until next week.

Wednesday, February 01, 2006

Response to Tom

Thanks for pointing me at the auto-format. Any way I can blame this one on my students?

Your point about () for no-arg methods is sorta beside the... point. The real source of the problem is ambiguity that "obj.gizmo" could ever be a reference to a member variable. Processing should have (force?) implicit accessors ala' Ruby.

Processing does a bunch of little things to deemphasize stack traces: truncated traces, line numbers are mangled, no reference to tabs, no browsing based on the stack trace, etc. I say "deemphasize" instead of "buggy" because stack traces are such a fundamental part of debugging that I can't imagine these problems getting through — unless they're almost intentional?

I'm not going to submit Processing bugs to Bugzilla because I wouldn't do myself justice, and it would be flamebait: "1.) Replace Java with Ruby, 2.) Replace all custom GUI widgets with standard Win32 / Aqua / Qt toolkit components, 3.) Emulate all OpenGL functionality in P3D, 4.) Implement a comprehensive unit test suite so there are no steps backward on new releases," etc.

Processing is explicitly designed for doing computer graphics. Doing computer graphics in a development environment higher level than C/C++ over OpenGL or DirectX will compromise your performance. Thus if you program in Processing you already accept a compromise of weaker performance for higher level language constructs. So a Processing developer should have access to constructs like arbitrary-precision, ubiquitous floats.

Teaching architects and designers ubiquitous, arbitrary-precision floats is easy. It's the principle of least surprise; it's what people expect.

Maybe instead of your Processing sketch skeleton macro, just start with each of those functions as a tab in every project?

Positions and vectors are probably the same class (hierarchy). "...modeling a velocity vector and a spatial position with the same underlying data structure." It needs to be drilled because most students balked at a general Point class.

Scope and heaps are hard to teach. Their faces always glaze over when I talk about visibility and local-clobbering-global. Must more about this.

Processing Notes, 25 January 2006

I am a lecturer on an MSc course at the Bartlett in UCL, and one of my friends Tom suggested I keep a log of particular difficulties in teaching architects and designers to program via the Processing platform. Thus disclaimed are my digressions from rare postings on chefery, politics and Potter.

Divuldging my side of the fence: I feel Procesing is a deeply flawed albeit contagious and buzzy platform for teaching programming. My criticisms are plenty but now public — because "in the trenches" teacher and student would benefit from these gripes being addressed. It behooves the whole community if nascent programmers come away from their terms spent in Processing with academe nostalgia, not flight. Their appraisals at future design and architecture gigs will make or break Processing, either promoting or dashing its current momentum.

And so, my notes from last week's lecture on boids:

Algol to C to Java to Processing: Matching curly braces — or begin/end blocks — is a necessary evil in this lineage of programming languages. Processing helps by highlighting a matching brace while hovering, but this is of limited use to students who are learning by cut 'n paste. A more helpful feature would be an "auto format" option to indent and align a tab of Processing code, especially after said code has been mangled by many-a CTRL-V. Check, thanks Tom.

No argument methods and functions: Other 4GL languages skip the irritating verbosity of parentheses when passing no arguments, so why shouldn't Processing? Think "obj.meth;" instead of "obj.meth();". Like many of my criticisms, this may seem pedantic nit-picking of the Java legacy. However these sort of redundant redundancies just devastate novices.

Stack traces: Processing should move my cursor to the correct tab and line of a particular stack trace. There seems to be a deemphasis in Processing on making stack traces visible, but they are actually a very natural and linear way to review a program's logic in hindsight. At the bare minimum, Processing's stack traces should at least list line numbers and tabs.

float vs. int: Now we come to probably the most consistently baffling and frustrating (to both teacher and student) aspect of learning to program with Processing. The distinction between floating point numbers and integers, and the accompanying nasty casting, is fundamentally non-intuitive. This is the 21st century; memory, disk and CPU are cheap. Have the stones to make everything arbitrary-precisioned floating point numbers. All literals and all numeric variables are this "super float," and let the interpreter or compiler worry about the optimizations of when-and-where a value can be coerced for faster integer math. From the learning programmer's perspective, it is almost maddening that "1.0/99 != 1/99". And in light of Processing's already compromised performance, please ignore anyone saying "but it'll be slow."

Not criticisms of Processing specifically, but general practices to remember when teaching designers and architects to program:

Top down: Professional developers grow accustomed to a progressive focus on the minutiae of a problem, while gluing these pieces together "later." Long experience in writing software, or a background in mathematics, facilitates this minutiae-driven programming process. Though you may know this bit of code will be needed eventually, it is more conducive to teaching good programming style — or to teaching programming at all — to work from the top down.

Even if it does not resemble your actual programming practice, live lecture or lab demonstrations of coding should invert the minutiae thinking: Code and discuss the most general logic of the program first, and fill in the blanks later. One of my first programming teachers taught programming in this style, and while demanding of the lecturer, it is deeply instructive to code the skeleton first.

Vector vs. points data representation: While we're used to modeling a velocity vector and a spatial position with the same underlying data structure, this is a significant leap for students getting used to 3D programming. This is true even for those designers and architects comfortable with a CAD package. Drill this "not distinction."

Heap data is sorta global: Yet another murky legacy of Algol-ish, side-effect-ridden languages is the confusing heap; that an object instantiated in a small method, but referenced via a stack variable that is eventually returned, is visible to the caller — another conceptual leap for novice programmers. A visual diagram of a simplified heap can help. A purely functional language for learning would help even more...

While these feature requests are certainly not on the grand scale of software methodology practics, these sorts of "little things" are what enable frequent and vicious refactoring, a vital practice in good top-down object oriented (OO) development.