The is now a RedMine setup for Rake, FlexMock and Builder.
RedMine
As part of an effort to get better control of changes to the my open
source projects, I’ve setup a RedMine issue tracking site for Rake,
FlexMock and Builder. You can find it at
http://onestepback.org/redmine.
I was introduced to programming in high school by reading a book on
the topic. The book taught me how to write machine code for a strange
decimal-based machine. Unfortunately, there was no actual computer
involved in the process. Shoot, who had computers back then? Certainly
not our high school (the personal computers? not invented yet!)
In college, I learned a smattering of FORTRAN. Just enough to drive a
Calcomp plotter to plot data from my undergraduate physics courses.
But didn’t really get into programming until my junior year in
college. (Story continued in next question)
How did you get started in programming?
So, I was planning out the courses for my junior year in college and I
had a hole in my math courses. The math class I needed was not offered
that semester, so my adviser suggested taking a computer programming
course. He said it would be useful and, who knows, I might enjoy it.
So I signed up for an introduction to FORTRAN course, figuring it
would be easy because I already knew a little bit of FORTRAN. I show
up on the first day of class and after a few preliminaries the
instructor jumps right into some code, that looked like this:
(de member (pip deck) (cond
((null deck) nil)
((eq pip (car deck)) t)
(t (member pip (cdr deck)))))
I remember scratching my head and thinking this was the strangest
FORTRAN I had ever seen. I was totally confused for about three days,
then something clicked on the third day of class. I suddenly
“got” what the instructor was trying to get across and it all
made perfect sense.
If you haven’t figured it out yet, the instructor taught us Lisp as
part of an introduction to FORTRAN. The instructor turned out to be
Daniel Friedman, the author of The Little
Lisper,
and was well known in the Lisp community. That small exposure to Lisp
hooked me on programming from that point on. I took as many CompSci
courses as I could in my remaining year and a half in college. I
eventually graudated with a BS in Physics, but had a strong background
in Computer Science as well.
What was your first language?
Technically, FORTRAN was my first language. But Lisp is the language I
fell in love with and is what got me hooked on programming.
What was the first real program you wrote?
I have a very clear memory of the very first program I wrote
professionally. The reason it is so clear is that this was the first
program I wrote that was intended for actual use by someone who wanted
it. Everything else up to that time was done for my own personal
enjoyment or to satisfy some course requirement.
The program calculated the “critical angles” of “pieces”. I was given
the requirements by Anne Exline, a senior programmer, and proceeded to
write the program to spec. It took a few days, but when I was done I
showed the result to Anne and she was pleased with the result.
The funny thing is that I had no idea what a “piece” was nor what was
so critical about the angles I was calculating. I was so excited about
writing an actual program that I did not ask until the software was
done. When asked, Anne just looked at me funny and said “Rocket
Pieces”. When Cape Canaveral lauches a rocket, they track it very
carefully to make sure it stays on course. If it strays, the range
safety officer is required to activate the self destruct. The critical
angles are those angles that would cause the “rocket pieces” to land
outside the safety area of the flight path.
So, my very first professional program was not only useful, it might
actually save lives.
What languages have you used since you started programming?
Languages I have used as part of my professional career (in roughly
chronological order) include FORTRAN, various assembly languages,
FORTH, C, PL/M, C++, Java, Ruby.
Languages I have used in addition to those mentioned above: Pascal,
Perl, Eiffel, and Lisp/Scheme.
Languages I can read, but never wrote anything significant in them:
Ada, Python, Erlang, Smalltalk, SNOBOL, Algol, Pascal.
What was your first professional programming gig?
I was hired by the RCA Missile Test project in Cape Canaveral, Florida
as a Near Real Time Analyst. Duties included programming various
launch related software (e.g. the critical angle program mentioned
above) and working launch support.
The launch support was the “Near Real Time” part of the job
description. From the moment a rocket is launched until it reaches
orbital velocity, any malfunction could cause it to fall back to
earth. During this initial portion of the launch, the launch is
monitored in “real-time” so that we know exactly where it would land
if the engines were to cut off NOW. Trajectory calculations had to be
done in fractions of a second and updated constantly in real time.
After the rocket reaches oribital velocity (usually somewhere between
8 and 14 minutes into its flight), it won’t fall back to earth. At
this point the real time trajectory program is shut down and the near
real time program is started. The near real time program can take a
few minutes to calculate a more exact orbital prediction and then send
that prediction to downrange radars (e.g. the the Ascension
Island station) that
won’t see the rocket until about 20 minutes after launch. It was the
job of the Near Real Time analyst to run that program and provide
oribital predictions for downrange station.
If there is one thing you learned along the way that you would tell new developers, what would it be?
Find something that you enjoy and do that. Life is too short to work
in a job that you dislike.
What’s the most fun you’ve ever had … programming?
Oh, the fun I have had. This story still makes me smile.
My first computer was a single board Z80 microcomputer with 4 KB of
memory. I wrote a small FORTH-like interpreter for it and hacked a
version of the animal game in FORTH. The animal game is a program that
plays 20 questions to figure out what animal you are thinking of. It
constructs a binary tree where each node is a question and the
subtrees are the yes and no answers to the question. To play the game,
all the program does is walk the tree, ask the question at the current
node and follow either the YES branch or the NO branch as appropriate.
If the program guesses wrong, it will ask you for your animal and a
question that will distinguish your animal from the one it guessed. It
then adds your question to the tree. By this extremely simple
mechanism, it is able to expand its knowledge base. (see Ruby Quiz
#15 for more details).
I had just finished the program and had seeded it with a single
animal, a mouse. I turned to my wife and asked her to play the game.
She thinks of an animal and starts the program, which immediately
asked her “Is it a mouse?”. She turned to me with surprise and said
“How did it know?”. Of course, the animal she picked was a mouse.
I don’t think I have ever impressed anyone with my programming skills
as much as she was impressed with that game.
Who’s up next?
I’m tagging the following people. Remember, this is entirely
voluntary so don’t feel obligated to answer. But I’m betting the
answers are interesting:
Wow, what a great conference! There was a lot of energy flowing at
RailsConf this year. Overall I’d rate this year as head and shoulders
above last year. I’m not going cover much here, but will direct you
attention to a Rails Envy
VideoCase that
Greg Pollack put together. The video is a series of very short
interviews with a number of presenters giving summaries of their own
talks. The only downside with the video is that I wish it was
available before the conference. I see there were a number of
interesting talks that I missed.
Followup on the “Modelling Dialogue”
Joe O’Brien, Chris Nelson and myself did a dialogue style presentation
on the difference between object modelling and data modelling. The
most common question I got after the talk was requests for book titles
to learn more about object oriented modelling. Here are the books
that Joe, Chris and I have recommended:
The Musician’s Birds of a Feather gathering at RailsConf was great. We
had a room full people, two guitars, a ukulele, a flute, several
harmonicas and an improvised drum set. Unfortunately, one of the
guitars was an electric travel guitar which had a dead battery,
therefore no way to really hear it.
However, the other guitar was a nice Epiphone accoustic which was
passed from player to player. It became the quickly became the basis
for most of the music performed that night.
I want to thank Artichoke Community
Music for supplying the
guitar. Travelling with a guitar by plane is a big pain, so I arrived
with nothing to bring to the music BOF. I called several local music
stores looking for a guitar that I could rent for an evening.
Artichoke music said they had a “not-for-profit” guitar that they
would let me borrow for a day. Not many stores would do that for an
out-of-town stranger.
So, if you’re in Portland looking for a good guitar store, check out
the great people at Artichoke Community
Music.
Joe O’Brien and I will be leading another Test Driven
Studio in Denver, June 9-11.
Testing, Colorado, June … What’s not to like?
About 8 years ago I come upon a technique that radically changed the
way I developed code. I was reading Martin Fowler’s “Refactoring”
book and came across this paragraph:
“Whenever I do refactoring, the first step is always the
same. I need to build a solid set of tests for that section of code.
The test are essential because even though I follow refactorings
structured to avoid most of the opportunities for introducing bugs,
I’m still human and still make mistakes. Thus I need solid
tests.” —Martin Fowler
Chapter 4 of “Refactoring” was my first introduction to JUnit and got
me interested in “Test First Design” (what we now tend to call “Test
Driven Development”). Although I wrote good code before, the
confidence I had in my code took a dramatic leap forward after I
started adopting TDD practices.
On June 9 through 11, Joe O’Brien and I will have
the pleasure of leading the next Pragmatic Programmer’s Test-Driven
Development with Rails
Studio. in Denver. We will
have an opportunity to share with you some of our experiences in using
TDD with Ruby and Rails.
There are still seats available, so its not too late to sign up. More
information is available
here.
I’ve updated the Textile formatter on the site and the code
for this entry is now displaying correctly. The previous version was
swalling the == operators in the code.
Lisp 1.5 Programmer’s Manual
I stumbled across this in
Bill Clementson’s blog and remembered using the Lisp 1.5 Prgrammers
manual from the college years. I have strong memories of pouring over
that particular page in the manual and attempting to understand all
the nuances.
If you’ve never read the Lisp 1.5 Programamers Manual, page 13 is
the guts of a Lisp Interpreter, the “eval” and “apply” functions. It
is written in Lisp, although the notation used is a bit funky. The
entire interpreter (minus two utility functions) is presented on a
single page of the book. Talk about a concise language definition!
In Ruby?
I had often thought about implementing a Lisp interpreter, but back in
the “old days”, the thought of implementing garbage collection and the
whole runtime thing was a bit daunting. This was in the day before C,
so my implementation language would have been assembler … yech.
But as I was reviewing the page, I realized that with today’s modern
languages, I could problably just convert the funky M-Expressions used
on page 13 directly into code. So … why not?
The Code
Here is the complete Ruby source code for the Lisp interpreter from
page 13 of the Lisp Programmers manual:
# Kernel Extensions to support Lisp
class Object
def lisp_string
to_s
end
end
class NilClass
def lisp_string
"nil"
end
end
class Array
# Convert an Array into an S-expression (i.e. linked list).
# Subarrays are converted as well.
def sexp
result = nil
reverse.each do |item|
item = item.sexp if item.respond_to?(:sexp)
result = cons(item, result)
end
result
end
end
# The Basic Lisp Cons cell data structures. Cons cells consist of a
# head and a tail.
class Cons
attr_reader :head, :tail
def initialize(head, tail)
@head, @tail = head, tail
end
def ==(other)
return false unless other.class == Cons
return true if self.object_id == other.object_id
return car(self) == car(other) && cdr(self) == cdr(other)
end
# Convert the lisp expression to a string.
def lisp_string
e = self
result = "("
while e
if e.class != Cons
result << ". " << e.lisp_string
e = nil
else
result << car(e).lisp_string
e = cdr(e)
result << " " if e
end
end
result << ")"
result
end
end
# Lisp Primitive Functions.
# It is an atom if it is not a cons cell.
def atom?(a)
a.class != Cons
end
# Get the head of a list.
def car(e)
e.head
end
# Get the tail of a list.
def cdr(e)
e.tail
end
# Construct a new list from a head and a tail.
def cons(h,t)
Cons.new(h,t)
end
# Here is the guts of the Lisp interpreter. Apply and eval work
# together to interpret the S-expression. These definitions are taken
# directly from page 13 of the Lisp 1.5 Programmer's Manual.
def apply(fn, x, a)
if atom?(fn)
case fn
when :car then caar(x)
when :cdr then cdar(x)
when :cons then cons(car(x), cadr(x))
when :atom then atom?(car(x))
when :eq then car(x) == cadr(x)
else
apply(eval(fn,a), x, a)
end
elsif car(fn) == :lambda
eval(caddr(fn), pairlis(cadr(fn), x, a))
elsif car(fn) == :label
apply(caddr(fn), x, cons(cons(cadr(fn), caddr(fn)), a))
end
end
def eval(e,a)
if atom?(e)
cdr(assoc(e,a))
elsif atom?(car(e))
if car(e) == :quote
cadr(e)
elsif car(e) == :cond
evcon(cdr(e),a)
else
apply(car(e), evlis(cdr(e), a), a)
end
else
apply(car(e), evlis(cdr(e), a), a)
end
end
# And now some utility functions used by apply and eval. These are
# also given in the Lisp 1.5 Programmer's Manual.
def evcon(c,a)
if eval(caar(c), a)
eval(cadar(c), a)
else
evcon(cdr(c), a)
end
end
def evlis(m, a)
if m.nil?
nil
else
cons(eval(car(m),a), evlis(cdr(m), a))
end
end
def assoc(a, e)
if e.nil?
fail "#{a.inspect} not bound"
elsif a == caar(e)
car(e)
else
assoc(a, cdr(e))
end
end
def pairlis(vars, vals, a)
while vars && vals
a = cons(cons(car(vars), car(vals)), a)
vars = cdr(vars)
vals = cdr(vals)
end
a
end
# Handy lisp utility functions built on car and cdr.
def caar(e)
car(car(e))
end
def cadr(e)
car(cdr(e))
end
def caddr(e)
car(cdr(cdr(e)))
end
def cdar(e)
cdr(car(e))
end
def cadar(e)
car(cdr(car(e)))
end
An Example
And to prove it, here’s an example program using Lisp. I didn’t
bother to write a Lisp parser, so I need to express the lists in
standard Ruby Array notation (which is converted to a linked list via
the “sexp” method).
Here’s the ruby program using the lisp interpreter. The Lisp system
is very primitive. The only way to define the function needed is to
put them in the environment structure, which is simply an association
list of keys and values.
require 'lisp'
# Create an environment where the reverse, rev_shift and null
# functions are bound to an appropriate identifier.
env = [
cons(:rev_shift,
[:lambda, [:list, :result],
[:cond,
[[:null, :list], :result],
[:t, [:rev_shift, [:cdr, :list],
[:cons, [:car, :list], :result]]]]].sexp),
cons(:reverse,
[:lambda, [:list], [:rev_shift, :list, nil]].sexp),
cons(:null, [:lambda, [:e], [:eq, :e, nil]].sexp),
cons(:t, true),
cons(nil, nil)
].sexp
# Evaluate an S-Expression and print the result
exp = [:reverse, [:quote, [:a, :b, :c, :d, :e]]].sexp
puts "EVAL: #{exp.lisp_string}"
puts " => #{eval(exp,env).lisp_string}"
The program will print:
$ ruby reverse.rb
EVAL: (reverse (quote (a b c d e)))
=> (e d c b a)
All I need to do is write a Lisp parser and a REPL, and I’m in business!
The Example in Standard Lisp Notation
If you found the Ruby-ized Lisp code hard to read, here is the reverse
funtions written in a more Lisp-like manner.
Paul Graham issues the Arc Challenge … who could resist?
Paul Graham’s Arc Challenge
You can read about the Arc Challenge here: The Arc
Challenge. Go ahead a
read it now, but I will summarize the challenge.
Write a web program such that:
The first page of the program displays nothing but a text box and a
submit button. You enter some arbitrary text and press the submit
button, which takes you to …
The second page is nothing but a single link labeled “click here”.
The URL linked to must not contain the text entered in the first
step (i.e. you are not supposed to pass the text as a parameter on
the link). Clicking the link takes you to …
The third page which contains “You said: XXX” (where XXX is the text
you entered in the first step).
Here’s a screen cast demoing my solution to the Arc Challenge. (We
will show the code shortly).
Paul’s Solution
Paul has been working on designing Arc, his ideal programming language
for the future. Given Paul’s language preferences, it is no surprise
that Arc is very Lisp-like. Here is Paul’s solution written in Arc:
Paul points out that the solution is very short and elegant, only 23
nodes in the codetree. I’m sure I don’t quite understand exactly what
it is doing (I’d love to see a step by step explanation of the code).
He wonders what it would look like in other languages.
Several people have responded with solutions in their own languages.
I’ve seen a Smalltalk
Solution
as well as a Ruby solution (which
pretty closely mimics the Arc code from Paul) on the Arc Language
Forum page that was setup for
responses.
Continuation Web Servers
The Arc challenge is a perfect candidate for a continuation based
server solution. And I recalled that Chad Fowler and I had written a
demo continuation based server for the Continuations
Demystified talk we did at
RubyConf 2005. (Look for the “Poor Man’s Seaside Demo in that
presentation.) I wondered how easy it be to code up an Arc challenge
solution using that code base.
The key to a continuation based server is that it allows the
programmer to code in a linear fashion. All the request/response
nature of web interaction is completely hidden from you as a
programmer.
For example, let’s pretend we wanted to solve the Arc challenge using
a terminal and command line rather than a web based solution. How
would you write it? Probably something like this:
Simple, linear programming. (OK, printing “click here” is silly in a
text program, but you get the idea). You ask a question and read a
response. You pause for a click. You then tell the user what the
result is.
Ask. Pause. Tell.
Those are our basic abstract operations for this problem. Lets
rewrite our text based solution using these abstractions. We’ll put
this in a file called “arc_challenge.rb”.
Conversation.interact do |io|
text = io.ask
io.pause("click here")
io.tell("You said: #{text}")
end
I’ve introduced three operations (methods) that are provided by an I/O
object (let’s ignore the interact line for now). “ask” will ask the
user for input, returning the string. “pause” will pause until the
user indicates he/she is ready to continue (e.g. pressing return in our
command line version). “tell” sends the given string to the user.
So, what does “Conversation.interact” do? It creates the environment
where the user have a conversation with the program. The interation
is controlled through our ask/pause/tell functions provided by the I/O
object passed to the interact block.
Here is an implementation of a text based conversation.
class TextBased
def interact
yield(self)
end
def ask(prompt=nil)
print prompt, " " if prompt
gets.chomp
end
def pause(prompt="")
print prompt, " " if prompt
gets
end
def tell(message)
puts message
end
end
Conversation = TextBased.new
To run the text based conversation, just require the text. Here’s a demo:
Arc on the Web
Well, anybody can solve the challenge in text mode. How much work do
we have to do to get it on the web.
The answer: Zero!
The code Chad and I wrote for Continuations
Demystified includes a
web-based version of the conversation object that is ready to go. All
we have to do is plug it in and run it. No changes are required to
our basic Arc challenge solution.
Again, a screen demo:
Yes, we know that although we now have our Arc Challenge on the web,
we haven’t quite conformed to the exact requirements of the challenge.
We will handle that next.
The Final Arc Solution
The problem is that the current Web based conversation object makes
all kinds of assumptions that are not appropriate for the final Arc
solution.
In particular, we need to change:
Get rid the head line, restart link and other extraneous HTML
elements.
Don’t keep a running log of the conversation. When you move to a
new page, you start from scratch.
The “click here” should be a real link, not just a text box where
you can press enter.
To get to here, we will have to make some modifications to the
conversation web library. It turns out the changes are pretty
straight forward. The whole interaction framework is controlled by
the Conversation object that implements ask/pause/tell methods. You
can see the changes made for the Arc challenge in the
“noecho_web_based.rb” file (see the end of this post for the
availability of the source code).
The Final Conversation Based Solution
In cased you missed it, here is the Arc Challenge Solution:
Conversation.interact do |io|
text = io.ask
io.pause("click here")
io.tell("You said: #{text}")
end
Yep, it’s the exact same file we used for the text based solution. I
don’t know if it is as elegant as Paul’s version, but I certainly find
it easy to read and understand. (Rerun the very first screen
cast in this posting if you want
to see it in action again).
If you want to look at the code, there is a
tarball available
that contains all the continuation server demo code from
Continuations Demystified
talk, as well as the two new files I added for the Arc challenge.
“arc_challenge.rb” is the actually solution and “noecho_web_based.rb”
is the conversation library that renders the solution in the style set
forth by the challenge.
Erlang defines functions by listing a set of possible argument lists
and the body of the function to be executed for each argument list.
For example, the factorial function might be defined in Erlang as:
factorial(0) -> 1;
factorial(N) -> N * fac(N-1).
If factorial is called with a 0 (zero) for an argument, the first
argument list will be chosen and the value of the factorial function
will be 1. Otherwise, the value returned will be calculated by a
recursive call to factorial.
FlexMock and Erlang
While playing around with FlexMock the other day, I realized that it
does parameter matching, much like Erlang, when deciding what mock
method to call. So I started wondering if you could write Erlang-like
function definitions in FlexMock.
The deadline for the proposals is August 20. However, I have it on
good authority that the deadline will be extended to Aug 23, 5:00 pm
EST. (Ahh … I see the announcement made it to Ruby-Talk) So you still have some time.
Some Hints
RubyCentral has been having some problems with getting their
registration responses delivered (I found my registration confirmation
in GMail’s spam box). I would recommend that you go ahead and
register a proposal now, even if you don’t have all the details ready.
By the time you are ready to submit the final version, you won’t have
to worry about any last minite registration hassles.
Good luck with your proposals. I hope to see you at RubyConf!
Welcome to ...
Jim Weirich’s blog on Ruby, OO, Programming, whatever.