Quelle est la différence entre une «fermeture» et un «bloc»?

J’ai constaté que beaucoup de gens utilisent les mots « fermer» et « bloquer» de manière interchangeable. La plupart de ces personnes ne peuvent pas expliquer de quoi elles parlent.

Certains programmeurs Java (même ceux de consultants très coûteux) parlent de classes internes anonymes comme “blocs” et “fermetures” – mais je sais que ce n’est pas vrai. (Vous ne pouvez pas transmettre de variables mutables depuis la scope de la méthode dans laquelle elles sont définies …)

Je cherche:

  • une définition informatique précise d’un bloc
  • une définition informatique précise d’une fermeture
  • et des éclaircissements sur la différence entre les deux.

J’aimerais vraiment voir des liens, des articles ou des références de livres sur ceux-ci s’il vous plaît .

Alors qu’un bloc est juste un morceau de code qui peut être composé par des déclarations et des déclarations mais rien d’autre, une fermeture est un véritable object de première classe, une variable réelle qui a pour valeur un bloc.

La principale différence est qu’un bloc regroupe simplement les instructions (par exemple le corps d’une instruction while ), tandis qu’une fermeture est une variable qui contient du code pouvant être exécuté.

Si vous avez une fermeture en général, vous pouvez la passer en paramètre pour les fonctions, la currifier et la décurrifier, et surtout l’appeler!

 Closure c = { println 'Hello!' } /* now you have an object that contains code */ c.call() 

Bien sûr, les fermetures sont plus puissantes, elles sont des variables et peuvent être utilisées pour définir un comportement personnalisé des objects (alors que généralement vous deviez utiliser des interfaces ou d’autres approches de la POO dans la programmation).

Vous pouvez penser à une fermeture comme une fonction contenant ce que cette fonction fait à l’intérieur d’elle-même.

Les blocs sont utiles car ils permettent de déterminer la scope des variables. Généralement, lorsque vous définissez une variable dans une étendue, vous pouvez remplacer les définitions externes sans aucun problème et de nouvelles définitions existeront juste pendant l’exécution du bloc.

 for (int i = 0; i < 10; ++i) { int t = i*2; printf("%d\r\n", t); } 

t est défini à l'intérieur du bloc (le corps de l'instruction for ) et durera juste à l'intérieur de ce bloc.

Un bloc est quelque chose de syntaxique – Une unité logique d’instructions (plus liée à la scope qu’à la fermeture ).

 if (Condition) { // Block here } else { // Another block } 

Une fermeture est liée à des fonctions ou à des classes anormales – Un object anonyme (fonction), un morceau de code lié à un environnement (avec ses variables).

 def foo() { var x = 0 return () => { x += 1; return x } } 

Ici, foo renvoie une fermeture! La variable locale x persiste à travers la fermeture même après la fin de foo et peut être incrémentée par des appels de la fonction anonyme retournée.

 val counter = foo() print counter() // Returns 2 print counter() // Return 3 

Notez que Ruby est un bloc dans lequel les blocs et les fermetures sont traités de la même façon, car ce que Ruby appelle le bloc est une fermeture:

 (1..10).each do |x| px end 

Là, each méthode reçoit une fonction de fermeture (prenant un paramètre x) appelé bloc dans Ruby.

Il y a beaucoup de confusion ici, car il y a des termes avec plusieurs définitions et plusieurs éléments distincts qui sont confondus simplement parce qu’ils se trouvent généralement ensemble.

Tout d’abord, nous avons “bloc”. C’est juste un morceau lexical de code qui fait une unité – le corps d’une boucle, par exemple. Si le langage a réellement une scope de bloc, des variables peuvent être définies qui n’existent que dans ce morceau de code.

Deuxièmement, nous avons du code appelable comme type de valeur. Dans les langages fonctionnels, ce sont des valeurs de fonction – parfois appelées “funs”, “fonctions anonymes” (parce que la fonction est trouvée dans la valeur, pas le nom auquel elle est assignée; vous n’avez pas besoin de nom pour les appeler) lambdas “(de l’opérateur utilisé pour les créer dans Lambda Calculus d’Eglise). Ils peuvent être appelés “fermetures”, mais ils ne sont pas automatiquement de véritables fermetures; pour se qualifier, ils doivent encapsuler (“close over”) la scope lexicale entourant leur création – c’est-à-dire que les variables définies en dehors de la scope de la fonction mais dans le cadre de sa définition sont toujours disponibles si le point appelant se trouve après la variable référencée aurait autrement été hors de scope et son stockage a été recyclé.

Par exemple, considérez ce Javascript:

 function makeClosure() { var x = "Remember me!"; return function() { return "x='" + x + "'"; } } // console.log(x); // The above is an error; x is undefined var f = makeClosure(); console.log(f()); // The above outputs a ssortingng that includes x as it existed when f was created. 

Le plus fort et barbu dit ceci à propos des fermetures et des blocs:

http://martinfowler.com/bliki/Closure.html

À un moment donné, il dit qu’une fermeture est un bloc qui peut être transmis comme argument à une méthode.

Les termes que vous utilisez sont généralement utilisés ensemble ces jours-ci dans Ruby, bien que les constructions apparaissaient auparavant dans Algol, Smalltalk et Scheme. Je citerais le standard Ruby, s’il y en avait un.

Je ne suis pas sûr de pouvoir répondre à votre question exacte, mais je peux illustrer. Mes excuses si vous le savez déjà …

 def f &x yield x end def g y = "block" t = f { p "I'm a #{y}" } y = "closure" t end t = g t.call 

Et…

 $ ruby exam.rb "I'm a block" "I'm a closure" $ 

Ainsi, un bloc est une séquence de code de type fonction anonyme attachée à un appel de méthode. Il est utilisé partout dans l’API Ruby. Lorsque vous facilitez la création d’une fonction anonyme, il s’avère qu’elles sont utiles pour toutes sortes de choses.

Mais notez qu’après que f retourne, alors g retourne, nous nous sums accrochés au bloc en le renvoyant de f (comme x ) et ensuite de g (comme t ). Maintenant, nous appelons le bloc une deuxième fois. Encore une fois, notez que g() a été renvoyé. Mais le bloc fait référence à une variable locale dans une instance de fonction (et une étendue) qui n’existe plus?! Et la nouvelle valeur de y ?

Une fermeture est donc un object de type fonction qui est fermé sur son étendue lexicale. Ils sont très difficiles à implémenter car ils détruisent le modèle do-it-with-a-stack, si utile pour les variables locales dans les instances d’appel de fonctions.


1. Ruby a diverses saveurs d’objects fonctionnels de type fermeture; C’est juste l’un d’eux.

5

C’est un entier .

Int workDaysInAWeek = 5

C’est une variable entière et il peut être défini sur un entier différent. (Si les circonstances vous empêchent de modifier cette valeur, cela peut être appelé une constante .)

Alors que les chiffres ci-dessus concernent les nombres, les blocs et les fermetures concernent les algorithmes. La distinction entre les blocs et les fermetures , respectivement, est également équivalente à ce qui précède.