{ |one, step, back| } 132 to 141 of 182 articles WikiSyndicate: full/short

Some Pointers   13 Mar 04
[ print link all ]
I have not updated this Blog for over a month. It has been real busy around here. I have some ideas I want to share, but I think I’ve run afoul of Charles Miller’s #1 blogging rule. So I’m just going plunge into this posting by pointing out a couple of interesting reads I’ve found lately.

But First, Some Apologies

Yes, my site was down for a few days in February. I didn’t notice it right away, and when someone at work pointed out they couldn’t get to onestepback.org I had to wait to fix it until I got home. Even then, I thought it was only down for the day. It wasn’t until I reviewed the web stats for February did I realize that it was down for at least three days.

Sorry. It turns out that the copy of apache servicing http requests had crashed and burned. The ssl server was still up so remote access to my mail was OK. I just didn’t notice that the http server was down (see, I really was busy). Nevertheless, we now have some monitoring software in place so simple crashes shouldn’t cause extended outages any more.

Directing VS Enabling

Static verses Dynamic Typing. Checked verses Unchecked Exceptions. The battle rage on (and I’ve taken part in my share of them). Martin Fowler has some keen insight into the nature of the proponents of each side of the debate. He calls it the difference between a Directing attitude and an Enabling attitude. Directors wish to make the computing environment as safe as possible and willing accept restrictions to achieve that goal. Enablers desire flexibility above (in their view unneeded) safety, and will chaffe unagainst restrictions. Read Martin’s writeup, he explains it much better than I do.

I’ve landed on both sides of the debate in the past. Lately I’ve found myself on the enabler side of the equation more often than not.

When Generic’s Aren’t

Bruce Eckel has some surprising insight on the use of generics in Java (available in Java 1.5). For those who enjoy the ad-hoc polymorphism available in C++ generics are going to be surprised by Java’s version. If Eckel is correct, then generics look like they will be great for making generic containers and little else.

See Bruce’s article for details.

And More on Latent Typing

Speaking of the Static/Dynamic typing debate, the feedback page for Eckel’s Generics article, a commenter is defends the need for interfaces with the following comment:

In java, the symantics of a method are not bound to its name, so much as they are bound to the interface the method belongs to.

Bruce responds with a followup article on Latent Typing, but I would like to add my two cents here.

Java interfaces are more about syntax than semantics. They insure that implementing classes have the proper methods defined with the proper number and type of arguments, and that the methods actually do return a value of the appropriate type. But that’s it. Interfaces do nothing to support any meaningful semantics about the methods.

If you are interested in language support for semantics, I suggest you take a look at Eiffel. When you define a interface in Eiffel (which Eiffel would call a deferred class), you not only specify the argument list for the method, you also specify the promises to which the method implementor must adhere. This set of promises (the semantics) is called a contract and leads to the concept of Design by Contract.

Even if you never program a line of Eiffel code, understanding Design by Contract is a useful skill for a developer.

Speaking of Design by Contract

And that leads us to our final posting. Artima has published a series of interviews with Bertrand Meyer, the designer of Eiffel and Design by Contract. The interviews are worth reading (here is part 4, you can find links to the other parts from there).

I find that I don’t always agree with Meyer, but when I do disagree, I think through my position very carefully.

All for Now

I’ve run out of time. Hopefully it won’t be so long before I post again.

Writing an RCR   31 Jan 04
[ print link all ]
Matz is accepting RCRs (Ruby Change Requests) for Ruby 2.0 and Rite until the end of March. Tell the truth, is there something in Ruby that you wished worked a little differently? If so, now is your chance to stand up and be counted.

The Ruby Nuby Syndrome

I’ve noticed a trend on the ruby-talk mailing list. A nuby appears on the list, likes the language, except for one minor nit. Wouldn’t it be nice if Ruby would do (insert fix for minor nit here). A nit might be Ruby’s lack of overloaded functions, static typing, explicit interfaces, or anything else in Language X that is different in Ruby.

Now there is nothing wrong with static typing or interfaces. It is just that these topics have been hashed out on ruby-talk over and over again.

How Ruby Sucks

Don’t get me wrong. Ruby isn’t perfect by any means. In fact, I thought the Matz’s Keynote speech at the 2003 RubyConf was particularly healthy. Matz titled his talk "How Ruby Sucks" and then detailed the direction Ruby was moving for version 2.0.

And now that the features of Ruby 2.0 are beginning to solidify in Matz’s mind, he is encouraging Ruby Change Requests (RCRs) to be submitted through March at the RCRcive.net site.

But before you go and write up your favorite change request, consider the following.

Before You Write an RCR

Before you write an RCR, make sure you cover the following bases.

  1. Research. Has this change been requested before? Search the ruby-talk archives (Google is your friend). Also read the list of RCRs, both current and legacy entries to see if there are similar RCRs. Be sure to read and understand any issues raised during any previous discussions.
  2. Investigate. What would it take to implement your RCR. Can you simulate it with Ruby code today? What are the tradeoffs? Are there performance issues? Are there complexity issues? What about backwards compatibility?
  3. Solicit Feedback. If your suggestion is way out there, perhaps it would be wise to get feedback before you write up your RCR. It wouldn’t hurt to post a message on ruby-talk saying "I’m considering writing an RCR on XYZ, am I on track here?". Many ruby-talk members are tired of the same-old changes being discussed over and over again, but if you’ve made it past the research and investigate phase, a ruby-talk message would not be out of line. The feedback you get may help you tighten up the RCR.

Writing the RCR

Once you are ready to actually write the RCR, do the following

  1. Read the Submission Guidelines and Suggestions for submitting an RCR.
  2. Fill out each section of the RCR submission form. Pay special attention to the purpose of each section. The RCR submission help page goes over the sections, so I won’t repeat the information here.
  3. Remember the purpose of the RCR is to convince Matz and other Rubyists that they would benefit from your proposed language change. Clearly lay out what the perceived problem is and exactly how your proposal addresses that problem. Don’t skimp in the Analysis section, but carefully layout both the pros and cons to your RCR. Good, compelling examples are worth their weight in gold.
  4. If there is any way possible, provide an implementation of your suggestion. If your suggestion cannot be done in the current version of Ruby, approximate it as best you can. If you can’t provide a full speed implementation, provide a slow one (but include performance analysis as appropriate). Working code speaks much louder than vague suggestions.
  5. Don’t bother to invoke POLS (Principle of Least Surprise) as a justification for the RCR. Matz is the final arbiter of what is surprising and what is not, and telling him what his expectations are will not advance your position.

After You Write Your RCR

  1. Go back to review and comment on other RCRs. Make sure you vote too. But remember, the voting is only there to provide Matz with some indication of the interest in a given feature. This isn’t a democracy, Matz still makes the final call.
  2. Listen to feedback on your RCR. Several RCRs have already been withdrawn or rewritten based on the feedback provided by the RCR process.

It’s an exciting time for Rubyists, we are beginning to get a picture of what Ruby 2.0 might be like. So if you have an RCR in mind, please go ahead and submit it.

Just make sure you do the homework too.

Saw this ...   23 Jan 04
[ print link all ]
in a UseNet signature:
  A: No.
  Q: Is top-posting okay?

A Little Ruby, A Lot of Objects   23 Jan 04
[ print link all ]
It was my junior year in college and the math course I intended to take wasn’t offered that semester. My advisor recommended a computer programming course. He said "It will be useful, and who knows, you may like it." (Little did he know!). So that’s how I signed up for an introductory class on FORTRAN.

When I got to the first lecture, the instructor kept writing code snippets on the blackboard and asking questions about them. Now I knew a enough FORTRAN to do simple plots for my physics lab courses, but the code on the blackboard had way too many parenthesis to be FORTRAN.

Here’s one example (from memory):

  (DE MEMBER (PIP DECK) (COND
      ((EQ PIP (CAR DECK)) T)
      (T (MEMBER PIP (CDR DECK)))))

(And yes, the layout is accurate. The COND was definitely on the first line. At this point in the class, it was explained as required "magic".)

"What kind of programming language is this?" I thought. It didn’t make any sense for about 3 days. And then I had the "Ah-HA!" experience and everything fell into place. I finally "got it", and fell in love with Lisp and programming in general from that point on.

The instructor for the course was Daniel Friedman, the author of the book "The Little Lisper" (which was one of the required books for the course). The Little Lisper emulated, in print, Professor Friedman’s style of teaching, revealing a little bit of information through a question and answer session until the reader/student gains enough understanding to put all together.

Brian Marick has started a book where he emulates that Q&A style, but targets the book at Object Orientation and Ruby instead of Lisp. You can find the first three chapters of A Little Ruby, A Lot of Objects at www.visibleworkings.com/little-ruby. In those three short chapters he introduces objects, messages, protocols, inheritance, classes and meta-classes to a beginning programmer in a whimsical manner, similar to the original Lisp book. It was a delight to read the step by step approach used in the book.

The only downside is that Brian seems to have stopped after three chapters. Nevertheless, if you are looking for a gentle introduction to object orientation in general and Ruby in particular, take a look at A Little Ruby, A Lot of Objects.

Another Ruby Build System   21 Jan 04
[ print link all ]
Jon writes about a build system he put together using Ruby. Scripts in Jon’s system look alot like normal programs. Tasks are defined like a normal Ruby method, but a target_method command marks that method as special. These special commands are only executed once, no matter how many times they are called.

It’s a clever and remarkably simple approach.

Jon also describes a technique he uses to interface with ant to build a Java program. Details are a little sketchy, but I wonder if it is something that could be used with Rake.

Eckel and Fowler on Build Systems   08 Jan 04
[ print link all ]
Build systems seem to be at the forefront of everyone’s mind recently. Bruce Eckel and Martin Fowler have recently commented on the topic.

Bruce Eckel on Build Systems

In "Why We Use Ant", Bruce argues why we should continue use Ant, even though it has some significant flaws as a build system for large, complex projects. His arguments are:

  1. It’s never as easy as it seems [writing a replacement for Ant].
  2. It’s probably not the battle you should be fighting.
  3. Lots of people have tried and failed.
  4. Politics matter.

Number four is actually a very strong argument, especially in a group doing Java development.

Let me quote an interesting passage in Bruce’s article.

Another important proglem with Ant is that its XML-influenced declarative syntax is limited. A build system is really a little computer program. Normally, you look for conditions (a source file is out of date with its target is the primary one for make) and you execute commands, but sometimes you need to do things that are more sophisticated, conditional logic, that kind of thinkg. Both make and Ant fall down here because, while it’s possible to do these things it suddenly gets a lot more complicated because that’s not normally what they do.

Exactly! It was my need to dynamically generate some make targets that started my original make rant that sparked the rake project. make, by itself, just wasn’t up to the task

Bruce continues …

I suppost if I were give a budget and a bevy of programmers, I would ask them to take make, which is open-source, eliminate the silly tab-vs.-space thing, and meld it together with Python, also open-source. make would only retain the simplest of its functionalites (primariy the way you set up dependencies and execute simple commands), and as soon as you wanted to do something more complex you’d be able to drop seamlessly into Python syntax, using any Python libraries you want. I think that would probably be my dream build system.

Bruce, you really need to check out rake. Its exactly what you describe above (well, if you substitute Ruby for Python). And it didn’t take a bevy of programmers. The core functionality was an evening’s worth of work.

Dropping seamlessly into Ruby is trivial, because a Rakefile is a Ruby program, specified in standard (although idiomatic) Ruby syntax. Since we never leave Ruby, we have no parsers to deal with, leaving a very small code base for the core functionality. The core of Rake (dependency management, task execution and rule matching) is less than 200 lines of code. The minimal rake install (a single file) is around 500 lines of Ruby code and adds common file commands (system independent versions of cp, rm, mv, etc.) and a flexible FileList object that mimics Ant’s include and exclude semantics.

Martin Fowler on Build Systems

Martin Fowler echos many of Bruce’s comments and reiterates that a build system really needs a full blown programming language. Martin has been dabbling in Ruby, and it seems that he has discovered rake and has been using in it some small projects. Great!

A Build Language Needs to be a Programming Language

Why should your build system support a full blown programming language? Here is one small example taken from a real situation at work.

When we are ready to install a project at work, we create a staging directory containing the files to be installed into an environment (e.g. testing or production). As problems are discovered in testing, corrections are made in a development area and copied to the staging directory for reinstallation.

The following makefile copies 2 jar files from the developement area to the staging area. Yes, I know that a makefile is probably overkill for this problem, but in real life there are other tasks as well. For example, using make (or rake) allows me to ensure that a refresh step always occurs before an install step, but only if the refresh is needed.

So here is the makefile …

  # Makefile to copy jars

  DEV=/home/jim/development
  JARDIR=jars

  refresh: $(JARDIR)/a.jar $(JARDIR)/b.jar

  $(JARDIR)/a.jar: $(DEV)/AProject/lib/a.jar $(JARDIR)
          cp $@(DEV)/AProject/lib/a.jar $@

  $(JARDIR)/b.jar: $(DEV)/BProject/lib/b.jar $(JARDIR)
          cp $(DEV)/BProject/lib/b.jar $@

  $(JARDIR):
          mkdir -p $(JARDIR)

Notice that there are several duplications in the file. The copy command for the two jar files are remarkably similar, yet different enough that you can’t capture both cases with a generic make rule. Also, knowledge about a particular jar file is spread out in two places; once in the copy rule itself, and again in refresh task line.

First we will translate the above Makefile into an equivalent Rakefile. See the Rakefile documents for details on the syntax of a Rakefile.

  # Rakefile translated directly from the Makefile

  DEV = "/home/jim/development"
  JARDIR = "jars"

  task :refresh => [ "#{JARDIR}/a.jar", "#{JARDIR}/b.jar" ]

  file "#{JARDIR}/a.jar" => [ "#{DEV}/AProject/lib/a.jar", JARDIR ] do |task|
    cp "#{DEV}/AProject/lib/a.jar", task.name
  end

  file "#{JARDIR}/b.jar" => [ "#{DEV}/BProject/lib/b.jar", JARDIR ] do |task|
    cp "#{DEV}/BProject/lib/b.jar", task.name
  end

  directory JARDIR

All the duplication from the original makefile still exists in the rake version. Lets remove it by writing a function that will generate the dependency (and copy command) based on the jar file name and the project name.

  # Rakefile with (some) redundencies removed

  DEV = "/home/jim/development"
  JARDIR = "jars"

  task :refresh
  directory JARDIR

  def make_jar_copy_task(jarname, project)
    stagejar = "#{JARDIR}/#{jarname}.jar"
    devjar   = "#{DEV}/#{project}/lib/#{jarname}.jar"

    task :refresh => [ stagejar ]

    file stagejar => [ devjar, JARDIR ] do
      cp devjar, stagejar
    end
  end

  make_jar_copy_task("a", "AProject")
  make_jar_copy_task("b", "BProject")

Notice that the refresh task is now declared without any explicit dependencies. The individual jar file dependencies are added to the refresh task inside the make_jar_copy_task function.

If we had a lot of jar files, we could put them in an explicit list and replace the last two lines with something like this …

  jarfiles = [ ["a", "AProject"], ["b", "BProject"], ["c", "CProject"] ]
  jarfiles.each { |jar, proj|  make_jar_copy_task(jar, proj) }

Or perhaps we have to deduce the jar files from the current contents of the JARDIR directory. (Assume that projects is a lookup table mapping jarfiles to project names.)

  Dir["#{JARDIR}/*.jar"].each { |jar|
    jarname = File.basename(path).sub(/\.jar$/, "")
    make_jar_copy_task(jarname, projects[jarname])
  }

Or perhaps we need to pull our jar file names from a database …

  DBI.connect(DBI_STRING, USER, PASSWORD) do |db|
    sql = "SELECT jarfile, project FROM install_table WHERE install_date = ?",
    db.select_all(sql, INSTALL_DATE) do |row|
      make_jar_copy_task(row['jarfile'], row['project'])
    end
  end

Ok, that last example might have been a little over the top. The point is that builds can become arbitrarily complex, and anything less than a full programming language is just doesn’t cut it.

Variable Bindings in Ruby   23 Dec 03
[ print link all ]
In the Shoeboxes article I argued that a mapping of names to values is a better mental model for variables than the shoebox model. How can we take advantage of explicit bindings?

Bindings

In Ruby, bindings are explicitly made available in a Binding object. Invoking the binding method will produce a Binding object for the current local variables.

Given that bindings are objects, one would think that there would be a number of methods available to get, set and query the names and their values. Unfortunately, in Ruby that is not the case. When you pass a binding to eval, Ruby will use the binding to resolve open variable references while evaluating a string. Other than that, bindings are pretty opaque.

But that still gives us some useful functionality. If you want to know the value of a variable in binding, just evaluate the variable name …

  eval "a", vars         # Evaluate the value of "a" in the binding "vars"

To change a variable’s value in a binding, use …

  eval "a = 101", vars   # Bind "a" to the value 101.

Bindings and Local Scope

Using the binding method, we can capture the variable bindings available at a particular point in the code, and pass that binding to a different part of the code to be used there.

Here we pass the binding of the current scope to a method that uses it. This is pretty straight-forward.

  def value_of_a(vars)
    eval "a", vars
  end

  def my_scope
    a = 33
    value_of_a(binding)
  end

  my_scope               # => 33

Bindings can be returned from a function as well. This example shows that a binding continues to exist after the function that defines the binding has exited.

  def f
    a = 22
    b = 33
    binding
  end

  f_vars = f()

  eval "a", f_vars         # => 22
  eval "b", f_vars         # => 33
  eval "a = 101", f_vars
  eval "a", f_vars         # => 101

The bizzare feature of this example shows that not only does binding persist beyond the scope of the function that created them, but that you can modify these bindings just by evaluating an assignment within their context.

Blocks and Bindings

A block in Ruby is a chunk of code that can be called like a function. The block automatically carries with it the bindings from the code location where it was created. For example …

  a = 33
  block = lambda { a }
  def redefine_a(b)
    a = 44
    b.call
  end
  redefine_a(block)      # => 33

The block returns the value of a in the binding where the block was defined (a == 33), not the binding where the block was called (a == 44).

This combination of code block and binding is called a closure, and is a very powerful tool in a Ruby programmers toolbox.

Swapping Values

Recently on the ruby-talk mailing list, someone asked about writing a swap function where swap(a,b) would swap the values of the variables "a" and "b". Normally this cannot be done in Ruby because the swap function would have no reference to the binding of the calling function.

However, if we explictly pass in the binding, then it is possible to write a swap-like function. Here is a simple attempt:

  def swap(var_a, var_b, vars)
    old_a = eval var_a, vars
    old_b = eval var_b, vars
    eval "#{var_a} = #{old_b}", vars
    eval "#{var_b} = #{old_a}", vars
  end

  a = 22
  b = 33
  swap ("a", "b", binding)
  p a                          # => 33
  p b                          # => 22

This actually works! But it has one big drawback. The old values of "a" and "b" are interpolated into a string. As long as the old values are simple literals (e.g. integers or strings), then the last two eval statements will look like: eval "a = 33", vars". But if the old values are complex objects, then the eval would look like eval "a = #<SomeObject:0x401fef20>", vars. Oops, this will fail for any value that can not survive a round trip to a string and back.

Blocks as Getters and Setters

Let’s try a different approach to the "swap" problem. Instead of passing variable names and bindings to the swap function, let’s pass closures that do the work for us …

  def swap(get_a, get_b, set_a, set_b)
    temp = get_a.call
    set_a.call(get_b.call)
    set_b.call(temp)
  end

  a = 22
  b = 33
  swap(lambda{a}, lambda{b}, lambda{|v| a=v}, lambda{|v| b=v})
  p a           # => 33
  p b           # => 22

Wow! This works great! The values are swapped and arbitrary values are supported. The only down side is that the call to swap is extremely verbose.

Abstracting the Getter/Setter Code

We can shorten this by creating a getter/setter abstraction called a reference. To create a reference, we will need to supply the name of a variable along with a binding. But this is what we want the code to look like.

  a = 22
  ref_a = Reference.new(:a, binding)
  p ref_a.value        # => 22
  ref_a.value = 33
  p ref_a.value        # => 33
  p a                  # => 33

So changing the value of a reference should change the binding of the variable the reference refers to.

Here is a first pass at writing the Reference class …

  class Reference
    def initialize(var_name, vars)
      @getter = eval "lambda { #{var_name} }", vars
      @setter = eval "lambda { |v| #{var_name} = v }", vars
    end
    def value
      @getter.call
    end
    def value=(new_value)
      @setter.call(new_value)
    end
  end

Note that we create lambdas to handle the getting and the setting of values. This avoids the string interpolation problem mentioned above. Since we create the lambdas in the scope of the initialize fuction, we need to explicity pass in the calling scopes bindings so that the lambdas are created in the environment where are variables are defined. Leaving off the binding to eval will cause our getter and setter lambdas to modify the values of "a" and "b" in the scope of initialize instead of the calling scope.

Writing Swap

We are almost ready to write our swap function. First, let’s create a utility function (named ref) for creating references.

  def ref(&block)
    Reference.new(block.call, block.binding)
  end

ref takes a single block that returns the name of the value we are refering to. Since blocks automatically carry their binding with them, we get both the variable name and binding in a single argument. We use ref like this …

   aref = ref{:a}

Now swap can be written like this.

  def swap(aref, bref)
    aref.value, bref.value = bref.value, aref.value
  end

  a = 22
  b = 33
  swap(ref{:a}, ref{:b})
  p a                       # => 33
  p b                       # => 22

Summary

Using bindings, blocks and closures, we can have a great deal of control over the binding of names to objects within any scope. The basic ideas for the Reference class were developed in response to a Scheme/Python question on the C2 Wiki (see c2.com/cgi/wiki?SinisterSchemeSampleInRuby).

Shoeboxes And Bindings   15 Dec 03
[ print link all ]
This is a reposting of an article on RubyTalk from about a year ago. I’m posting it here in anticipation of a related posting later.

When I was first learning about programming (mumble mumble) years ago, variables were explained to me as shoeboxes. A variable name denoted a location in memory (a shoebox) which can hold things. You put values into the shoebox and they stay in there until you put something else in there. Each shoebox is exactly the right size to hold the type of data you put into it. Integers fit in int-sized shoeboxes and floating point numbers fit in float-sized shoeboxes. Pointers can be added to this model by envisioning labels (addresses) for each shoebox and storing a shoebox label in another shoebox.[1]

Assignment is the act of copying a new value into one of your shoeboxes.

This model works really well for understanding FORTRAN (the language I was learning at the time) and Algol, and reasonable well for C and C++. HOWEVER, this is exactly the wrong way to think about Ruby variables.

Consider the code …

    a = b = "Hello"

The shoebox model encourages us to think that the string is in the ‘a’ shoebox and another string is in the ‘b’ shoebox. Therefore we are surprised when modifying a changes b. To explain this within the shoebox model, we resort to talking about references and how the shoeboxes ‘a’ and ‘b’ don’t actually hold the string object, but hold a reference to it.

All of this is perfectly correct, but I believe there is a better model to use for Ruby variables.

In Ruby, the variable ‘a’ does not represent a shoebox that can store things. Instead, it represents an association between a name and an object. We call this association a "binding". Executing the code …

    a = "Hello"

binds the name ‘a’ to the string object "Hello". References to ‘a’ after the assignment will lookup the name ‘a’ in a dictionary of bindings and will find the object currently associated with ‘a’. We no longer need think of variables as shoeboxes containing objects, but as names associated (bound) to objects.[2]

I see a number of advantages to this point of view.

  1. The distinction between immediate values (like Fixnum) and reference values (most everything else) becomes invisible.
  2. Multiple assignment statements (like ‘a = b = "Hello"’) is explained in terms of binding the names ‘a’ and ‘b’ to the same object. No need to talk about pointers or references.
  3. Assignment becomes an operation that is outside an object. Objects don’t care what names they are bound to. Therefore binding is not an operation on an object and won’t ever be a method on an object. This helps explain why "+=" is not a method and why "++" can’t be implemented as a method.

I found that adopting this view has helped me understand Ruby better. I hope it helps you as well. Comments and feedback are encouraged.

Footnotes

  1. I used this technique to explain pointers when I taught a class in C, except I used styrofoam cups with labels instead of shoeboxes. I would write on yellow postit notes and drop them into the cups (variables). Each cup had a label, so to represent a pointer I would write another cup’s label on a postit and put it in a cup representing a pointer variable. It was actually a rather effective in demonstration.
  2. Variables as name bindings is not unique to Ruby. I first encountered the concept when learning Lisp (what I learned after studying FORTRAN). I’ve also read threads in the Python newgroup where someone was offering a similar explaination of variable binding for Python. I’m sure there are many other languages where binding is a better model than shoeboxes.

RubConf.new(2003) (Friday)   21 Nov 03
[ print link all ]
The Third Annual International Ruby Conference was in Austin Texas this year, November 14-16. I’m going to put down a rundown of the conference and some of the after hours activities.

Conference Introduction

Its Friday morning in Austin Texas, and the 3rd Annual International Ruby conference is just beginning. David Black welcomed everyone to the conference. He spoke a few words about RubyCentral, Inc, the organization that sponsors the conference.

Working in the Garden: Web Apps with Borges (Eric Hodel)

At last year’s conference, Avi Bryant demostrated an unusual web application framework that allowed linear programming to be applied to the rather non-linear web. Avi’s ruby framework was a partial port of his Smalltalk framework, Seaside. Seaside uses continuations to allow a user to return the application to an arbitrary earlier point in the program and to make a different decision.

Eric Hodel has done a complete port of Seaside to Ruby. The result is named "Borges". Eric demoed Borges by modeling SushiNet, a sales cart style application for ordering raw fish.

The Seaside/Borges model for web applications is really interesting. It seems to be a good fit for certain types of applications, especially for those that lead the user through a certain set of pages (e.g. the checkout pages for a web shopping site). Now if I could just get my head wrapped around continuations.

The State of XML Processing in Ruby (James Britt)

James points out that using XML these days is much like using ASCII, you really don’t care about the exact representation. You just use the APIs without worrying so much about the gory details. James gave us a survey of the currently available XML tools for Ruby, noting whether they were pure Ruby or C library based, whether they were streaming or DOM like, and gave a summary of there use. I’m not going go through his entire list, it was quite long. If fact, I was a bit surprised at the length of the list.

Object-relational mapping with Lafcadio (Francis Hwang)

Lafcadio is a OO mapping tool, allowing one to deal with objects in their Ruby code while accessing a relational database. Francis wrote Lafcadio for his own use, but appears to be fairly complete.

Lafcadio is specifically designed to support unit testing. Francis uses an interesting mechanism for flexibly controlling singletong instantiation in the framework.

Here are a couple of notes

  • I would like to see Lafcadio support more databases. Francis indicated that it would not be hard to add DBI support, but currently MySql is the only supported out of the box.
  • Francis talked about better abstractions for queries, but wasn’t aware of Ryan Pavlik’s Criteria library (see my Leaky Abstractions writeup. I think this would be a good match for Lafcadio.
  • I asked Francis later about the origin of the name "Lafcadio". He indicated that it came from a children’s book by Shel Silverstein about a lion of the same name. Lafcadio the lion grew up in the jungle, but was transplanted into the world of men. Lafcadio longed for the jungle, but was unable to return after becoming acclimated to his new world. Lafcadio becomes a metaphor for the strange between world of objects coming from a database, but living in the world of objects.

Ruby World: Implemented (Steve Tuckner)

Steve intended to talk about the implementation his Ruby World project, but implementation of Ruby World was delayed. Since David Black (one of the conference organizers) wouldn’t let him back out of speaking, Steve decided to talk about using Ruby in a commercial project.

And that’s a good thing. Steve’s company is developing a fax device controller and Steve is using Ruby to write the PC-based scheduling and control software for outbound faxes. This is a native windows application that will actually ship with the product (the fax controller is not yet shipping).

It was refreshing to hear about a Ruby project that is product related.

Some random notes:

  • Uses: Ruby, Vruby/Swin, win32ole, exerb
  • Threads on windows are problematic and can suck 100% of the CPU. There was some discussion of how to solve this problem using separate ruby processes and allowing them to communicate within the box.
  • Exerb will occasionally GP when built on certian machines. This problem has not reoccured since switching to Ruby 1.8.

As a wrap up, Steve shared some techniques for testing GUI code.

Generating Code in Ruby (Jack Herrington)

Jack is the author of Code Generation in Action. Jack talks about using code generation for anything from small one-liners to large MDA-style generators.

Some advice from Jack:

  • First hand write the code that you will eventually generate.
  • Generate only what you understand (avoid the wizard syndrome).
  • Maintain the generator as part of the build process.

I only disagreed with Jack on one point. Jack seemed in favor of guarded blocks in generated code. Guarded blocks are areas where developers are not allowed to edit. I personally have a great dislike for guarded blocks and would rather have the generated code be in a completely separate file, but that’s just me.

I don’t have much details here, buts that’s probably because I was doing more listennig than note taking at that point in time.

Roundtable with Matz

Chad Fowler introduced Matz and opened the floor for questions. Matz set the ground rules in that he will talk about Rite and Ruby 2.0 tomorrow night. So no Ruby 2/Rite questions for tonight.

Note :The following is very paraphrased and greatly shortened. I captured what I could from the talk as best I could. I apologize for any inaccuracies and errors.
  • Question: When is Ruby getting static typing?
    • Matz: Ummmmm .… I’m actually thinking about optional typing in Ruby 2.0, but based on signature rather than classes.
    • Comment: Strong Duck Typing?
  • Question: What is that status of a packaging system for Ruby? I know you are a benevolent dictator, but perhaps this is a where we need less benevolence and more dictator.
    • Matz: I maintain Ruby itself but do not implement
    • Comment: But perhaps you are the right person to choose an implementation or the person to work on it.
    • Matz: Perhaps we can setup a Wiki and gather requirements.
    • Moderator: Perhaps

      Aside: This packaging question turns out to be one of the more significant questions asked during the roundtable. It caused a handful of us to lose a great deal of sleep over the weekend. More on this later.

  • Question: Can you explain the reasoning behind the proc and Proc.new argument semantics?
    • There is a lengthy discussion about the difference. In the end, Matz agrees to deprecate "proc" in favor of "lambda" in order to differentiate block vs method argument semantics.

      Aside: I’m not sure I’m happy with this. I tend to use proc much more often than lambda, but I guess I can adjust. I suppose this shows what can happen when you can bend Matz’s ear.

  • Question: What is the news about the Ruby language specification?
    • Matz defered to Rich Kilmer who talked about the possibility of using a stand-alone parser to be the arbitor of syntax.
  • Question: Is the C API considered part of Ruby?
    • Matz: No, new versions might not support the current API, but I hope to provide some kind of backward compatibility.
  • Question: Is there someway we can get more of the Japanese web pages translated to english?
    • Matz: I don’t know.
    • Comment: I’ve had good luck with Babelfish.
    • Comment: I have the a copy of the Ruby Hackers guide. Its in Japanese. It’s a great book, I haven’t read it.
  • Question: What are you doing as the author of Ruby to ensure that Ruby doesn’t change and break are existing code?
    • Matz: Ruby 2.0 will be different from Ruby 1.8 and there will be some incompatibilities between the two, but Ruby 1.8 will remain as it is. Ruby 1.9 will generate warnings for future incompatibilities.
    • Comment: There are some advantages to being small and having a smaller installed base in that we can evolve the language
  • Question: What is being done to improve Ruby on the Win32 platform?
    • Matz: The Win32 folks are working on issues to make the platform better. Perhaps we need to get away from standard IO on that platform.
  • Question: Is Ruby going to follow Perl 6’s lead in regular expressions?
    • Matz: I have no plan to follow Perl6 in regular expressions, however if someone can convince me of a need for a particular feature I might change my mind. Ruby 1.9 will have a new regular expression engine that will unencumber it from license problems and gives better performance.
  • Question: Would it be possible to optimize string and regex interpolations when the interpolated data is static?
    • Matz: Ruby optimization is very difficult. I have considered many things and I have rejected many things. If you have some good ideas, I would like to consider them.
  • Question: What is the status of the local / block variable issue?
    • Matz: In Ruby 2.0, all block variables will be local to the block.
  • Question: Do you get bored working on Ruby for 10 years?
    • Matz: I’m not bored yet.
  • Question: What was the motiviation for using "#" for both comments and string interpolation?
    • Matz: Ummm … I don’t remember.
  • Question: People at work ask me why they should use Ruby instead of Perl. What should I tell them?
    • Matz: I’m not the right person to answer that because I am not a Perl programmer.
    • Comment: It’s like the Matix. No one can tell what Ruby is, you have to experience it.

At this point people started sharing Ruby stories in the workplace. Matz closed by saying that we will review changes for Ruby 2.0 tomorrow evening. Yeah!

Post Meeting Talks

The package question that came up during the roundtable touched a nerve with a number of us. Rich Kilmer, Chad Fowler, Paul Brannan and I (Jim Weirich) headed for the hotel (Club Max) and setup our laptops in a corner (near an outlet). Chad had a cellular internet connection so we were able to pull down a number of packages and previous attempts for review. We finally decided we would hijack the RubyGems project started by Ryan Leavengood. Ryan presented RubyGems at the very first Ruby conference in 2001 and got a favorable reception. Unfortunately the work was never continued and the project languished. So, Ryan, if you are out there, we hope you don’t mind.

We setup the following rough goals:

  • Single File, System Independent Distribution Format
  • Simple installation
  • Explicit versioning, possibly multiple version installed at the same time.
  • Easy downloading, something like apt-get.

I don’t recall enumerating the goals in this form, but they evolved from the discussions as the night progressed. In particular, we waffled on installing gems or loading files directly from gems. We finally decided on going through an installation because shared native libraries couldn’t be loaded directly from a gem file.

That first night, Rich and Paul attacked the package format and metadata required for a gem. Chad and I started looking at compression libraries and packaging techniques. Zlib is now packaged with Ruby 1.8, so it will be easy to compress the individual files. Standard zip files were considered, especially when we found a zip file library in the RAA. But eventually we decided on a self-extracting format that begins with a Ruby script to do the extraction.

By the end of the evening my mind was turning to mush. Fortunately the bar began turning out lights at 2:00 am. I headed off to bed, but I’m pretty sure Rich kept going for a bit beyond that.

Next: One day down, Two to go …

RubConf.new(2003) (Saturday)   21 Nov 03
[ print link all ]
Although I had a late night on Friday, I woke up early and was ready for another day of talks at RubyConf.new(2003).

Programming LOGO MINDSTORMS with Ruby (Shashank Date)

Having seen a LEGO Mindstorm robot at our CLUG meetings, I was very interested in seeing how Ruby works with the robots. The guts of the robot is the RCX brick that has inputs and outputs connected to the "nubs" on the top of the brick. Sensors and motors connect to the brick by snapping a sensor or motor block onto the nubs of the RCX brick.

The RCX brick sports 16 KB of ROM for BIOS-like functions and 32 KB of RAM containing a byte code interpreter. There is about 6 KB available for byte-coded user programs.

Shashank’s eleven year old son, Rutvik, demostrated the graphical "non-programming" environment by writing a simple program that moved the robot back and forth, switching directions on inputs from the light sensors and touch sensors.

Rutvik’s school has four dedicated PCs for programming the LEGO robots. To work with a particular robot, you must be sitting at the dedicated PC for that robot. Shashank’s goal is to use DRb to allow any PC in the lab to download programsm to any of the robots.

Using a second machine, Shashank ran a Ruby version of the program Rutvik used. The Ruby program on the client (rather than the RCX brick) and sent commands via DRb to the server machine, which in turn sent the command to the RCX robot via the IR tower.

…aside (David Black)

"Every conference needs a low point, and I’m always a team player". David confesses that he is standing in for a speaker who had to pull out of the conference. So David presented a program called aside that allows students to provide anonymous feedback to professors, and to allow professors to interact with anonymous students.

The purpose of David’s talk was not to present the program, but to open a discussion of applications vs frameworks and how to get some "half-baked" ruby programs out in the public eye. We discussed the role of RubyGarden and other web sites (e.g. CodedBliss) in the community. We had to cut the conversation short, but I’m sure the lunch time conversion

Building Environments for MUES (Michael Granger)

MUES stands for Multi-User Environment Server. MUES is the server for the FairyMUD project since 2000. It is an event based dispatcher for creating multi-user games. I’m really not up to speed on MUDs and such, but Michael’s design looked very clean and deep.

A Clueless Ruby Hacker Explores Security (Nathaniel Talbott)

Nathaniel talked about some basic issues around securing a DRb server using OpenSSL and other techniques. He stresses that security must be considered at a system level, not merely at a product level.

Teaching Ruby to Testers (Bret Pettichord)

Bret teaches a Scripting for Testers course with Brian Marick. They believe that some programming is required for automated testing, but that the programming should be easy. That’s why they use Ruby!

They take folk who have some programming experience, but that experience is stale. They might be familiar with procedural programming, but not with some of the newer paradigms. Bret and Brian use an Internet Explorer controller to programmatically control IE to interact with a web application. Bret demonstrated the code interactively.

Introducing Ruby to the Corporate World (Jim Freeze)

Jim’s perfect job involves getting paid to develope in Ruby (and not having to program in <fill in the blank>). Seriously, Jim shared some ideas for promoting Ruby in the workplace, something that most of us have dealt with in some for or another. Jim stresses the need to be honest about Ruby and its capabilities.

Jim has put together a course on Ruby for his company and is teaching it at several locations across the country.

Jim’s company also provides awards for "Productivity Wins", suggestions that save the company money. It was interesting to note that Ruby was involved in two of the first four wins in this contest and a third win copyied the architecture of a prior Ruby win.

Visions of the Future - Keynote Address (Yukihiro Matsumoto)

Finally, the moment we’ve all been waiting for, to hear news about Rite and Ruby 2. After an (short) introduction by David Black, Matz begins by saying that Ruby is "Good Enough" and that’s why we are here. So the real topic is "How Ruby Sucks", and what we will be doing about it.

First of all, Matz drew the distinction between what is Ruby 2 and what is Rite. Ruby 2 is the next version of the Ruby language. Matz plans to take advantage of the major version upgrade and introduce some things to clean up the language that are not necessarily backwards compatible. Rite refers specifically to the VM for Ruby 2.

So, with that in mind, here are some things that may by in Ruby 2.

Note:
The following is a paraphrase of the information Matz provided. The talk generally moved too fast for me to capture all the details, but I tried to capture the overall gist of the topic. If there are any inaccuracies, it is entirely my fault.
Note 2:
I discovered later that Chad Fowler had logged onto IRC during the keynote talk, and was streaming this same information into the IRC channel. Someone not at the conference was then taking the IRC information and updating the Ruby wiki pages in real time. That’s pretty cool.
  • Local Variable scope. Block parameters will be block local, hiding any existing variables. Also, local variables created by "eval" will
  • Instance Variables. @_foo will be truely private (not protected). Or maybe @foo will be private and @_foo protected. Matz hasn’t decided yet.
  • Constant Lookup. New rule will check enclosing class, then all superclasses, then one level of nesting classes. This simplifies the rules for constant lookup.
  • Class Variables. Now class variables will will be local to the class or module. Use accessors if you wish to access class variables from a larger scope.
    Question:
    How will class variables be different from class instance variables?
    Answer:
    Class instance variables are normal instance variables of the class object. Class variables will be more like static variables that are scoped by the class.
  • Statements and Expressions. No implicit string concatenation (use "+"). Parenthesis will cause line continuations. Statement grouping by parenthesis will be disallowed, use begin/end instead.
  • Multiple Values. Multiple value assignment is confusing. We can either separate arrays and multiple values strictly by syntax. Or we could use a subclass Array::Values < Array to return values. Matz hasn’t decided which solution he will go with. (There was a lot of questions and comments on this item).
  • Method Visibilities. Private may be in a separate namespace from public/protected.
  • Range in Condition. This is confusing. No one remembers the exact semantics (even Matz)
  • Keyword Arguments. Finally! Here’s the scoop:
      def foo(a, b: 42, **keys)
        p [a,b,keys]
      end
      foo(1)               => [1,42,{}]
      foo(2, b: 5)         => [2,5,{}]
      foo(3, b: 4, c: 6)   => [3,4,{:c=>6}]
    

    Some Smalltalkers wanted an optional colon after foo. Matz said no.

  • New Hash Literal. A new form of Hash literal will be available.
      { a: 1, b: 2, c: 3 }  == { :a => 1, :b => 2, :c => 3 }
    
  • Method Combination. Pre, Post and Wrap method combinations will be available. These methods are modelled after the CLOS before/after/around modifiers.
     class Foo
       def foo:pre();  p "pre"; end
       def foo:post(); p "post"; end
       def foo:wrap(); p "wrap pre";   super;   p "wrap post"; end
       def foo();      p ;foo"; end
     end
    

    prints …

     wrap pre
     pre
     foo
     post
     wrap post
    
  • Selector Namespace. It will be possible to modify the behaviors of selections within statically scoped namespace. Details are subject to change.
  • Optional Type. Current strong typing experiments are class/module based. Matz is exploring options, but wants any solution to be signature based and efficient.

Matz is interested hearing about ideas, so he is encouraging RCRs (Ruby Change Requests) for a limited time (say March 2004). He wants more than mere "could we change it this way" type of requests, but RCRs should contain an abstract, motivation, proposal and rationale. Mats demonstrates an "proper" RCR#1 with the proposal to remove "proc" from the language.

After talking about Ruby 2, the language; Matz moved on to talk a bit about Rite, the VM for Ruby 2. Ruby 1.9 will be a testing ground for some items targeted for Rite. It sounds like the big push will be for dealing with M17N. The new RegEx engine (handling M17N) will be in 1.9.

You can find the slides at: www.rubyist.net/~matz/slides/rc2003/

Post Conference Activities

It was back to Club Max for another night of hacking on RubyGems. The group continued to work on it throughout the day during lunch and breaks. This evening David Black joined us.

Friday night we worked without a net … well, network. But tonight someone had enough presence of mind to snag Shashank’s network hub. Imagine this, four networked laptops in the corner of the bar with cables strung across several tables. The local club hoppers took it all in stride.

Tonight was an integration night. David supplied a version comparison module that he had worked on during the day. Rich integrated it with the code base on his laptop. I setup a CVS server on my laptop made it available to everyone. We did eventually check into that CVS system, but because of the small number of files, it was difficult to split up work in a meaningful way. Rich went ahead with the the software to create and extract gem files. Chad concentrated on the remote download and install portion. He even got a simple WebBrick server set up to serve out gem files loaded on a system.

What did I do? Well, my presentation was first thing in the morning, so I took the opportunity to finish that before doing anything else. I was able to integrate the Gem creation software into my general package task library in rake. I even slipped in a last minute slide into the Rake presentation showing how to generate gems.

It is really interesting to see how other developers go about writing software. I had paired with Rich earlier that day and the man is a code generating machine. Rich didn’t to TDD (at least not while I was pairing with him), but every step he takes is incremental and well tested by hand. He really knows how to break up a programming session into small tasks and tackle them one at a time and then put together the pieces into the final whole.

The night broke up a bit earlier than the night before. By the time we broke up, we had the beginnings of an actual working system. It was pretty exciting.

Next: the final day of the conference.

 

Formatted: 07-Oct-08 22:24
Feedback: jim@weirichhouse.org