Method Shelters : Another Way to Resolve Class Extension Conflicts

54
Method Shelters : Another Way to Resolve Class Extension Conflicts Classboxes でも Refinements でもない別のやり方 Shumpei Akai / 赤井駿平 @flexfrank

description

A presentation on Rubykaigi11

Transcript of Method Shelters : Another Way to Resolve Class Extension Conflicts

Page 1: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

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

% 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

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

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

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

Or Monkey Patching

Page 8: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

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

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

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

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

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

Classboxes

You might have known via matz’s diary

Page 15: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

Classboxes

Cited from “Classbox/J: Controlling the Scope of Change in Java”

Page 17: Method Shelters : Another Way to Resolve Class Extension Conflicts

The Problem in Classboxes

Importing overwrites internally used classes

◦ Importing causes another conflict

Page 18: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

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

Method Shelters

Page 21: Method Shelters : Another Way to Resolve Class Extension Conflicts

Key concept

Hide your methods

Hide your imports

Page 22: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

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

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

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

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

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

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

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

Syntax: Import

shelter :ShelterName doimport :AnotherShelterName

end

Page 31: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

Evaluate

Evaluate within a shelter

shelter_eval :ShelterName do#shelter is enabled

end

Page 33: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

start

Global

1

2

3

4

5

7

8

6

9

Page 35: Method Shelters : Another Way to Resolve Class Extension Conflicts

Global

Found!

Start

1

Page 36: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

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

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

Performance: Fibonacci

fib(33) in a method shelter

◦ Up to 20% overhead

Page 40: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

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

Cache hit ratio on rails

Count shelter’s cache hit

Page 43: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

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

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

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

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

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

Questions?

Page 50: Method Shelters : Another Way to Resolve Class Extension Conflicts

時間が余ったら

Page 51: Method Shelters : Another Way to Resolve Class Extension Conflicts

Global

Page 52: Method Shelters : Another Way to Resolve Class Extension Conflicts

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

before

A

B

C

Page 54: Method Shelters : Another Way to Resolve Class Extension Conflicts

after

A

B

C’’C’