ruby object model at the ruby drink-up of sophia, january 2013
Post on 19-Jan-2015
258 Views
Preview:
DESCRIPTION
TRANSCRIPT
An introduction to Ruby's object model
Riviera.rb – 08/01/2013
Nicolas Bondoux
Overview● Introduction to module and classes
● Singleton class; case of meta-classes
● Tools for meta-programming
● Using modules for extending objects: mixins
A simple class● A class definition
contains
– Instance methods
– Constants
– Class variables● Instance variables are
prefixed by @; they are manipulated through instance methods
class LinkedElement #constructor def initialize(content,link) @content = content @link = link end
# setter def content=(content) @content = content end
#getter def content return @content end
# automatic generation setter/getter: attr_accessor :linkend
Class instances
● A class be instantiated using #new (class method)
● Instance variables live within the instance, but are not directly accessible → need of getter and setters
irb(main):192:0> a = LinkedElement.new("a", nil)=> #<LinkedElement:0x00000001b63b58 @content="a", @link=nil>
irb(main):193:0> b = LinkedElement.new("b",a)=> #<LinkedElement:0x00000001b5daf0 @content="b", @link=#<LinkedElement:0x00000001b63b58 @content="a", @link=nil>>
irb(main):194:0> b.link()=> #<LinkedElement:0x00000001b63b58 @content="a", @link=nil>
irb(main):195:0> b.@linkSyntaxError: (irb):195: syntax error, unexpected tIVAR
from /usr/bin/irb:12:in `<main>'
irb(main):196:0> b.content=> "b"
b.instance_variables=> [:@content, :@link]
Objects' equality
● Objects comparison:
– == → true if the content of two objects
– .eql? → true if == and class of the two objects;● Used alongside with .hash for hash maps
– .equal? : true if the same instance on both sides● == and .eql? Must be provided by class implementation
Classes inheritanceclass Toto def myNameIs return "My Name Is #{name}." end def name "Toto" endend
class Titi < Toto def name "Titi" endend
irb(main):027:0* Toto.new.myNameIs=> "My Name Is Toto."irb(main):028:0> Titi.new.myNameIs=> "My Name Is Titi."
irb(main):030:0* t = Titi.new=> #<Titi:0x00000001d376c8>irb(main):035:0> t.class=> Titiirb(main):036:0> t.class.superclass=> Totoirb(main):037:0> t.is_a? Titi=> trueirb(main):038:0> t.is_a? Toto=> trueirb(main):039:0> Toto === t=> trueirb(main):040:0> Toto.superclass=> Object
Self● “self” keyword represents the instance in which the code is
executed
– inside a method definition , the instance on which method is defined
– Inside class/module definition: the class/module being defined
class TestSelf puts self def f return self endend# display TestSelf
t = TestSelf.newt.f.equal? t=> true
Class methods and variables
● Class are objects: class methods are their instance methods!
● Class variables are prefixed with @@
● Ruby magic: class variables from parent classes are accessible to child classes
● Class variables are accessible anywhere in class definition
class TestClassMethod #class variable @@a=0 #class method def self.counter @@a=0 end #instance method def putsSelf puts self @@a+=1 endend
Classes methods: exampleclass LinkedElement class LinkedElementEnd end #class variable @@end = LinkedElementEnd.new
#example of constant End = @@end #class method
def self.end @@end endend
irb(main):015:0* LinkedElement.end().equal? LinkedElement::End=> trueirb(main):016:0> LinkedElement.class_variables=> [:@@end]
irb(main):069:0> a= LinkedElement.new("a", LinkedElement.end)=> #<LinkedElement:0x00000001931df8 @content="a", @link=#<LinkedElement::LinkedElementEnd:0x0000000152e8c8>>
irb(main):070:0> b=LinkedElement.new("b",a)=> #<LinkedElement:0x0000000192a8c8 @content="b", @link=#<LinkedElement:0x00000001931df8 @content="a", @link=#<LinkedElement::LinkedElementEnd:0x0000000152e8c8>>>
Adding methods to a class● Class definition can be extended anytime
● Let's add a size method to our linked list:
class LinkedElement def size @link.size + 1 end class LinkedElementEnd def size 0 end endend
irb(main):081:0> a.size=> 1irb(main):082:0> b.size=> 2
Structs● Struct.new allow to dynamically create Classes, with getter
and setters
● Instance of struct have, among others .eql?, .equal?, .hash methods defined !
● Very useful to quickly define records, keys …
● Structs can then be inherited from/extended like any classes
irb(main):008:0> MyClass = Struct.new(:a,:b, :c)=> MyClassirb(main):009:0> m = MyClass.new(1,10)=> m = MyClass.new(1,10)
irb(main):011:0> m.a=2=> 2
irb(main):013:0> m.to_a=> [2, 10, nil]
Modules● Module is a parent type of Class;
– A module is an instance of Module● Modules are like classes, except that
– They cannot be instantiated
– No inheritance: they cannot have parent or child● Still, they are objects:
– They have instance variables, (class) methods● And they also have
– class variables
– and instance methods → used for the mixins● Modules are useful for namespaces
Modules (2)module M1 #constant: C=1
def self.f "f1; self is #{self}" endend
module M2 def self.f "f2; self is #{self}" endend
irb(main):026:0* M1.f=> "f1; self is M1"irb(main):028:0* M2.f=> "f2; self is M2"irb(main):033:0> M1::C=> 1
A very simplified diagram
Instance MyClass Class
Object
MyParentClass Module MyModule
.class .superclass
Extending instances:● We have already seen that class methods of a class A are
instance methods specific to the object A
– It is possible to add methods to instances!
● Where is stored “mult” Method ? In the Singleton class !
a="5"
def a.mult(x) "#{self.to_i*x}"znd
irb(main):096:0* a.mult(10)=> "50"
irb(main):103:0> a.singleton_class=> #<Class:#<String:0x000000018ec7a8>>irb(main):104:0> a.singleton_class.ancestors=> [String, Comparable, Object, Kernel, BasicObject]irb(main):105:0> a.singleton_class.superclass=> String
What are singleton classes ?● One instance has its own singleton
● Those are anonymous and invisible classes, inserted at the bottom of the class hierarchy
● They are used to hold methods that are specific to an instance
a (a)singleton_class
Object
Stringclass
Singleton classes of classes: meta-classes
● Meta-classes: the singleton classes of methods
– This is where class methods are stored!● Meta-classes magic:
– when looking for a class methods ruby search in the meta-classes of all the inheritance chain!
– This is because meta-classes inheritance scheme is parallel to class inheritance scheme
Meta-classes: a diagram
Instance
MyClass
Object
MyParentClass
.singleton_class .superclass
(MyClass)
(MyParentClass)
Class
(Instance)
Extending the singleton classesclass Toto #instance method of Toto def f end
#class method of Toto def self.g endend
#class method of Totodef Toto.gend
# > def x.g .... > add an instance method to the singleton class of x !
# Singleton class can also be accessed explicitlyclass << Toto def h return self endend
class Toto class << self def i1 end def i2 end endend# i1 and i2 are class methods of Toto !!!
instance_eval/instance_exec● instance_eval allow to execute code in the context of an
instance;
– Ruby magic: self represents the instance, but methods are added to the singleton class!
class TestInstanceEval def initialize @a=5 endendb=5
irb(main):189:0> t.instance_eval "@a"=> 5irb(main):190:0* t.instance_eval "def f; puts @a+#{b};end"=> nilirb(main):191:0> t.f10
Mixins● Mixins are a way to add properties to an object
● They are modules referenced by classes
● Instance methods of the module becomes available to instances of the class
● Include: the module becomes an included module of the Class
– the instance methods of an module become instance methods of the Class → used to extend classes
● Extend: the module becomes an included module of the singleton of the class → allow to extends objects, add class methods to classes ...
Mixins: examplesmodule AppendModule def append(x) return LinkedElement.new(x,self) endend
#add append method to LinkedElement and LinkedElementEnd
class LinkedElement #add append as instance method of LinkedElement include AppendModule class LinkedElementEnd include AppendModule endend
irb(main):268:0> l = LinkedElement::End.append("z").append("y").append("x")=> #<LinkedElement:0x00000001d18138 @content="x", @link=#<LinkedElement:0x00000001d18188 @content="y", @link=#<LinkedElement:0x00000001d181d8 @content="z", @link=#<LinkedElement::LinkedElementEnd:0x00000001f04f78>>>>
irb(main):269:0> l.size=> 3
irb(main):270:0> LinkedElement.included_modules=> [AppendModule, Kernel]
Any questions?
top related