Download presentation
Presentation is loading. Please wait.
Published byAurora Roswell Modified over 10 years ago
1
Method Shelters: Avoiding Conflicts among Class Extensions Caused by Local Rebinding Shumpei Akai, Shigeru Chiba Tokyo Institute of Technology 1
2
Class Extensions Destructively 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) 2
3
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’ lib 10.kilobytes # => 10240 10.kilobytes # => NoMethodError: undefined method require “active_record” #load rails’ lib 10.kilobytes # => 10240 3
4
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
5
What is the appropriate scope of class extensions? Global? ◦ Same as Ruby Lexical? ◦ Redefinitions are available in a lexical scope Local rebinding property (of Classbox *)? ◦ Redefine methods in another module by importing ◦ Redefinition is limited in imported module 5 * [‘05 Bergel et al.]
6
Global Scopes 6 List avg(): average of elems using div Integer div(): return rational Integer div(): return integer plus(): … minus(): … 1.div(2) #=> (1/2) Redefine destructively Module 1 Module 2 Module 3 No one can use original div()
7
Lexical Scopes 7 List avg(): average of elems using div Integer div(): return rational Integer div(): return integer plus(): … 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 [1, 2].avg() #=> (3/2) 1.div(2) #=> 0 [1, 2].avg() #=> (3/2) 1.div(2) #=> 0
8
Local rebinding (Classbox) 8 List avg(): average of elems using div Integer div(): return rational Integer div(): return integer plus(): … minus(): … 1.div(2) #=> 0 Module 1 Module 2 Module 3 import [1, 2].avg() #=> (3/2) 1.div(2) #=> (1/2) [1, 2].avg() #=> (3/2) 1.div(2) #=> (1/2) Module 4 Redefinition in importing chain Original div() Redefined div()
9
Local rebinding (Classbox) 9 List avg(): average of elems using div Integer div(): return rational Integer div(): return integer plus(): … minus(): … [1, 2].avg() #=> (3/2) 1.div(2) #=> Conflicts [1, 2].avg() #=> (3/2) 1.div(2) #=> Conflicts Module 1 Module 2 Module 3 1.div(2) #=> (1/2) [1, 2].avg() #=> (3/2) 1.div(2) #=> (1/2) [1, 2].avg() #=> (3/2) Module 4
10
Our proposal: Method Shelters A 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
11
A Code with Method Shelters shelter :MathN do class Fixnum # fixed size integer in Ruby def /(x) Rational(self,x) end shelter :Average do class Array def avg sum = self.inject(0){|r,i|r+i} sum / self.size end hide import :MathN end shelter :MathN do class Fixnum # fixed size integer in Ruby def /(x) Rational(self,x) end shelter :Average do class Array def avg sum = self.inject(0){|r,i|r+i} sum / self.size end hide import :MathN end 11
12
Chambers in a method shelter A 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#m0 S0 Exposed Hidden 12 Import
13
Exposed Chambers for public API ◦ Local rebinding Methods ◦ Visible from importer Import ◦ Imported methods are also visible from importer - Obj#m0 S0 S1 S2 import 13 Call/redefine
14
Hidden chamber for internally used methods ◦ Not called/redefined from importer Method ◦ Visible only from the same shelter Import ◦ Imported methods are not visible from importer - Obj#m1 - Obj#m0 S0 S1 S2 14 Call import
15
Method Lookup Algorithm Contexts : ◦ (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
16
- m1 - m0 current First, look up this group Second, 16 *Look up from importer
17
Detect Ambiguity If you use exposed chambers, it may cause conflicts ◦ Detects and raises an error S0 - C#m0 S1 S2 Error! - C#m0 S3 17
18
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 shelter :ShelterName do class Foo def hoge # <- defined in the method shelter end 18
19
Syntax: Import shelter :ShelterName do import :AnotherShelterName end shelter :ShelterName do import :AnotherShelterName end 19
20
Syntax: hide “hide” method switches a chamber ◦ Methods and imports below “hide” are in the hidden chamber shelter :ShelterName do # exposed chamber hide # hidden chamber end shelter :ShelterName do # exposed chamber hide # hidden chamber end 20
21
Example of method shelters 21 List avg(): average of elems using div Integer div(): return rational Integer div(): return integer plus(): … minus(): … Shelter1 Sheleter 2 Sheleter 3 [1, 2].avg() #=> (3/2) 1.div(2) #=> 0 [1, 2].avg() #=> (3/2) 1.div(2) #=> 0 Shelter 4
22
Example of method shelters 22 List avg(): average of elems using div Integer div(): return rational Integer div(): return integer plus(): … minus(): … Shelter1 Sheleter 2 Sheleter 3 [1, 2].avg() #=> (3/2) 1.div(2) #=> (1/2) [1, 2].avg() #=> (3/2) 1.div(2) #=> (1/2) Shelter 4
23
Implementation Based 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
24
Micro benchmark : empty methods Micro benchmark : empty methods Call an empty method in shelter 10,000,000 times ◦ Less than 5% overhead when shelters are used 24
25
Micro benchmark : Ruby on Rails Enabled shelters in an action method ◦ Numeric#kilobytes method in a shelter In the action method ◦ 1. Call kilobytes method in shelter ◦ 2. One access to SQLite 4% overhead 25
26
Related Work Refinements (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
27
Conclusion Method 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
28
Evaluate Should specify the initial method shelter ◦ Evaluate within a shelter shelter_eval :ShelterName do #shelter is enabled end shelter_eval :ShelterName do #shelter is enabled end 28
29
Global Methods Methods not in shelters ◦ Callable from any shelter ◦ Global methods can call methods in a shelter if the caller is in the shelter To preserve local rebinding obj.g0() S0 - Obj#g0 Global 29
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.