Fermeture (informatique)

Fermeture (informatique)
Page d'aide sur l'homonymie Pour les articles homonymes, voir Fermeture.

Dans un langage de programmation, une fermeture ou clôture (en anglais, closure) est une fonction qui capture des références à des variables libres dans l'environnement lexical[1]. Une fermeture est donc créée, entre autres, lorsqu'une fonction est définie dans le corps d'une autre fonction et fait référence à des arguments ou des variables locales à la fonction dans laquelle elle est définie.

Ce procédé est utilisé notamment pour rassembler les exécutions à saisir sur moins de lignes. Ce principe est par exemple celui de la fonction principale (main) sans laquelle le programme entier ne se déclenche pas, ou bien la base de la programmation orientée objet où les classes prédéfinies ne sont pas utilisées à moins d'être appelées[2]. Il arrive aussi qu'on utilise destructeur au sein d'un programme pour assurer la fermeture avec les lignes précédentes[3].

Une fermeture peut être passée en paramètre d'une fonction dans l'environnement où elle a été créée (passée vers le bas) ou renvoyée comme valeur de retour (passée vers le haut). Dans ce cas, le problème posé alors par la fermeture est qu'elle fait référence à des données qui auraient typiquement été allouées dans la pile, et désallouées à la sortie de l'environnement. Hors optimisations par le compilateur, le problème est généralement résolu par une allocation sur le tas de l'environnement.

Sommaire

Exemple de fermeture

La fonction interne ajoute10 a toujours accès à l'argument nombre, bien que l'appel à la fonction ajouteur soit terminé :

En Python

def ajouteur(nombre) :
  def ajoute(valeur) :
    return valeur + nombre
  return ajoute
 
ajoute10 = ajouteur(10)
ajoute10(1) # retourne 11

En PHP (depuis 5.3)

<?php
function ajouteur($nombre) {
  // On est obligé d'utiliser une fonction anonyme sinon  PHP ne déclare pas 
  // la fonction dans l'environnement actuel mais dans l'environnement global
  return function($valeur) use($nombre) {
    return $valeur + $nombre;
  };
}
 
$ajouter10 = ajouteur(10);
$ajouter10(1); // Retourne 11
?>

Il est important de noter qu'en PHP, une fonction n'a pas accès aux variables de l'environnent où la fonction est déclarée. Pour ce faire il faut utiliser use($nombre) comme ci dessus.

En Javascript

function ajouteur(nombre) {
  function ajoute(valeur) {
    return valeur + nombre;
  }
 
  return ajoute;
}
 
var ajoute10 = ajouteur(10);
ajoute10(1); // retourne 11

En C#

Func<int, int> ajouteur(int nombre)
{
    return valeur => nombre + valeur;
}
 
var ajoute10 = ajouteur(10);
ajoute10(1); // retourne 11

En C++

En C++ le concept de cloture peut être implémenté avec des structures, comme montré ci desous.

#include <iostream>
struct Ajouteur
{
        Ajouteur(int val)
        : val_(val)
        {}
 
        int val_;
 
        int operator () (int rhs)
        {
                return val_ + rhs;
        }
};
 
// version plus simple et infiniement plus efficace
template<int Val_>
struct AjouteurT
{
        int operator () (int rhs)
        {
                return Val_ + rhs;
        }
};
 
int main(void)
{
        Ajouteur ajout10(10);
        std::cout << ajout10(2) << std::endl; // affiche 12 (par calcul)
 
        AjouteurT<5> ajout5;
        std::cout << ajout5(1) << std::endl; // affiche 6 (6 existe dans le code objet car le compilateur a tout précalculé)
        return 0;
}

Les clotures peuvent aussi être implémentées à travers des objets de bibliothèques populaires telles que boost. Par exemple boost::function couplé de boost::bind permet d'implémenter une cloture. Des clotures plus simples peuvent aussi être implémentées à travers boost::lambda.
Le concept de cloture est aussi présent dans la meta-programmation (programmation template), on en trouve beaucoup dans boost::mpl. Ceci s'explique du fait que la programmation en langage template se rapproche du paradigme fonctionnel.
Il convient d'être prudent car par définition une cloture peut faire référence a son environnement direct, ici pour gérer ce modèle il faudrait que la cloture soit consciente de son créateur (passage de reference ou de pointeurs). Cela complique la syntaxe et rend dangereux leur utilisation en fonction de leur durée de vie. Il existe de telles clotures dans boost::signals et libsigc++ qui sont capables de savoir quand leur créateur est supprimé, évitant alors de potentielles violations d'accès.

En Common Lisp

Exemple, en Common Lisp, d'une fonction qui renvoie un prédicat, vrai si son argument est plus grand qu'un certain minimum :

   (defun créer-prédicat-plus-grand-que (min)
     (lambda (x)
       (> x min)))

La fermeture créée dans créer-prédicat-plus-grand-que capture dans son environnement lexical la variable min.

En Ruby

def ajouteur(nombre)
  lambda {|valeur| valeur + nombre}
end
 
ajoute10 = ajouteur(10)
ajoute10.call(1) # retourne 11

En OCaml

Les mêmes fonctions en OCaml :

let ajouteur n =
  let ajoute v = n + v in
  ajoute;;
 
ajoute10 = ajouteur 10;;
ajoute10 1;;

Syntaxe spécifique

Grâce à la curryfication, toute fonction peut générer une fermeture lorsqu'on lui passe seulement une partie de ses arguments :

let ajouteur nombre valeur = nombre + valeur;;
let ajoute10 = ajouteur 10;;
ajoute10 1

Ou encore, étant donné que les opérateurs sont eux-mêmes des fonctions :

let ajoute10 = ( + )  10;;
ajoute10 1

Autres exemples

On peut également donner d'autres exemples :

let creer_predicat_plus_grand_que = function
    seuil -> (fun x ->  x > seuil)

qui donne :

let sup10 = creer_predicat_plus_grand_que 10;;
sup10 12;;   (* true  *)
sup10 8;;    (* false *)

OCaml permet également de capturer dans une fermeture une valeur modifiable en place (mutable). Par exemple, pour créer un compteur, on définit simultanément 3 fonctions :

let raz, inc, compteur = (* remise à zéro, incrémentation, interrogation *)
  let n = ref 0 in
  (function () -> n:=0),        (* raz = remise à zéro  *)
  (function () -> n:= !n + 1),  (* inc = incrémentation *)
  (function () -> !n)           (* compteur = interrogation  *)

la variable mutable n est capturée dans l'environnement commun des 3 fonctions raz, incr et compteur, qui s'utilisent de la sorte :

compteur();;  (* renvoie 0 *)
inc();;       (* incrémente, ne renvoie rien *)
compteur();;  (* renvoie 1 *)
inc();inc();inc();; (* compteur vaut maintenant 4 *)
raz();;
compteur();;  (* renvoie 0 *)
n;;           (* renvoie "Unbound value n" car n est encapsulée *)

en Haskell

Grâce à la curryfication, en Haskell toute fonction peut générer des closures lorsqu'on lui passe seulement une partie de ses arguments :

ajouteur nombre valeur = nombre + valeur
 
ajoute10 = ajouteur 10
x = ajoute10 1

Ou encore, étant donné que les opérateurs sont eux-mêmes des fonctions :

ajoute10 = (10 +)
x = ajoute10 1

en Groovy

En Groovy, une fermeture se débute et se termine par une accolade. La fermeture ajouteur renvoie une fermeture anonyme

def ajouteur = { nombre ->
    return { valeur -> valeur + nombre }
}
def ajoute10 = ajouteur(10)
assert ajoute10(1) == 11
assert ajoute10 instanceof groovy.lang.Closure

En Scala

def ajouteur(n: Int)(x: Int) = (x + n)
 
def ajoute10 = ajouteur(10);

En C, C++, Objective-C 2.0

Le principe de fermeture a été introduit par Apple au travers des blocs qui sont une extension non standard du C disponible sur Mac OS X à partir de la version 10.6 "Snow Leopard" et sur iOS à partir de la version 4.0[4].

#include <stdio.h>
#include <Block.h>
 
typedef int (^AjouteBlock) (int);
 
AjouteBlock ajouteur (int nombre)
{
    return Block_copy( ^ int (int valeur)
    {
        return valeur + nombre;
    });
}
 
int main(void)
{
    AjouteBlock ajoute10 = ajouteur(10);
    printf("%d",ajoute10(1)); // affiche 11
 
    // Release the block
    Block_release(ajoute10);
 
    return 0;
}

En Lua

local ajouteur = function(nombre)
  return function(valeur)
    return valeur + nombre
  end
end
 
local ajoute10 = ajouteur(10)
ajoute10(1) -- retourne 11

Notes et références

  1. Sussman and Steele. "Scheme: An interpreter for extended lambda calculus". "... a data structure containing a lambda expression, and an environment to be used when that lambda expression is applied to arguments." (Wikisource)
  2. http://woufeil.developpez.com/tutoriels/perl/poo/?page=page_5#LV-4
  3. http://www.generationphp.net/cours/programmation-orientee-objet/
  4. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html

Wikimedia Foundation. 2010.

Contenu soumis à la licence CC-BY-SA. Source : Article Fermeture (informatique) de Wikipédia en français (auteurs)

Игры ⚽ Поможем решить контрольную работу

Regardez d'autres dictionnaires:

  • Fermeture (Informatique) — Pour les articles homonymes, voir Fermeture. Dans un langage de programmation, une fermeture ou clôture (en anglais, closure) est une fonction qui capture des références à des variables libres de son environnement lexical qui ne sont pas des… …   Wikipédia en Français

  • Fermeture De Kleene — Pour les articles homonymes, voir Fermeture. La fermeture de Kleene, parfois appelée étoile de Kleene ou encore fermeture itérative, est un opérateur unaire utilisé pour décrire les langages formels. Appliquée à un ensemble V, elle a pour… …   Wikipédia en Français

  • Fermeture de kleene — Pour les articles homonymes, voir Fermeture. La fermeture de Kleene, parfois appelée étoile de Kleene ou encore fermeture itérative, est un opérateur unaire utilisé pour décrire les langages formels. Appliquée à un ensemble V, elle a pour… …   Wikipédia en Français

  • Informatique Légale — On désigne par informatique légale ou investigation numérique légale l application de techniques et de protocoles d investigation numériques respectant les procédures légales et destinée à apporter des preuves numériques à la demande d une… …   Wikipédia en Français

  • Informatique legale — Informatique légale On désigne par informatique légale ou investigation numérique légale l application de techniques et de protocoles d investigation numériques respectant les procédures légales et destinée à apporter des preuves numériques à la… …   Wikipédia en Français

  • Informatique légiste — Informatique légale On désigne par informatique légale ou investigation numérique légale l application de techniques et de protocoles d investigation numériques respectant les procédures légales et destinée à apporter des preuves numériques à la… …   Wikipédia en Français

  • Fermeture de Kleene — Pour les articles homonymes, voir Fermeture. La fermeture de Kleene, parfois appelée étoile de Kleene ou encore fermeture itérative, est un opérateur unaire utilisé pour décrire les langages formels. Le nom vient de la notation employée: la… …   Wikipédia en Français

  • Fermeture — Cette page d’homonymie répertorie les différents sujets et articles partageant un même nom. Sur les autres projets Wikimedia : « Fermeture », sur le Wiktionnaire (dictionnaire universel) Le terme fermeture renvoie à :… …   Wikipédia en Français

  • Informatique légale — On désigne par informatique légale ou investigation numérique légale l application de techniques et de protocoles d investigation numériques respectant les procédures légales et destinée à apporter des preuves numériques à la demande d une… …   Wikipédia en Français

  • Criminalistique informatique — Informatique légale On désigne par informatique légale ou investigation numérique légale l application de techniques et de protocoles d investigation numériques respectant les procédures légales et destinée à apporter des preuves numériques à la… …   Wikipédia en Français

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”