«

»

Jul
24

Blocks are Proc : Les procédures Proc et les blocks en ruby.

( For non-french readers : I am not giving up writing in english … Read the next post! )

Si vous venez d’un autre langage, le terme procédure (associé au terme fonction) doit vous dire quelque chose. Vaguement ….

Allez quelques connaissances (méconnaissances) tirées de ma mémoire pour poser les bases.

Par exemple, en PHP il existe deux types de fonctions. Les fonctions natives (built-in) et les fonctions “codées” par l’utilisateur.
Ces dernières se séparent en deux types : les fonctions et les procédures.

La différence entre les deux ? Une procédure est un groupe d’instructions qui ne renvoie pas de valeur. Une fonction est une procédure qui renvoie une valeur.

Et ruby dans tout ça ??

C’est complètement différent et je dirai même plus les procédures Ruby sont très éloignés des procédures PHP. En ruby il n’y a que des objets (les méthodes sont des objets) et les méthodes renvoient toujours une valeur.
Vous avez déjà vu ou même codé des choses comme ceci :

[1,2,3,4,5,6].each do |nb|
  # Un code quelconque : des instructions ...
end

C’ette méthode est native à Enumerable (module que la classe Array inclut)
La méthode Array#each prend 0 paramètre mais un block. Le block est tout ce qui se trouve entre do et end.
On pourrait le représenter en Ruby comme ceci :

def each(&block)
  # Un truc compliqué à écrire en ruby
end

Ne vous y trompez pas “&block” n’est pas un argument. C’est la notation ruby pour dire que la méthode each s’accompagne obligatoirement d’un block.

Autre exemple :

class Bar
 
  def my_proc(&procedure)
     @foo_proc = procedure
  end
 
  def recall
    @foo_proc.call
  end
end
 
bar = Bar.new
bar.my_proc do
# Pas de code
end
 #=> #<Proc:0x00000>

Il se trouve que la procédure est une instance de la classe Proc.
Sans trop de surprise mêmes les procédures sont des objets. Et oui, en ruby tout est objet.

Quel est l’intérêt me direz-vous?

Cela change tout !!! En PHP les prcoédures sont codées en dur, en ruby on peut générer à la volée des suites d’instructions sans pour autant avoir à implémenter une méthode !!!

Illustration :

On sait que les blocks sont des instances de la classe Proc. La solution est facile, il suffit de créer des instances de Proc et les passer comme blocks d’une méthode acceptant un block.

p1 = Proc.new do
 puts "Je suis p1"
end
 
p2 = Proc.new do
  puts "Je suis p2"
end
 
bar = Bar.new
bar.my_proc(&p1)
# Je suis p1
#=> nil
bar.foo_proc 
#=> #<Proc:0x164564ab>
 
bar.recall
# Je suis p1
#=> nil
 
bar.my_proc(&p2)
# Je suis p2
#=> #<Proc:0x054ecdab>
 
bar.recall
# Je suis p2
#=> nil
 
bar2 = Bar.new
bar2.my_proc(&p2)
# Je suis p2
#=> #<Proc:0x054ecdab>
 
bar2.instance_eval("@foo_proc") == bar.instance_eval("@foo_proc") 
#=> true

Vous avez compris l’intérêt? Les blocks sont bien des suites d’instructions mais plus que cela, ce sont des objets !!! L’illustration précédente montre qu’on peut partager des suites d’instructions entre différents objets, générer ces instructions dynamiquement !

En route pour la méta-programmation avec Ruby !!!

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">