My buddy Adam Williams @aiwilliams tweeted this link., which is, at it's roots, about the dangers of doing more than should be done.
Feature creep is one temptation which leads to overdoing, and thus doing the wrong thing. Another is obsessively trying to remove all defects. As they say "Perfect is the enemy of good."
Which reminds me of an old chestnut from my earler days. I've provided some footnotes for younger readers
The Perfect Program
no program's that perfect" they said with a shrug. "the client is happy-- what's one little bug?" but he was determined the others went home he dug out the flow chart (1) deserted. alone. night passed into morning the room was quite littered with core dumps (2) and punch cards (3). "i'm closer." he tittered. chain smoking, cold coffee. logic, deduction. "i've got it!" he cried. just change one instruction. then change two, then three more as year followed year. and strangers would comment "is that guy still here?" he died at the console (4) of hunger and thirst next day he was buried face down, nine edge first. (5)
Footnotes
- A flow chart was a primitive form of program representation, comprising variously shaped boxes connected by lines and indicating the control-flow of a program. This was in the days when programmers wanted to be like engineers, and we all know that engineers draw stuff on big draft boards before they build anything. This idea lives on in ideas like UML. It's still a bad idea.
- Back in the days before laptops, behavior driven design and continuous testing, programmers would submit their programs to the big computer locked up in a room and attended by priests called operators. The priests would offer the program up to the computer, and return with a reply. If something went wrong, you got back a large stack of paper which showed a picture of what was inside the computer when things went south. Back then the inside of the computer had memory comprised of little magnetic donuts called cores woven into a matrix with wires, so memory was called "core" A core dump was that picture of what was in the computer. This was as close as we had to a debugger back then.
- Punch cards were strangely shaped index cards, the shape was something like a widescreen TV compared to a normal index card, three of the corners were rounded and the upper left corner was beveled.
Each card held 80 whole twelve bit words, or the equivalent of 120 bytes. Each bit was a hole bit since it was represented by the presence or absence of a hole in a particular row or column. Each column was a word. In most cases using all of the bits on a card was rare. Usually each column encoded a character, in some archaic encoding scheme like EBCDIC.
Programs were kept as large stacks of these cards, and these stacks would be fed to the big computer through a machine called a card reader. The holes would be punched into the cards using a kind of typewriter (a primitive kind of laptop/desktop comprising a keyboard and a printer) called a keypunch, which instead of printing what you typed on paper, punched it into cards.
Usually the computer would output to a printer, but some older printers output back to cards through another machine named, strangely enough a card punch. In these cases there was a separate machine detached from the computer which could read decks of cards and print their contents to a printer.
If you were really lucky, the computer would combine the card reader and punch with one input hopper. You would put your program deck into the hopper, followed by (carefully counted) blank cards for the output. One fun experience was to put your program into the hopper when a program was running with insufficient blank cards before you, in which case the machine would happily overpunch part or all of your program with the first guy's output.
For those who fell for static typing, there were specially printed cards for different programming languages, here's a FORTRAN card there were also COBOL cards, although the computer and card readers used duck typing, they really didn't care what was printed on the card, only the holes, the whole holes and nothing but the holes.
- The console was the machine through which the priests, and sometimes programmers, directly interacted with the big computer. It was a rare privilege for a mere programmer to have access to the console, it usually happened late at night on third shift when the priests wanted to sleep. What no, terminals/workstations/laptops you say! ha!
- A reference back to punch cards. Each row of bits on the card had a number. For some good reason, the top two rows had the numbers 12 and 11 and were called zone rows. The non-zone The remaining rows were numbered 0 through 9 with 9 at the bottom. A card deck could be put into a reader, punch, or reader/punch in four orientations. The deck could be inserted face (printed) side down, or face side up, and with the 12 or the 9 edge entering the machine first, hence "face down, nine-edge first." It was important to get this right, even more so when submitting a job than burying a dead programmer.
Gawd how I miss the old days!
NOT
From one of the many non-Ruby blogs I follow comes this collection of strange duck-types.
A bit off the beaten track for this blog, but, “if it quacks…!”
For some reason, talk on ruby-talk brought up old computer stories. David Black related a story told him by a former boss about a “photo op” in a company computer center triggering failures when the photographers’ flashes upset the optical sensors in the tape drives.
Since I’m sitting in a hospital cafeteria this afternoon waiting to see my wife who just had some surgery. I figured I might amuse myself, and hopefully you gentle reader with some old mainframe war stories.
Tale #1
When I was an undergraduate, I used to spend all my free-time (and much of my non-free time) at the University computer center. There was a large room for student use with keypunch machines on the walls and worktables in the center.
One of my friends was a graduate student who was working on a team writing an Algol compiler as a term project. They had broken down into teams, lexical analysis, parser, code generation ,etc. They were in the middle of integration.
The “source code control system” was a large punch card box. For those who haven’t seen them these are long corrogated cardboard boxes which hold a big stack of cards and have a lid hinged in the back.
The team was making a series of debugging runs, they would take turns carrying the box to the room with the card reader and offer the contents to the god in the mainframe as their latest ‘sacrifice.’ When the listing came back, they would spread it out on the table and figura out what to do next.
This wasn’t ‘pair’ programming, it was ‘septet’ programming.
I was sitting at a nearby table helping another student with a homework assignment, and glancing occasionally at the compiler team.
The guy with the card box came back from the reader to see his team-mates vigoursly discussing something they had seen in the last run. He was carrying the box in front of him, his fingers wrapped around the bottom, and his thumbs holding the lid down. He walked up to the table gaining interest in the discussion. As he leaned over the table, he absent-mindedly rotated his wrists and relaxed his thumbs!
They spent the next hour or so trying to ‘revert’ the deck from the last listing.
Thank God that today we’ve got cheap hard-disks and subversion!
Tale #2
Same time frame and place.
Tom was another graduate student friend. He was an older guy who had come back to school after spending some time in the trenches in Texas. Back in the early 1970s there was lots of data processing done by what IBM called “Unit Record Shops.” Tome had worked in one before coming to graduate school.
In IBM parlance a punched card was a unit record since the file record (I guess we’d call it a row in SQL these days) and the physical unit, the card, were one and the same.
Unit record shops, didn’t have computers, which in those days were investments on the order of a million dollars, give or take an order of magnitude or two. They did everything with decks of punchcards and machines which sorted, collated, or printed them. These machines were ‘programmed’ by connecting holes in plugboards with wires.
Tom said that once he’d accompanied his boss to a trade show. The boss, like many others, didn’t have a really good grasp of the technology his business used.
The boss saw Tom on the show floor and told him, “Tom, come here, you’ve got to see this!”
He led Tom to a booth where a “booth babe” was loading a rainbow-colored stack of cards into the input hopper of a machine, and pushing the start button at which point the machine put all the blue cards in one slot, the yellow cards in another, and so forth.
Tom couldn’t figure out why the boss was so impressed, surely he’d seen sorting machines before. After all they has several of them at work.
Then the boss showed his hand.
Tom, I’ve seen lots of fancy machines in my day, but this is the first one I’ve ever seen that could sort by color!
Even today, it’s too easy to create demos with lots of flash and no substance.
Maybe I’ve gotten a bit sensitive of late to the perception some Rubyists
seem to have of Smalltalk-bred Rubyists like me. So I thought that I might say a bit more of what
I think of the current and future of Ruby as a language.
What follows is much longer than what I expected it to be when I started writing it yesterday,
I hope that some will find it some combination of interesting, useful, thought-provoking, or
at least amusing.
- This weeks meeting of the raleigh.rb
group was a recap of railsconf 2007. Some of the attendees seemed to have gotten
a feeling that Avi Bryant was attacking Ruby in his keynote. I can’t speak for
him, and I wasn’t there so this might just be my reaction. - Heard this week on ruby-talk in a discussion of the fact that Module#ancestors doesn’t
include a singleton class of the receiver should it have one:
I do not want to argue with the wise guys if it is an error – I
clearly thought so but that is not important ;)
But it really would have saved me an hour of debugging if the doc
stated clearly that singletons are not included. I thought this might
help others and as it took me 20s to vim the missing line into class.c
- Robert DoberTo which I replied:
As far as I can tell, singleton classes aren’t mentioned in the doc.
The documentation borders on folklore.
Singletons as a means of implementing both individual instance, and
class behavior have a position like “the man behind the curtain” in
“The Wizard of OZ.” We’re really supposed to disregard them.
Coming from a background in Smalltalk, my preference would be if this
machinery were more visible and official, but Matz has his reasons for
not doing so. For one thing, not documenting it, and hiding it from
methods like ancestors and class makes it easier to tinker with as the
language evolves without “officially” breaking backward compatibility.Which prompted:
Does that mean that no one who’s ever used Smalltalk can ever think
that it’s right for Ruby to deviate from Smalltalk? :-) I ask in a
humorous spirit – and also because it gives me an excuse to mention:
http://www.infoq.com/articles/coming-from-ruby
— David A. Black
To answer David’s humorously posed question, No,
and I present myself as “exhibit A,” because I certainly think that it’s right
for Ruby to deviate from Smalltalk. My main motivations in writing about Ruby in the context
of my Smalltalk background are first to help myself, and I hope others, understand Ruby a little
better by providing some perspective from another, earlier, dynamic language, and second, to a much
lesser extent, to air ideas of how some of the features of Smalltalk might be incorporated or
adapted as useful additions to Ruby as it evolves.
In many ways, I like Ruby better than I like Smalltalk. To name a few reasons, Ruby is more dynamic, has a more flexible deployment ‘model,’, and
albeit it’s not a technical reason, it’s not carrying the burden of the old business model of
trying to get thousands of bucks for each development seat.
This
is what really allowed
Java to pop Smalltalk’s balloon. Smalltalk was seen by IBM and it’s competitors as “enterprise”
technology, and they expected the same kind of prices which
other corporate level software development
tools commanded. When Java came out and was free “as in beer,” it gained a large popularity with
language hobbyists/hackers who could easily get it to play with, and a lot of those guys worked
for the companies to which IBM, ParcPlace-Digitalk, and the others were catering.
The other aspect of Java which helped at the time was it’s relationship in
syntax, and a lot of its semantics, to C++ at a time when there was a lot of corporate C++
activity and some frustration was starting to be felt with the complexity of C++. Java
felt enough like a simplified and friendlier C++ being a language which was more dynamic
without “going all the way” and which
felt familiar to both C++ advocates and C++ approach to
strongly typed class hierarchies, and C++ programmers with symptoms of the
Stockholm syndrome.
These self-same aspects of Java caused many Smalltalkers to be uneasy with
the language.
The real salvation of Smalltalk, as it exists today, was and is Squeak. I remember when I
first encountered Squeak, it was at a Birds-of-a-feather session at OOPSLA, right when Java was
really starting to get most of the mind-share. My impression was that the atmosphere in the room
must have been somewhat like that in the Roman catacombs when the early Christians were
hiding out.
I guess that there is still a bit of the old “Enterprise” Smalltalk market,
Instantiations, which took
over the old IBM/VisualAge Smalltalk base when it fell out of IBMs strategies,
sells it for an entry price of
$6,995. There must be enough of the old legacy corporate Smalltalk customers around who
buy it.
Personally, it’s been quite a while since I was an active Smalltalker, I made an oddyssey
through Java-land with IBMs shift in priorities. I plan to write about some of my
feelings during that period in retrospection but that’s for a later date.
I haven’t been
keeping up with Squeak enough to know how and how much it has evolved the Smalltalk technology
and community.
Old Smalltalker’s perceptions of Ruby
I always thought that Smalltalk would beat Java, I just didn’t know that it would be called
‘Ruby’ when it did.— Kent Beck
I ran across this quote for the first time a few weeks ago. It sounded like
something that Kent would say, and also something that I would like to quote myself, but just
to make sure, I asked him. He told me that ‘yes’ he had said it in a private communication to
someone else, and both he and the original recipient had only recently found out that it was
becoming an internet meme. Googling <a href=""I always thought smalltalk would beat java">
“I always thought that Smalltalk would beat Java” garners over 250 hits.
Kent tells me that he’s a Ruby fan. Ward Cunningham is also.
I asked Ward, just before RailsConf,
if he was going since it was in his home-town.
He said that he had found out about it after
registration was closed, but he was planning to hang out at the hotel anyway. From what I heard
last night he was recognized and invited to attend.
Several of my other old Smalltalk buddies, who had also gone through a period with Java,
seem to have the same feeling which I do, that
looking at and using Ruby feels like being a widower who meets a new woman, who just seems to
be a partial reincarnation of the former spouse.
Where You Are Come From Depends On Where You Came From
Getting to David Black’s article. He certainly has a point about letting Ruby be Ruby. As
I’ve said, I’m quite happy with Ruby.
Getting back to the early perceptions of Java, and making an analogy with natural languages
let me suggest that if we think of Smalltalk as Italian, and C++ as German, Java is
Alsatian, and Ruby is French.
Were it not for Squeak, Smalltalk might be Latin instead of Italian.
The most un-Smalltalk like thing about Ruby, to me at least, is the syntax,
Smalltalk has almost
none, many Smalltalkers say that Ruby has too much. I thought so initially, but now
I’d argue that the flexibility and
“sugarary” aspects of Rubys syntax are what makes it so successful as a host for internal DSLs
like Rake, Rails/ActiveRecord, RSpec, etc. etc. which would be far less
natural in Smalltalk with its extremely limited syntax.
One of the complaints I often
heard about Smalltalk was it’s ‘different’ syntax just unary, binary, and keyword message send
expressions, blocks, parentheses for expression grouping, the use of ‘;’ to send a message
to the object which got the last one,
and single value assignment, and a way to return a value, everything else,
including class and method definition, and control flow was built from these atoms.
Ruby probably appeals to a broader audience
since it looks enough like something like Java not to be considered too wierd, at least not at
first. For one thing in ruby 1 + 2 * 3 is 7, instead of 9 in Smalltalk due to its total lack
of operator precedence.
But, syntax differences aside, conceptually both Smalltalk and
Ruby are romance languages, as compared to the Teutonic C++ and it’s kinder-gentler relative.
Language Evolution and Cross-Breeding
Programming languages evolve much like natural languages. They pick up influences from
other languages and incorporate them with modifications. English is the equivalent
of a multi-paradigm language, it has been influenced by the languages spoken by both the conquered
and counquerors of English speaking lands. It’s been influenced by Vikings, Normans, and Indians (both the Asian and American meanings of the last).
English has a lot of synonym pairs one from French and
one from Anglo-Saxon with it’s Germanic roots. Pork and pig; beef and cow; fraternity and brotherhood. This comes from the days after the Norman conquest when the language of the English court
was French. Bill Bryson describes this in his book
The Mother Tongue""The Mother Tongue".
Many of the words considered “fancy” by English speakers are of French origin. Kent
Beck told me that while he was working in Zurich on a contract with a Swiss bank, he found that
an effective way of communicating with the programmers there, was to use simple English grammar,
but “fancy” English vocabulary. The latter helped because the Swiss programmers facility with
French increased the chances that they would share such word.
Multi-lingualism
There’s an old joke which goes:
What do you call a person who speaks two languages?
Bilingual.
And what do you call someone who speaks only one language?
An American.
Most good programmers, even the Americans, are multi-lingual when it comes to programming
languages. As it does with natural languages, this gives a broader perspective.
But multi-lingualism sometimes makes it hard to compartmentalize language concepts.
Once on a trip to Zurich,
I was having dinner with Erich Gamma, some other Zurich OTIers, and a couple of customers in a
very nice restaurant on the Bahnhofstrasse. My facility with German fills a small thimble,
but as I perused the large menu, with no obvious English to be seen, I realised that I was reading
it rather easily, and thought to myself, “Hmmm, I’m starting to understand German.” Then I
realized
that the menu was in fact bi-lingual, but the second language was French, a language with which I do have some facility.
I suspect that the “coming from x” quotes in David Black’s article are the result of this
difficulty in compartmentalizing by newcomers to Ruby.
A Living Language
Programming languages, like natural languages, survive best when they evolve, this is what
distinguishes live languages from dead ones. Languages die as the number of speakers diminish,
despite revival attempts like Winnie Ille Pu,
Quomodo Invidiosulus Nomine Grinchus Christi Natalem Abrogaverit: How the Grinch Stole Christmas in Latin,
Harrius Potter et Philosophi Lapis (Harry Potter and the Philosopher’s Stone, Latin Edition), or
the Vicipaedia.
Ruby is evolving, the core-team isn’t asleep, right now ruby1.9 is the cauldron to which new
potions are being added to brew what will emerge as the next major Ruby revision.
This is another area where Ruby and Smalltalk have similarities.
Smalltalk started as a paper design by Alan Kay to win
a hallway bet challenging his assertion that he
“could define the ‘most powerful language in the world’ in ‘a page of code’.”
Dan Ingalls then actually implemented it in Basic on a NOVA minicomputer, this
begat Smalltalk-72,
which begat Smalltalk-76, which begat Smalltalk-80. Smalltalk-80 was the basis for the
commercial Smalltalks of the pre-Java era, VisualWorks Smalltalk (ParcPlaces commercial Smalltalk-80),
Smalltalk/V which merged with VisualWorks when ParcPlace and Digitalk merged, and IBM/VisualAge
Smalltalk. Squeak is also a child of Smalltalk-80.
Smalltalk started to freeze when it became commercial. We tried hard to forge a standard in
X3J20 which allowed evolution and variation by underspecifying things as much as we could, but
broad enterprise acceptance slowed things down quite a bit.
So it’s exciting to see that Ruby is evolving. I hope that it too doesn’t get bogged down
in it’s success.
Personal Preferences
Finally getting back to my “Coming from Smalltalk” quote in ruby-talk, I expressed a personal
viewpoint that Ruby would be well-served if the mechanisms of singleton classes, and their use
as metaclasses were made visible and officially documented parts of the language.
If the rationale for not doing so is to preserve “freedom-of-action” in changing the
implementation in future versions, I can understand it, but to used a mixed language
expression, that is a “two-edged katana.” One of the things which Alan Kay told me a long time
ago was that he was disappointed that so few Smalltalkers experimented with changing and
extending Smalltalk by building off of the mechanisms of Class, Metaclass, and Behavior.
In Ruby, despite the fact that knowledge of the equivalent implementation is only known
“sub-rosa,” there is much more such experimentation.
Metaprogramming in Ruby is au courant, and lots of code is being written which depends on
undocumented “stuff.” I have to ask if this, being undocumented that is, is a good thing.
So, to wrap this all up, while I do “come from Smalltalk,” Today, I live in Ruby!
$. Or at least implicit $
Just seen on ruby-talk:
Do we have such things for getc(), too?
If we call gets(), the returned string is copied to a special variable $_
No, implicit global variables are evil. I'd rather remove $_ in the future.
matz.
Maybe the reason that Matz picked $ as the sigil for global variables wasn’t to follow perl!
And this just after we learn that “Fahrenheit-451” was about the dangers not of government censorship but of TV."
Five doctors go duck hunting, they draw lots to determine the order in which they will shoot from the blind.
The Psychiatrist gets the first chance.
A flock of birds fly over. He looks down at his shotgun and says
They look like ducks! They sound like ducks! I wonder how they feel about being ducks?
Meanwhile the birds fly by.
Next up is the internist:
They look like ducks! They sound like ducks! But we can’t rule out the possibility that they might be geese.
Then the general practitioner:
They look like ducks! They sound like ducks! What do you guys think?.
The surgeon takes his place next. He confidently feels the trigger of his shotgun with his highly skilled right forefinger. The next flock flys over.
Bang! Bang!
And the surgeon turns to the pathologist and says:
Check them out and see if they are ducks.
I’ve known this joke for quite a few years, but I’ve never thought about it in relationship to software, until I started playing around with Ruby, and discovered an old friend under a new name, “Duck Typing.”
Last week, I ran across a thread on the ruby forum called “I’ll have the Duck!” which quickly got lots of responses, and seems to have ended up with jokes.
Most of this thread seems to miss the point of duck typing.
Once you’ve really grokked duck-typing you become like that surgeon. Your perception of the properties of objects that really matter changes. And you learn to use the pathologist (testing) as a powerful ally.
Many programers coming to ruby from languages like C++ and Java are like the psychiatrist, internist, and general praticioner in the duck hunting story.
They want certainty in their typing. They’ve developed the expectation that early type-checking by a compiler will keep them from making mistakes.
The problem with this expectation of the power of early type checking is two-fold.
- It doesn’t really work
- It is overly constraining
It doesn’t work because the bugs caused by type-checking errors is a small subset of buges in general. Besides, in a fully object—oriented language like Ruby or Smalltalk, they are rare (because the methods which actually operates on the data is actually automatically strongly type-bound to the data by virtue of it being a method. It’s overly constraining because it unnecessarily couples the implementations of the provider and users of the services provided by an object.
Rather than droning on about the failures and contraints of early-type checking, which I suspect I’ll address more fully here as time goes on. Allow me to introduce the notion of types in an object-oriented languagethat I’ve come to accept over many years.
Let me suggest that in a fully object-oriented language types are not properties of objects or classes, but properties of variables which code using an object uses to refer to those objects. In saying this I’m recapping the key idea behind an IBM Technical Report I wrote back in 1991 entitled “Types fromthe Client’s Viewpoint” Which is available here as a pdf file.
“But wait a minute!”, you say. “Aren’t types for matching objects with variables, so that programmers won’t make mistakes when they manipulate the object?” To which I reply, “That’s not object-oriented.”
Now of course many will argue with this, but I’d like to revisit the original conception of object-orientation, a term which was coined by Alan Kay, the inventor of Smalltalk, a language from which Ruby has borrowed a lot.
The key idea behind “object-orientation” a la Smalltalk and Ruby is the encapsulation of implementation behind an interface defined by a set of messages. Kay felt that the traditional way of structuring software as programs which processed data, and the attendant separation of program and data was somthing to be avoided. His view is that it isbetter to compose software out of components which all look like little computers, which contain and bind the programs and state together. This was a synthesis of ideas which he had seen over many years, although they had never been codified before he did it.
For an insight into Kay’s thinking, have a look at the article he wrote some years ago about “The Early History of Smalltalk”
Another way of looking at this idea, is that objects should be like little server machines, the exact set of services available and their implementation can vary from server to server, but clients can still use those services in isolation from those details.
In both Ruby and Smalltalk, classes and inheritance are used for implementation sharing, in order to achieve economies in implementing those little computers (objects). This is not an essential feature in Kay’s conception of OO. The original versions of Smalltalk had neither classes nor inheritance which were introduced in later versions.
In parallel with the evolution of Smalltalk, a family of languages based around the concept of Abstract Data Types became an important Computer Science research topic. Abstract Data Types arranged data types into a hierarchy so as to categorize their use as a way to structure more traditional procedural programs, and they called these abstract data types, classes, and the relationship between classes inheritance, so subclassing was simply a synonym for subtyping.
Since, by the time Smalltalk had been made widely known by the publication of a special issue of Byte magazine devoted to Smalltalk-80 in 1981, it had added classes and inheritance, most observers mistakenly thought of classes and inheritance as essential features of the language. One of these was Peter Wegner who wrote an influential paper Dimensions of Object based Language Design which was published in the proceedings of the 1987 OOPSLA conference. In this paper, Wegner defined “object-oriented” languages as those cobining “objects+classes+inheritance.” What he missed was that in Kay’s conception of object-orientation classes and inheritance were merely implementation artifacts, and that the encapsulation of implementation within an object was the big idea which separates object-oriented languages from procedural languages, and despite the similarity in terminology, abstract-data-type languages, which presented instances of those data types as things to be manipulated from the outside, were far from object-oriented, at least as Kay conceived it.
So to wrap this up for now, duck-typing is a natural consequence of the nature of how objects with strongly encapsulated implementations should interact. The notion of objects containing the code which manipulates them, and hiding that implementation behind a wall, through which messages are sent, is a paradigm shift with powerful consequences. Because many so-called “object oriented” languages missed this paradigm shift, many of their users are uaware the power of thinking about software design from this new perspective.
I hope, that in some small way, this blog will help expose the beauty of this paradigm shift.




