[OSCON] Monday Morning
Facets of Ruby
Presented by Dave Thomas, OSCON 2005
I'm sitting in Dave Thomas's session on Intro to Ruby at the Oregon Convention Center. It looks like someone finally figured out the main problem with conferences - lack of power outlets. Kudos to O'Reilly - they've put power strips at the base of every table in this room. With the high-speed wireless and unlimited power, this conference is getting off to a great start.
Is programming still fun?
Round about 2000, programming started getting tedious for Dave - after having fun for the past 25 years. When we program, we combine all the problems of the artistic side of the race with all of the problems of the scientific side of the race. The only way to be successful at it is to enjoy doing it.
Is programming productive?
It has to be to enjoy it. The most satisfying thing about programming is watching it run. That's why scripting languages are so great - because you can see it run now. Myth: a good programmer can be a good programmer in any language. Language and tools make a difference - a good programmer knows which language to choose for a particular problem.
This session is not going to be a syntax session. Damn, sounds like I won't really learn how to program Ruby in this session.
Ruby, the Language
Born in Japan in 1994. Father: Invented by Yukihiro Matsumoto (Matz). Mother: Ada, Smalltalk, CLU, Perl, Lisp. Grew very rapidly in 2000, outpaced Python in 2000. Became international star in 2004.
Dave and Andy are language freaks and downloaded Ruby 1.4 shortly after finishing The Pragmatic Programmer. It passed the 5-minute test, the 1/2-hour test and Dave ended up playing with it all morning. The first Pickax book was 500+ pages long, and they wrote it because there wasn't much English-language documentation on Ruby. Ever since Rails, Ruby's adoption has grown exponentially.
Ruby is a multi-paradigm language: procedural, object-oriented, functional, meta-programming. You can write procedural code, but you'll be using OO concepts at the same time. You can do all of these at the same time.
Ruby code example:
# Generate Fibonacci numbers up to a given limit def fib_up_to(max) f1, f2 = 1, 1 while f1 <= max puts f1 f1, f2 = f2, f1+f2 end end fib_up_to(1000)
Methods start with def and end with end. The parenthesis around the method arguments are optional.
Now Dave is ragging on Java Programmers and how they discount Ruby because of its duck typing. In a Java program, most things are dynamically typed too. This is because most objects are stored in collections and whenever you pull things out of a collection - you have to cast from Object to the real type. The argument is that you don't have to have static typing. Dave hates Generics because he thinks they should've just done automatic casting.
The basic gist of Dave's argument is that we use dynamic typing (using casting) in Java all the time and you don't see Runtime exceptions all of the place. So the biggest proponents of static typing are actually using dynamic typing all of the place.
Back to the code: in Ruby, you don't need parenthesis around conditionals (for instance in the while statement above). The main reason we have parenthesis is because of Fortran. There's no reason for them. You can put parenthesis and semi-colons in your code, but you don't need to. In this code example, the variables are scoped for the duration of the method. puts (pronounced "put s") just prints the value of a variable to the console.
class Song def initialize(a_title) @title = a_title end def title @title end end
Instance variables in Ruby start with an @ sign. The first time you use them, they spring into existence. If you access an instance variable and it's value hasn't been set - it's value is nil. Using the return keyword at the end of a method is optional - the default is to return the last line of a method. You can change the "title" method to use
attr_reader :title
The attr_reader call is actually a method of Class:class. The attr_reader will dynamically add an accessor (that looks like the title method above). To create a setter, you can use attr_accessor and it'll create both a getter and setter.
Ruby is a single Inheritance language.
class KaraokeSong < Song attr_reader :lyric def initialize(a_title, a_lyric) super(a_title) @lyric = a_lyric end end
Unlike Java, the super call can happen in any line, or not at all. To solve the single-inheritance problem, you can use mixins and apply them to any class.
Blocks and iterators are pervasive in Ruby, and look to be very easy to use.
3.times { puts "Ho!" } hash.each { |key, value| puts "#{key} -> #{value}" end
To do method calls with blocks, you use the yield keyword.
You can use blocks to simplify Resource Management and automatically close resources.
File.open("myfile.dat") do |f| name = f.gets # whatever end
When the above code hits end, the file is automatically closed.
Duck Typing
Strongly-typed objects, untyped variables and methods. Types are implicitly determined by the things that an object can do. Duck typing is great for testing, refactoring and maintenance. This is very similar to concepts in Smalltalk. There is a strong commitment to unit testing in Ruby - which makes duck typing even easier to use. Duck typing makes things very easy. For example, you can have a method that takes a file as a parameter - and writes data to it. You can test this method by passing in a String (which also supports << for appending) and verify that your method's logic works.
Duck typing is useful in regular code for reducing coupling and increasing flexibility. Ruby community now differentiates the type (what it can do) of an object and the class (what generated it) of an object.
The Road to Metaprogramming
Metaprogramming is really, really powerful in Ruby. Library writers use it, but most developers don't use it. The ActiveRecord framework is an example of metaprogramming. Rather than being an O/R Mapping tool, it's more of a database table wrapper. The belongs_to, has_one, has_many and other validation_presence_of method calls can be written by you. Allowing you to write DSL (domain-specific languages) that appear to be a part of the Ruby language.
4 steps to metaprogramming:
- Classes are open: in Ruby, you can always add methods,
attributes, etc. to existing classes. For example, you can add an encrypt() method
to the
String
class. Isn't this dangerous? What if someone changes the logic of + for math expressions. No, because if one of your programmers overrides methods that breaks things - you take them out in the parking lot and beat them with a rubber hose! The language shouldn't prohibit us from doing powerful things. - Definitions are active: code executes during what would normally be compilation. As the class if being defined, the code is being executed. For example, you can check if an environment variable is set - and create methods (i.e. log.debug()) accordingly. This can be great for caching.
- All method calls have a receiver: Methods are executed on objects. There's always a current object: self. Methods with no explicit receiver are executed on current object.
- Classes are objects too: You can easily add methods to classes.
Many more Ruby features: Reflection and ObjectSpace, Marshalling and Distributed Ruby, Tk, Gtk, Fox, networking, databases, etc. Garbage collection, Threads (like Java green threads), Modules and mixins. ObjectSpace - allows you to reflect on all of the objects that exist at runtime. Marshalling allows you to serialize into binary or text formats. No XML - uses YAML instead. Unlike XML, it's readable and looks more like a properties file. Modules (and their methods) can be easily included into a class simply by using "include ModuleName".
Now Dave is going to write a program to extract book sales ranks from Amazon pages, publish them as an RSS Feed, store them in a database, and access via a web application (using Rails). Since this is likely to involve a lot of live coding, I probably won't blog the code Dave writes.
Web Applications in Ruby can be done with Simple CGI, FastCGI, mod_ruby and frameworks (like Rails). Iowa, CGIKit, Nitro and Ruby on Rails are all web frameworks in Ruby. Iowa is a Ruby implementation of Apple's WebObjects. Dave's quote: "Apple really screwed up with WebObjects, they could've owned the market on web frameworks."
Summary
- Use Ruby because it is Lightweight. A Ruby download is under 10 MB. Ruby Gems allows easy package management for downloading libraries and documentation.
- Use Ruby is Transparent. It's nice and easy to read - and it only takes a couple of hours to learn its syntax.
- Portable - runs on PDAs and Mainframes.
- Open Source - MIT/Artistic style license. 1.8.3's regular expression engine is LGPL, 1.9's engine will be BSD-style license.
- Easy to Learn - uses the Principle of Least Surprise. Things seem to work as you'd expect. Dave knows people that've downloaded Ruby and put web applications on line in the same morning - w/o any prior knowledge of Ruby.
- Fun! It's enjoyable to program in.
Ruby Resources
- http://www.ruby-lang.org
- http://www.rubygarden.org
- http://www.rubyonrails.org
- com.lang.ruby - ruby-talk mailing list
- http://pragmaticprogrammer.com/titles/ruby (1st edition online for free, covers Ruby 1.6)
- Other Books: The Ruby Way, Ruby Developer's Guide, Agile Web Development with Rails (available for the first time at the OSCON bookstore)
Posted by Mike on August 01, 2005 at 07:16 PM MDT #
AFAIK, at conferences and such - it's OK to blog what the speaker talks about. I've been doing it for a couple of years now and haven't had a complaint yet. I also threatened Dave that I was going to heckle him on my blog this morning and he didn't seem to mind. ;-)
Of course, his talk was too good and I found no reason to heckle him.
Posted by Matt Raible on August 01, 2005 at 07:25 PM MDT #
Posted by Nick Sieger on August 02, 2005 at 02:44 PM MDT #
Posted by Scott Schram's Blog on August 03, 2005 at 07:30 PM MDT #
Posted by atog on August 03, 2005 at 09:32 PM MDT #
Posted by Michael Levin's Weblog on August 05, 2005 at 06:36 PM MDT #
Posted by George Moschovitis on August 06, 2005 at 07:28 AM MDT #
"In a Java program, most things are dynamically typed too. This is because most objects are stored in collections and whenever you pull things out of a collection - you have to cast from Object to the real type."
is simply wrong, Java has type-aware collections.
Scripting languages are a bit like fashinon collections. Last year Python was very hot, this year Ruby seems to take its place...
Another thing that I have noticed is that all scripting-languages advocates just love to kick Java, I can't figure out why. Why Java, not C, C++, etc.
It's kind of funny since Java has built in support for scripting languages, which can run on the Java Virtual Machine (much better then any VM used by Python or Ruby), there are even nice implementations, like Groovy, which has all such loved elements of scripting languages: no parenthesis and semicolons, closures, dynamic typing).
Posted by Piotr Kochanski on August 08, 2005 at 08:34 AM MDT #
Posted by Dave Thomas on August 24, 2005 at 09:36 PM MDT #