using closures as a replacement for "class", @, and @@

E

Eric Mahurin

Some of you might find it interesting that ruby's closures/blocks can
be used as an alternative for defining classes/objects. It's actually
quite simple. You just do this:

- instead of class/def initialize, you use a function/method to define
how to create/initialize an object of that "class" (the function
name).
- add methods by calling define_method w/ a block on the metaclass on
the object that the "class" function will return.
- local variables of the "class" function become "instance" variables
since all of the blocks used for defining methods are closures and
have access to them.
- a variable outside that "class" function that is accessible can be
used a "class variable".
- inheritance is easily done by starting with an object of the base class
- multiple inheritance is probably best done with using a "has-a"
relationship and delegating particular methods to particular member
objects. You could also mixin using Object#extend.
- calling a base class method can be done several ways: a) renaming
the base method before redefining the derived method, b) store the
base method in an instance variable, c) use a "has-a" relationship and
store the base object in an instance variable - inherit/delegate or
define each method explicitly.

All this is mostly academic. You should be able to base a complete
object-oriented language on closures.

There are a few advantages:

- don't need keywords for classes: class, module, self, super, etc.
- don't need to prefix instance/class variable with @ and @@. It is
determined by closure scope instead.
- don't need a special "initialize" method. You put this
functionality at the top-level of the "class" definition instead.
- instance variables are completely private. You could even have base
and derived classes with instance variables of the same name and they
won't collide. Of course you might consider this a disadvantage when
you want a derived class to access an instance variable of a base
class, but this can be done by providing methods to the instance
variables.

Here is a simple example:

class Object
# are we ever going to get the fundamental method built-in to Object?
def metaclass
class<<self;self;end
end
# this would be great to have by default too.
def define_method(name, &block)
self.metaclass.send:)define_method, name, &block)
end
end

# conventional class
class Employee1 < String
@@id = 0
def initialize(name)
super(name)
@id = @@id
@@id += 1
@salary = 0
end
def self.id(); @@id; end
def id(); @id; end
def salary(); @salary; end
def hire(salary); @salary=salary; end
def raise(inc); @salary+=inc; end
def fire(); @salary=0;end
end

# closure "class"
next_id = 0 # class variable: all Employee2 methods/closures share this
Employee2 = proc { |name|
this = String.new(name) # inherits methods from String
id = next_id # instance variable: methods/closures of this object share this
next_id += 1
salary = 0 # instance variable: methods/closures of this object share this
this.define_method:)id) { id }
this.define_method:)salary) { salary }
this.define_method:)hire) { |s| salary = s }
this.define_method:)fire) { salary = 0 }
this.define_method:)raise) { |inc| salary += inc }
this
}
Employee2.define_method:)id) { next_id } # class method

e1 = Employee1.new("bob")
e2 = Employee1.new("john")
e3 = Employee1.new("sally")

e1.hire(20)==20
e3.hire(25)==25

e1=="bob" and e1.salary==20 and e1.id==0 or raise(e1)
e2=="john" and e2.salary==0 and e2.id==1 or raise(e2)
e3=="sally" and e3.salary==25 and e3.id==2 or raise(e3)
Employee1.id==3 or raise

e1 = Employee2.call("bob")
e2 = Employee2.call("john")
e3 = Employee2.call("sally")

e1.hire(20)==20
e3.hire(25)==25

e1=="bob" and e1.salary==20 and e1.id==0 or raise(e1)
e2=="john" and e2.salary==0 and e2.id==1 or raise(e2)
e3=="sally" and e3.salary==25 and e3.id==2 or raise(e3)
Employee2.id==3 or raise
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,740
Latest member
AdolphBig6

Latest Threads

Top