method shelters : another way to resolve class extension conflicts
DESCRIPTION
A presentation on Rubykaigi11TRANSCRIPT
![Page 1: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/1.jpg)
Method Shelters : Another Way to Resolve Class Extension Conflicts Classboxes でも Refinements でもない別のやり方
Shumpei Akai / 赤井駿平
@flexfrank
![Page 2: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/2.jpg)
What I talk about today
Open Class causes conflicts of methods
Method Shelters resolve it!
![Page 3: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/3.jpg)
% whoami
Shumpei Akai / 赤井駿平
@flexfrank
Ph.D. Student / 学生(博士課程)
◦ 東工大の千葉研
◦ Programming Languages and Moduralization
◦ プログラミング言語とモジュール化
Today’s topic is my current research
![Page 4: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/4.jpg)
Open Class
Ruby’s one of the important features
You can (re)define methods in existing classes
◦ including Object, Integer, Array, …
Frequently used in Ruby world
![Page 5: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/5.jpg)
in open-uri
open-uri redefines “open” method
◦ It accepts URI
open("http://penguindrum.jp/"){|f|f.read}# => Errno::ENOENT: No such file or directory
require "open-uri”open("http://penguindrum.jp/"){|f|f.read}# => "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\”…”
![Page 6: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/6.jpg)
in Ruby on Rails
ActiveSupport adds various convenient methods to core classes
◦ e.g.
10.megabytes # => 104857601.day.ago # => Sat Jul 16 16:15:00 +0900 2011"survival strategy".pluralize #=> "survival strategies"
![Page 7: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/7.jpg)
Or Monkey Patching
![Page 8: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/8.jpg)
Problem of Open Class
Methods may conflict
When One library adds a method
◦ and another library adds a method with the same name in the same class
The method defined first is vanished!
◦ depends on the order of “require”
◦ Confusing!
![Page 9: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/9.jpg)
Method conflicts
I encountered about five years ago
◦ Ruby on Rails and flvtool added a method to String
◦ they used String as binary/array of int
Difficult to collaborate these two libraries
◦ I separated processes
◦ communicating via dRuby
![Page 10: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/10.jpg)
Another example of conflicts
“mathn” redefines the “Integer#/”
◦ returns a Rational object
◦ Ordinary code expects “/” returns a integer
Programs get broken
![Page 11: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/11.jpg)
Existing Solutions
Several module systems are proposed to resolve conflicts
◦ Selector namespaces (for Smalltalk)
◦ Classboxes (for Smalltalk and Java)
◦ Refinements (for Ruby)
◦ …
![Page 12: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/12.jpg)
Refinements
Proposed by Shugo Maeda [ruby-core:33322]
module MathNrefine Fixnum do
def /(other) quo(other)
endend
end
class Foousing MathNdef foo
p 1 / 2end
end
f = Foo.newf.foo #=> (1/2)p 1 / 2
![Page 13: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/13.jpg)
Refinements (cont.)
Refinements changes behavior of methods in a lexical scope
◦ methods defined by Refinements are not enabled in indirectly called methods
◦ No local rebinding
I need local rebinding
◦ e.g. scoped monkey patching
![Page 14: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/14.jpg)
Classboxes
You might have known via matz’s diary
![Page 15: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/15.jpg)
Classboxes
A classbox restrict the scope of methods
A classbox can import a class in another classbox
◦ You can use an imported class
◦ You can add/redefine methods to the imported class
◦ A redefined method can be called from the imported class
Local rebinding property
![Page 16: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/16.jpg)
Classboxes
Cited from “Classbox/J: Controlling the Scope of Change in Java”
![Page 17: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/17.jpg)
The Problem in Classboxes
Importing overwrites internally used classes
◦ Importing causes another conflict
![Page 18: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/18.jpg)
The Problem in Classboxes
Redefines Integer#div
Original Integer
Uses redefined Integer#div
returns rational
Oops!returns integer
Use original Integer
![Page 19: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/19.jpg)
I need another module system
A new module should:
◦ have local rebinding
◦ provide a way to resolve conflicts cause by importing
◦ not depends on the order of load
![Page 20: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/20.jpg)
Method Shelters
![Page 21: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/21.jpg)
Key concept
Hide your methods
Hide your imports
![Page 22: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/22.jpg)
What is a method shelter
A method shelter is a module which provides a scope of methods
◦ define methods in a method shelter
◦ import other method shelters
You can call methods in the imported shelter
You can call methods in the shelter which is importing the current shelter for local rebinding
importer
importeecall
call
![Page 23: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/23.jpg)
A Code with Method Shelters
shelter :MathN doclass Fixnum # fixed size integer in Ruby
def /(x)Rational(self,x)
endend
endshelter :Average do
class Arraydef avg
sum = self.inject(0){|r,i|r+i}sum / self.size
endendhideimport :MathN
end
![Page 24: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/24.jpg)
What conforms a method shelter
A method shelter is separated into tow parts
◦ An exposed chamber and a hidden chamber
◦ in order to protect internally used methods
◦ Each chamber can define methods and import
- Exposed - Hidden
![Page 25: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/25.jpg)
Exposed Chambers
for public API
Exposed methods◦ Visible from importer
◦ Importer can call or redefine exposed methods
Exposedly import◦ Transitive importing
◦ Imported methods are also visible from importer
- Obj#m0S0
S1
S2
![Page 26: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/26.jpg)
Hidden chamber
for internally used methods
Hidden method
◦ invisible in importing shelter
Hiddenly import
◦ Imported methods are not exposed
- Obj#m1 - Obj#m0S0
S1
S2
![Page 27: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/27.jpg)
Global Methods
Ordinal methods not in shelters
◦ Callable from any shelter
◦ Global methods can call methods in a shelter if the caller is in the shelter
obj.g0()S0
- Obj#g0
Global
![Page 28: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/28.jpg)
No Ambiguity
If 2+ methods are found in imported shelters
◦ Error!
S0
- C#m0S1 S2
Error!
- C#m0S3
![Page 29: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/29.jpg)
Syntax
I don’t want to edit parse.y
define methods in a block
shelter :ShelterName doclass Foodef hoge # <- defined in the method shelterend
endend
![Page 30: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/30.jpg)
Syntax: Import
shelter :ShelterName doimport :AnotherShelterName
end
![Page 31: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/31.jpg)
Syntax: hide
“hide” method switches a chamber
◦ do def or import below “hide”
shelter :ShelterName do# exposed chamber
hide# hidden chamber
end
![Page 32: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/32.jpg)
Evaluate
Evaluate within a shelter
shelter_eval :ShelterName do#shelter is enabled
end
![Page 33: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/33.jpg)
Method Lookup Algorithm
1. look up hidden-chamber
2. look up exposed-chamber
3. look up global methods
If not found, go to superclass
![Page 34: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/34.jpg)
start
Global
1
2
3
4
5
7
8
6
9
![Page 35: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/35.jpg)
Global
Found!
Start
1
![Page 36: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/36.jpg)
Implementation
Based on Ruby 1.9.2
Add one implicit argument to method:
◦ A node of method shelter tree
![Page 37: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/37.jpg)
Optimization: Method Cache
Shelter node cache
◦ Caches method entry in a node of shelter
Extend inline cache
◦ Size of an inline cache : 3 word -> 4word (per method call)
◦ Stores the found shelter node
![Page 38: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/38.jpg)
Performance: empty methods
Call a empty method 10,000,000 times
◦ Less than 5% overhead when shelters are used
![Page 39: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/39.jpg)
Performance: Fibonacci
fib(33) in a method shelter
◦ Up to 20% overhead
![Page 40: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/40.jpg)
Performance: Ruby on Rails
Enabled in an action method
◦ Numeric#/.*bytes?/ methods are in a shelter
In the action
◦ 1. Call one method in shelter
◦ 2. One access to SQLite via ActiveRecord
on WEBRick
Rails3
![Page 41: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/41.jpg)
Performance: Ruby on Rails (result) 4% overhead on production env.
50% on development
◦ Method caches are invalidated per req.production
development
![Page 42: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/42.jpg)
Cache hit ratio on rails
Count shelter’s cache hit
![Page 43: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/43.jpg)
Performance: tDiary 3.0.1
defined String#to_a, String#each, String#method_missing in a shelter
◦ These are used for compatibility of 1.8 & 1.9
Ran on CGI with apache
Method shelter improved performance !!
◦ Why?
![Page 44: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/44.jpg)
Why shelter made tDiary fast
String#method_missing issue
“require” calls its arg’s to_path method if defined
◦ If arg’s method_missing is defined, try to call it
◦ String#method_missing slows “require”
Method shelter restrict its negative effect
![Page 45: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/45.jpg)
Other Usage: protect optimized methods In ruby, + - * / … are optimized
◦ only if they are not redefined
◦ Redefinition slows programs
Method shelters can confine effect of redefinition
Method shelter can improve performance
![Page 46: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/46.jpg)
Other Usage: shelter-private accessor Ruby has no private instance variables
A method shelter can mimic private ivars
◦ by generating unique name
◦ Accessible within the defined shelter
and visible shelters
![Page 47: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/47.jpg)
class Moduledef shelter_accessor(name)define_method name doivname=get_unique_name(name)self.instance_variable_get(ivname)
enddefine_method( (name.to_s+"=").to_sym) do|val|ivname= get_unique_name(name)self.instance_variable_set(ivname,val)
endend
end
![Page 48: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/48.jpg)
Conclusion
Open class is dangerous
Method shelters resolving conflicts
◦ With hidden methods, hiddenly importing
I implemented in Ruby
◦ Not so slow (個人的な感覚)
For more details or the source code,
◦ wait for the acceptance of my paper
Deadline: 2.days.since
![Page 49: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/49.jpg)
Questions?
![Page 50: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/50.jpg)
時間が余ったら
![Page 51: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/51.jpg)
Global
![Page 52: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/52.jpg)
In my lookup algorithm,
◦ Shelter must have up to one parent
For simpler semantics
For efficient implementation
![Page 53: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/53.jpg)
before
A
B
C
![Page 54: Method Shelters : Another Way to Resolve Class Extension Conflicts](https://reader034.vdocuments.mx/reader034/viewer/2022052601/559470f41a28ab8d0e8b4735/html5/thumbnails/54.jpg)
after
A
B
C’’C’