Final/closed classes in Ruby (was: Sharp knives and glue)


#1

The ‘Sharp knives and glue’ thread inspired this. It’s probably been
done before but here’s my implementation of a final and/or closed class:

Make a class unsubclassable

class Class
def final(klass)
class << klass
def inherited(subclass)
error = “Illegal attempt to subclass #{self} with
#{subclass}”
raise RuntimeError, error
end
end
end
end

class Foo
final(self) # No subclasses allowed
end

Boom!

class Bar < Foo
end

Close a class (no method definitions or redefinitions)

class Module
def close(klass)
class << self
def method_added(method)
error = “cannot add or change method #{method} to closed”
error += " class #{self}"
raise RuntimeError, error
end
end
end
end

class Foo
def test
puts “hello”
end
close(self) # No method additions/redefinitions allowed
end

Boom!

class Foo
def test2
puts “eh?”
end
end

This could probably be combined into a single method, and perhaps put in
the Kernel module as well.

Anyway, there you have it.

Regards,

Dan

This communication is the property of Qwest and may contain confidential
or
privileged information. Unauthorized use of this communication is
strictly
prohibited and may be unlawful. If you have received this communication
in error, please immediately notify the sender by reply e-mail and
destroy
all copies of the communication and any attachments.


#2

On Fri, May 12, 2006 at 06:27:13AM +0900, Berger, Daniel wrote:
} The ‘Sharp knives and glue’ thread inspired this. It’s probably been
} done before but here’s my implementation of a final and/or closed
class:
}
} # Make a class unsubclassable
[…]
} # Close a class (no method definitions or redefinitions)
[…]
} class Foo
} def test
} puts “hello”
} end
} close(self) # No method additions/redefinitions allowed
} end
[…]

class Foo
def test
puts “hello”
end
freeze #this already exists and does what you want
end

} Regards,
} Dan
–Greg


#3

On May 11, 2006, at 5:27 PM, Berger, Daniel wrote:

#{subclass}"

Boom!

class Bar < Foo
end

Has potential, but why not just do:

class Class
def final # or even final!
class << self
def inherited(subclass)
error = “Illegal attempt to subclass #{self} with
#{subclass}”
raise RuntimeError, error
end
end
end
end

class Foo
final
end

class Bar < Foo
end

RuntimeError: Illegal attempt to subclass Foo with
Bar
from (irb):7:in `inherited’
from (irb):17

Unfortunately, it raises an exception way too late.

try:

class Foo
final
end

begin
class Bar < Foo
end

Foo.inherited(Bar) pretty much happens here

rescue
end

b = Bar.new