Wilson B. wrote:
What are some key points I should make sure to cover for procedural programmers?
Things on my list so far:
- Variables don’t hold values, they are just labels.
We hear that a lot, but, somehow, it never sounds right. If variables
are labels, why don’t they follow the object around, and become
accessible to other users of the object? How do I calculate how many
labels an object has? Is a label an object? Can you change the text of
the label? Do they ever fall off when the glue dries out?
Anyway, variables do hold some kinds of values, like numbers,
booleans, and symbols, in almost exactly the way that C variables “hold”
values. Ironically, the only thing that ruby variables hold is VALUE,
as it is called in the source.
So, what to say to COBOL programmers?
I know little of these early 60’s programming languages of which you
speak. However, if I were introducing ruby to C programmers, I would
show them the basic data types in ruby.h. Values are passed around as
unsigned long. Types like integers, symbols, etc. are encoded by certain
bit patterns. Other bit patterns encode pointers to heap-allocated
structs, which represent almost everything else: strings, arrays, user
defined objects. All assignment and argument passing is just copying
long words. An array is represented as a C array of long words that
encode either immediate values or pointers. Array access just means
getting and setting one (or more) of these long words.
This may seem extreme, to look at the implementation on the first day.
But it is very concrete, enough to inoculate against the usual
confusions: Is ruby pass-by-reference or pass-by-value? Why are there
are no destructive methods on Fixnum or Symbol?
- Duck typing makes testing easier.
It also makes libraries more useful, if the libraries are written to
assume as little as possible about the objects they interact with.
Grokking this point is a major step in learning to write ruby programs
in ruby, rather than write cobol programs in ruby.
In general, I don’t think it can hurt to be concrete, or to at least
give a concrete view of things as an alternative. For example, message
evaluation happens by looking up a symbol in the receiver’s table, and,
if no entry is found, iterating up the superclass tables. For some
people (esp. those with a procedural background), that means a lot more
than “this object over here sends a message to that object over there,
which can either respond to it or let its superclass handle it”.