Showing posts with label Ruby. Show all posts
Showing posts with label Ruby. Show all posts

Sunday, September 18, 2011

Io, Syntactic Sugar, and Performance

I had never heard of Steve Dekorte's Io language until coming across it in Bruce Tate's book. Io uses the prototype-based or classless paradigm, which is a flavor of the Object Oriented paradigm. In classless programming, classes are not declared but are cloned from the base object class. Such languages are usually interpreted and dynamically typed. The most popular classless language is JavaScript.

Io is interesting for a number of reasons, such as its actor-based concurrency model, but what struck me the most in working through Bruce Tate's examples was the ugliness of the code. There's no way around it. It's just ugly. This was especially noticeable after learning some Ruby. If you want a complex class structure, you have to do a lot of cloning. Here's an example that clones the root object class and then clones that clone in order to actually do something:
Account := Object clone do(
balance := 0
deposit  := method(v, balance = balance + v)
withdraw := method(v, balance = balance - v)
show := method(writeln("Account balance: $", balance))
)

myAccount := Account clone
myAccount show
"Depositing $10\n" print
myAccount deposit(10)
myAccount show
While the words "programming" and "aesthetics" are not often used in combination, we do regularly talk about the elegance of code--meaning its ability to solve a problem in a creative and concise manner. Elegance can come at the price of readability, since it typically involves doing something complex in a short number of lines. Io does concurrency elegantly, but its classless model doesn't allow for a lot of concision or elegance more generally. If you want to create a number of classes with a number of methods, this will take many more lines than in a language like Ruby.

Unlike Io, Ruby has a lot of syntactic sugar, or programming shortcuts that make code more readable and concise. This is different from elegance, since syntactic sugar has to do with syntax while elegance has to do with logic. For instance, instead of defining a bunch of get and set statements for a class's properties, you can define them all in one line using the attr_accessor command in Ruby. These shortcuts can make the learning curve a little steeper, since there are more commands to learn, but this might be a trade-off worth taking. Io takes minimalism to the extreme, so you can learn the basics in a short amount of time. However, understanding how to turn the small bits into something bigger is another question entirely!

Besides having a more gradual syntactic learning curve, Io's lack of syntactic sugar enables it to have a very small virtual machine (about 9k semicolons). This means it can fit on small embedded systems, though I'm not sure how many production environments use it. I should also mention that, despite its small footprint, it is not known for being performant, given its message-passing structure and the fact that it is not compiled.

Io has helped me to understand and appreciate JavaScript better, instead of simply thinking of it as a more difficult to debug version of C++, but it made me pine for more readable languages like Ruby or VB.NET.

Links:
-The Io Language

Sunday, August 21, 2011

Metaprogramming in Ruby

I've started learning some Ruby, one of the most popular object-oriented languages today. In OO programming, data and actions upon data are bundled together in objects that represent real-world things, such as cars, financial transactions, or database connections. Ruby is remarkable because it allows you to change object definitions on the fly due to 1) its open class structure (no methods are private) and 2) the fact that it is interpreted (not compiled beforehand). Since binding occurs at run-time, you can call any method on any object. If that method is not supported, it will call the method_missing method, which itself can be overridden to interesting effect.

Though Ruby does not support multiple inheritance, you can alter classes dynamically by extending them with modules. These modules are called mixins, since you can mix them in whenever you want. This allows for amazing flexibility and an advanced programming technique called metaprogramming, or the programming of programs by programs.

Metaprogramming sounds esoteric, but it is particularly useful when you're designing classes that need to have dynamic metadata. For example, Ruby's Active Record class implements Object Relation Mapping, creating wrappers for database objects. A table, view, or stored procedure can be accessed with standardized methods that can be automatically generated according to the database object to be instantiated once a database connection is established.

I put together some (unfinished) code that shows how this might work. The DBObject class includes the BuildDBObjects class, which extends the BuildIncludes class, which in turn mixes in the appropriate modules as dictated by the constructor. If you construct a table wrapper, only the BuildTable class is included. Each database type could use the same wrapper properties: metadata, data, and name.

module BuildDBObjects
    def self.included(base)
        base.extend BuildIncludes
    end
  
    module BuildIncludes
        def initialize(dbtype, name)
            case dbtype
                when "table"
                    include BuildTable
                    define_table(name)
                when "view"
                    include BuildView
                    define_view(name)
                    #...
            end
        end
    end

    module BuildTable
        def define_table(name)
            # query the database...
            @metadata = %w(SaleID ProductID DateSold)
            @data = %w(1101421 15981923 11/4/2006)
        end
    end

    module BuildView
        #...
    end

    attr_accessor :metadata, :data, :name
end

class DBObject
    include BuildDBObjects
end

tbl = DBObject.new("table","SalesOrders")
puts tbl.name
puts tbl.metadata
puts tbl.data
This is metaprogramming, since the code itself writes the class definition for each instantiation of the DBObject class. The great thing about using metaprogramming to implement object relation mapping is that your classes can change as your database schema changes. This cuts down on the amount of code you might have to write, depending on the way you're accessing data. (Of course, you should create a data access class that uses the ORM in order to decouple the database schema from the application code--otherwise your application code might break with the slightest changes to the database.)

Though this example isn't exactly esoteric, it's probably not something you're going to do every day. It also shows a downside to metaprogramming: you have to write code that is meant to be read by computers. That means it might not be particularly readable by humans. One of the many reasons people like Ruby is that it is very programmer-friendly. It's very easy to read while at the same time cutting down on a lot of "extra" code, like class accessors. Since metaprogramming is often less easy to read and understand, it's often more difficult to maintain.

A few links:
-Paolo Perrotta's book dedicated to metaprogramming Ruby, which contains an extended look at Active Record
-Ruby's core API
-Programming Ruby Pragmatic Programmer's Guide (2001)
-A good mixin tutorial
Related Posts Plugin for WordPress, Blogger...