Your SlideShare is downloading. ×
0
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Classboxes, nested methods, and real private methods
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Classboxes, nested methods, and real private methods

6,736

Published on

0 Comments
16 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
6,736
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
67
Comments
0
Likes
16
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Classboxes, nested methods, and real private methods Shugo Maeda 2010-11-12
  • 2. Self introduction Shugo Maeda A Ruby committer A director of Network Applied Communication Laboratory Ltd. (NaCl) The co-chairperson of the Ruby Association 01 77
  • 3. Where am I from? Matsue, Shimane, Japan A sister city of New Orleans 02 77
  • 4. We are different 03 77
  • 5. Please accept us 04 77
  • 6. Topics were supposed to be: classboxes, nested methods, and real private methods But... 05 77
  • 7. Topic A new feature "Refinements" 06 77
  • 8. What are Classboxes? A way to extend classes 07 77
  • 9. How to extend classes in Ruby? Subclassing Mix-in Singleton methods Open classes 08 77
  • 10. Subclassing class Person attr_accessor :name end class Employee < Person attr_accessor :monthly_salary end 09 77
  • 11. Aspects of subclassing Normal single inheritance Subclassing affects only instances of the subclasses Implementation-only inheritance Violations of LSP 10 77
  • 12. LSP Liskov Substitution Principle An instance of a subtype must behave like an instance of the supertype of the subtype An instance of the supertype can be substituted with an instance of the subtype 11 77
  • 13. An example of LSP def print_name(person) puts person.name end shugo = Person.new shugo.name = "Shugo Maeda" print_name(shugo) #=> Shugo Maeda matz = Employee.new matz.name = "Yukihiro Matsumoto" print_name(matz) #=> Yukihiro Matsumoto 12 77
  • 14. A typical LSP violation class Rectangle attr_accessor :width, :height end class Square < Rectangle def set_size(x) @height = @width = x end alias width= set_size alias height= set_size end def set_size(rect) rect.width = 80; rect.height = 60 end square = Square.new set_size(square) p square.width #=> not 80, but 60! 13 77
  • 15. A Ruby-specific LSP violation class Employee < Person undef name end def print_name(person) puts person.name end matz = Employee.new matz.name = "Yukihiro Matsumoto" print_name(matz) #=> undefined method `name'... 14 77
  • 16. Subclassing != Subtyping Implementation-only inheritance Duck typing 15 77
  • 17. Mix-in class; Stream; ... end module Readable; ... end module Writable; ... end class ReadStream < Stream include Readable end class WriteStream < Stream include Writable end class ReadWriteStream include Writable, Readable end 16 77
  • 18. Aspects of mix-in Limited multiple inheritance Only modules can be multiply inherited A module has no instances Modules are also used as namespaces for constants 17 77
  • 19. Singleton methods matz = Person.new def matz.design_ruby ... end matz.design_ruby shugo = Person.new shugo.design_ruby #=> NoMethodError 18 77
  • 20. Aspects of singleton methods Clients of a class can extend the behavior of an instance of the class A singleton method defines the behavior of only one particular instance Some objects cannot have singleton methods e.g., instances of Integer 19 77
  • 21. Open classes # reopen Person, and add code class Person attr_accessor :age end shugo = Person.new shugo.name = "Shugo Maeda" shugo.age = 34 20 77
  • 22. Aspects of open classes Clients of a class can extend the behavior of instances of the class Classes are extended globally 21 77
  • 23. Applications of open classes Ruby on Rails jcode / mathn 22 77
  • 24. Ruby on Rails A good example of monky patching 23 77
  • 25. Jealous of DHH not for... 24 77
  • 26. But for ActiveSupport DHH can extend Ruby without permissions from Matz # This doesn't work on plain Ruby! puts 3.days.ago 25 77
  • 27. Rails Plugins Plugins extend framework classes by monky patching Using alias to call original methods alias_method_chain 26 77
  • 28. jcode / mathn jcode Adds and refines methods of String for Japanese character handling mathn Provides mathematically natural operations on numbers Bad examples of monkey patching 27 77
  • 29. LSP and open classes s/subtype/class after reopen/g s/supertype/class before reopen/g Instances of a class after a reopen must behave like instances of the class before the reopen 28 77
  • 30. an LSP violation p 1 / 2 #=> 0 require "mathn" p 1 / 2 #=> (1/2) 29 77
  • 31. Summary Subclassing not by clients Mix-in not by clients Singleton methods per object Open classes global 30 77
  • 32. Extensibility and Modularity Subclassing, mix-in, and singleton methods are less extensible Open classes are less modular 31 77
  • 33. What we need Class extensions by clients per class local 32 77
  • 34. Possible solutions selector namespace Classboxes 33 77
  • 35. selector namespace Implemented in SmallScript and ECMAScript 4 A namespace of method names (selectors) A namespace can be imported into other namespaces Lexically scoped 34 77
  • 36. Classboxes Implemented in Squeak and Java A classbox is a module where classes are defined and/or extended A classbox can be imported into other classboxes Dynamically scoped called local rebinding 35 77
  • 37. An example of Classbox/J package Foo; public class Foo { ... } package Bar; import Foo; refine Foo { public void bar() { ... } } package Baz; import Bar; public class Baz { public static void main(String[] args) { new Foo().bar(); } } 36 77
  • 38. An example of local rebinding package Foo; public class Foo { public void bar() { System.out.println("original"); } public void call_bar() { bar(); } } package Bar; import Foo; refine Foo { public void bar() { System.out.println("refined"); } } package Baz; import Bar; public class Baz { public static void main(String[] args) { new Foo().call_bar(); } } 37 77
  • 39. Is local rebinding needed? Local rebinding is less modular Callees might expect the original behavior Learn from the history of local variable scoping Singleton methods and open classes can be alternatives However, effective scopes are different 38 77
  • 40. Refinements A newly implemented feature of Ruby Not merged into the official Ruby repository Refinements of classes are defined per module Effective scopes are explicitly specified no local rebinding Classbox/J like syntax 39 77
  • 41. An example of Refinements module MathN refine Fixnum do def /(other) quo(other) end end end class Foo using MathN def bar p 1 / 2 #=> (1/2) end end p 1 / 2 #=> 0 40 77
  • 42. Demo 41 77
  • 43. Module#refine refine(klass, &block) Additional or overriding methods of klass are defined in block a set of such methods is called a refinement Activated only in the receiver module, and scopes where the module is imported by using refine can also be invoked on classes 42 77
  • 44. Class local refinements class Foo refine Fixnum do def /(other) quo(other) end end def bar p 1 / 2 #=> (1/2) end end p 1 / 2 #=> 0 43 77
  • 45. Kernel#using using(mod) using imports refinements defined in mod Refinements are activated only in a file, module, class, or method where using is invoked lexically scoped 44 77
  • 46. An example of using using A # A is activated in this file module Foo using B # B is activated in Foo (including Foo::Bar) class Bar using C # C is activated in Foo::Bar def baz using D # D is activated in this method end end end 45 77
  • 47. Module#using using(mod) Module#using overrides Kernel#using The basic behavior is the same as Kernel#using Besides, Module#using supports reopen and inheritance 46 77
  • 48. An example of Module#using module A; refine(X) { ... } end module B; refine(X) { ... } end class Foo; using A end class Foo # A is activated in a reopened definition of Foo end module Bar using B class Baz < Foo # A is activated in a subclass Baz of Foo # A has higher precedence than B end end 47 77
  • 49. using and include module A; refine(X) { ... } end module Foo; using A end class Bar include Foo # include does not activate A end 48 77
  • 50. Precedence of refinements Refinements imported in subclasses have higher precedence Later imported refinements have higher precedence Refinements imported in the current class or its superclasses have higher precedence than refinements imported in outer scopes If a refined class has a subclass, methods in the subclass have higher precedence than those in the refinement 49 77
  • 51. An example of precedence class Foo; end module Bar; refine Foo do end end module Baz; refine Foo do end end class Quux < Foo; end class Quuux using Bar end module Quuuux using Baz class Quuuuux < Quuux def foo # Quux -> Bar -> Baz -> Foo Quux.new.do_something end end end 50 77
  • 52. Using original features super in a refined method invokes the original method, if any If there is a method with the same name in a previously imported refinements, super invokes the method In a refined method, constants and class variables in the original class is also accessible 51 77
  • 53. An example of super module FloorExtension refine Float do def floor(d=nil) if d x = 10 ** d return (self * x).floor.to_f / x else return super() end end end end using FloorExtension p 1.234567890.floor #=> 1 p 1.234567890.floor(4) #=> 1.2345 52 77
  • 54. special eval Refinements are also activated in instance_eval, module_eval, and class_eval 53 77
  • 55. An example of special eval class Foo using MathN end Foo.class_eval do p 1 / 2 #=> (1/2) end Foo.new.instance_eval do p 1 / 2 #=> (1/2) end 54 77
  • 56. Compatibility No syntax extensions No new keywords The behavior of code without refinements never change However, if existing code has a method named refine or using, it may cause some problems 55 77
  • 57. Applications of refinements Refinements of built-in classes Internal DSLs Nested methods 56 77
  • 58. Refinements of built-in classes Refinements are activated in particular scopes So you can violate LSP like MathN Refinement inheritance is useful for frameworks 57 77
  • 59. Example class ApplicationController < ActionController::Base using ActiveSupport::All protect_from_forgery end class ArticlesController < ApplicationController def index @articles = Article.where("created_at > ?", 3.days.ago) end end 58 77
  • 60. Internal DSLs Methods for DSLs need not be available outside DSLs So these methods can be defined in refinements instance_eval and module_eval are useful for DSLs 59 77
  • 61. Example module Expectations refine Object do def should ... end ... end end def it(msg, &block) Expectations.module_eval(&block) end it "returns 0 for all gutter game" do bowling = Bowling.new 20.times { bowling.hit(0) } bowling.score.should == 0 end 60 77
  • 62. Nested methods def fact(n) # fact_iter is defined in refinements # available only in fact def fact_iter(product, counter, max_count) if counter > max_count product else fact_iter(counter * product, counter + 1, max_count) end end fact_iter(1, 1, n) end 61 77
  • 63. Benchmark make benchmark (5 times) Environment CPU: Intel Core 2 Duo U7600 1.2GHz RAM: 2GB OS: Linux 2.6.34 (Ubuntu 10.04) 62 77
  • 64. Additional benchmarks For refinements bm_ref_factorial.rb bm_ref_fib.rb For nested methods bm_ref_factorial2.rb 63 77
  • 65. bm_ref_factorial.rb if defined?(using) module Fact refine Integer do def fact ... end end end using Fact else class Integer def fact ... end end end 64 77
  • 66. Benchmark result Average 2.5% slower than the original Ruby 65 77
  • 67. Samples 66 77
  • 68. Considerations Should include and using be integrated? Should singleton methods be refinable? Should modules be refinable? Implementation improvement 67 77
  • 69. Should include and using be integrated? Currently they are independent module Foo refine Bar { ... } ... end module Baz # Both include and using are needed # to use mix-in and refinements at the same time include Foo using Foo end 68 77
  • 70. Workaround module Foo refine Bar { ... } def used(klass) klass.send(:include, self) end end module Baz # using invokes used as a hook using Foo end 69 77
  • 71. Should singleton methods be refinable? Currently singleton methods cannot be refined module Foo # This doesn't work refine Bar do def self.foo end end end 70 77
  • 72. Workaround module Foo # This works refine Bar.singleton_class do def foo end end end 71 77
  • 73. Should modules be refinable? Currently the argument of refine should be a class module Foo end module Bar # This doesn't work refine Foo { ... } end 72 77
  • 74. Workaround You can refine a class which includes the module module Foo end class Quux include Foo end module Bar # This works refine Quux { ... } end 73 77
  • 75. Implementation improvement It's not my work ko1 will do it 74 77
  • 76. Patch http://shugo.net/tmp/refinement- r29498-20101109.diff 75 77
  • 77. Conclusion Refinements achieve a good balance between extensibility and modularity 76 77
  • 78. Thank you Any questions? 77 77

×