method shelters: avoiding conflicts among class extensions caused by local rebinding shumpei akai,...
TRANSCRIPT
1
Method Shelters: Avoiding Conflicts among Class Extensions Caused by Local Rebinding
Shumpei Akai , Shigeru ChibaTokyo Institute of Technology
Class ExtensionsDestructively change method definitions
in the existing classes◦Write new definitions in a separate file
Available in ◦Smalltalk, Objective-C, AspectJ …◦and Ruby
(called Open Class)
String
JSON lib
+ to_ json
2
Class Extensions are popular in Ruby
Ruby on Rails aggressively adds methods to built-in classes◦Class extensions are used in real applications◦e.g.
10.kilobytes # => NoMethodError: undefined method
require “active_record” #load rails’ lib10.kilobytes # => 10240
3
Conflicts among Class Extensions
Class extensions are dangerous◦Cause conflicts, of course
Ruby allows class extensions◦Ruby on Rails aggressively use◦Serious issue in Ruby◦Scope of class extensions are needed
4
What is the appropriate scope of class extensions?Global?
◦Same as RubyLexical?
◦Redefinitions are available in a lexical scopeLocal rebinding property (of Classbox *)?
◦Redefine methods in another module by importing
◦Redefinition is limited in imported module
5* [‘05 Bergel et al.]
Global Scopes
6
List
avg(): average of elems using div
Integerdiv(): return rational
Integerdiv(): return integerplus(): …minus(): …
1.div(2) #=> (1/2)
Redefine destructively
Module 1
Module 2
Module 3
No one can use original
div()
Lexical Scopes
7
List
avg(): average of elems using div
Integerdiv(): return rational
Integerdiv(): return integerplus(): …minus(): …
Redefinition in Lexical scope
Module 1
Module 2
Module 3
Cannot reuse redefined div()
[1, 2].avg() #=> (3/2)1.div(2) #=> 0[1, 2].avg() #=> (3/2)1.div(2) #=> 0
Local rebinding(Classbox)
8
List
avg(): average of elems using div
Integerdiv(): return rational
Integerdiv(): return integerplus(): …minus(): …
1.div(2) #=> 0
Module 1
Module 2
Module 3
import
import
[1, 2].avg() #=> (3/2)1.div(2) #=> (1/2)
Module 4
Redefinition in importing chain
Original div()Redefined div()
Local rebinding(Classbox)
9
List
avg(): average of elems using div
Integerdiv(): return rational
Integerdiv(): return integerplus(): …minus(): …
[1, 2].avg() #=> (3/2)1.div(2) #=> Conflicts
Module 1
Module 2
Module 31.div(2) #=> (1/2)[1, 2].avg() #=> (3/2)
Module 4
Our proposal: Method SheltersA method shelter is a module which
provides a way to control scopes of class extensions◦2 mechanisms
Preserves local rebinding Or redefine methods in limited scope
Based on Ruby
10
A Code with Method Sheltersshelter :MathN do class Fixnum # fixed size integer in Ruby def /(x) Rational(self,x) end endendshelter :Average do class Array def avg sum = self.inject(0){|r,i|r+i} sum / self.size end end hide import :MathNend
11
Chambers in a method shelterA method shelter has two parts
◦An exposed chamber and a hidden chamber◦Each chamber contains methods and
“import”s◦Exposed : for public APIs (similar to public)
◦Hidden : for internal use (similar to protected)
- Obj#m0S0
Exposed Hidden
12
Import
Exposed Chambersfor public API
◦Local rebindingMethods
◦Visible from importerImport
◦ Imported methods are also visible from importer
- Obj#m0S0
S1
S2
import
import
13
Call/redefine
Call/redefine
Hidden chamberfor internally used
methods◦Not called/redefined from
importerMethod
◦Visible only from the same shelter
Import◦ Imported methods are not
visible from importer
- Obj#m1 - Obj#m0S0
S1
S2
14
Call
Call
import
Method Lookup AlgorithmContexts :
◦(class, method name, current shelter)Search for methods as follows:
◦1. look up the current shelter’s hidden-chamber and its importing shelters
◦2. look up the current shelter’s exposed-chamber and its importing shelters
◦3.If not found, go to the superclass
15
- m1- m0
current First, look up this group
Second,
16
*Look up from importer
Detect AmbiguityIf you use exposed chambers, it may
cause conflicts◦Detects and raises an error
S0
- C#m0S1 S2
Error!
- C#m0S3
17
Syntax We have not modified syntax
◦Ruby has powerful syntax◦Use ordinal methods with a block
shelter :ShelterName do class Foo def hoge # <- defined in the method shelter end endend
18
Syntax: Import
shelter :ShelterName do import :AnotherShelterNameend
19
Syntax: hide“hide” method switches a chamber
◦Methods and imports below “hide” are in the hidden chamber
shelter :ShelterName do # exposed chamber hide # hidden chamberend
20
Example of method shelters
21
List
avg(): average of elems using div
Integerdiv(): return rational
Integerdiv(): return integerplus(): …minus(): …
Shelter1
Sheleter 2
Sheleter 3
[1, 2].avg() #=> (3/2)1.div(2) #=> 0
Shelter 4
Example of method shelters
22
List
avg(): average of elems using div
Integerdiv(): return rational
Integerdiv(): return integerplus(): …minus(): …
Shelter1
Sheleter 2
Sheleter 3
[1, 2].avg() #=> (3/2)1.div(2) #=> (1/2)
Shelter 4
ImplementationBased on Ruby 1.9.2 Add one implicit argument to method:
◦Current method shelter Optimize method-lookup caches
◦Shelter node cache Caches method body in a shelter
◦Extend inline cache Stores the found shelter Size of an inline cache : 3 word -> 4word
(per method call)
23
Micro benchmark : empty methods
Call an empty method in shelter 10,000,000 times◦Less than 5% overhead when shelters are
used
24
Micro benchmark : Ruby on RailsEnabled shelters in an action method
◦Numeric#kilobytes method in a shelterIn the action method
◦1. Call kilobytes method in shelter◦2. One access to SQLite
4% overhead
25
Related WorkRefinements (for Ruby)
◦Provide a scope of methods◦Redefined methods are available in lexical
scope No local rebinding
Classboxes [‘05 Bergel et al.]
◦A classbox provides the scope of class extensions
◦ Introduce Local rebinding property
26
ConclusionMethod shelters provide 2 mechanisms for
implementing scope of class extensions◦Exposed and Hidden◦You can control scopes of class extensions by
combining them◦Avoid conflicts
Implementation on Ruby◦reasonable overhead by caches
27