I believe Mr. Mielzynski's point is that
def initialize( options || {:wait=>20})
fails because the parameter list of a function is not subject to
expression execution the way its body is. You can only do a few things
in the list: give parameters some limited type specification with '*'
and '&'; and give them default values, which we are discussing here.
In
def initialize(options = {})
the 'options = {}' statement isn't really an assignment, but a borrowed
C++ idiom providing a pattern for a possible future assignment with a
built-in test. That last example behaves like
def initialize( *options )
options.empty? && options={}
but is safer and, once you get used to it, less confusing. It
originated as an improvement on C allowing for type-safe optional
parameters. Because in C/C++ the number and size (read 'space in
memory') of arguments passed to a function must be known at
compile-time, one way (the other being overloading) to provide
aforesaid flexibility is to provide a placeholder that fills in an
argument the user can leave out. The following C++ function
int f( int x=0, int y=0 )
{ return( x+y ); }
can be invoked as
f(); // 0+0=0
or
f(1); // 1+0=1
or
f(1,1); // 1+1=2
(but not
f(1,1,1); // Compiler error
because no 'f(x,y,z)' was defined).
That the idiom takes the form of what looks like an assignment
statement is due to C++'s avoiding introducing new keywords whenever
possible, a fact that makes for reuse of syntactic structures in some
surprising ways. Interpreted languages such as Ruby have much more
flexible invocation rules, so the C++ idiom is not, strictly speaking,
necessary here. But it is extremely well-known. If you wanted to
write a method in Ruby that took an optional number of arguments, how
would you do it?