42

He encontrado que muchas personas usan las palabras cierre y bloque de manera intercambiable. La mayoría de estas personas no pueden explicar de qué están hablando.Exactamente ¿cuál es la diferencia entre un "cierre" y un "bloque"?

Algunos programadores de Java (incluso los de consultorías realmente caras) hablan de clases internas anónimas como "bloques" y "cierres", pero sé que esto no es cierto. (No se puede pasar variables mutables en del ámbito de aplicación del método en el que están definidas ...)

Busco:

  • una manera precisa, la informática definición de una bloquear
  • una, la informática definición precisa de un cierre
  • y aclaraciones sobre la diferencia entre los dos.

realmente me gustaría ver links, artículos o libros referencias sobre estos por favor.

+0

No estoy seguro de que tengan definiciones precisas, por ejemplo, los cierres que Apple agregó a gcc se llaman "bloques" – cobbal

+0

Si estás hablando de [] 's - llegaron a Objective-C desde Smalltalk, donde están compilado en una instancia del denominado 'BlockClosure'. – daf

+2

No está hablando de Objective-C, está hablando de las extensiones de Apple a C. En OSX 10.6 Snow Leopard, Appel presentó una nueva biblioteca de concurrencia llamada Grand Central Dispatch. Es una biblioteca basada en tareas algo similar a la Biblioteca paralela de tareas de Microsoft. La idea básica de GCD es que entregue un bloque de código a la biblioteca y luego la biblioteca decida cuándo y qué núcleo ejecutar. Normalmente, harías eso con punteros a funciones, pero Apple lo consideró demasiado feo y extendieron C con expresiones esencialmente lambda, que llaman bloques. –

Respuesta

27

Mientras que un bloquees sólo un pedazo de código que puede estar compuesto por las declaraciones y declaraciones, pero nada más, un cierrees un objeto de primera clase real, una variable real que tiene un bloque como su valor.

La diferencia principal es que un bloque simplemente agrupa las instrucciones juntas (por ejemplo, el cuerpo de una declaración mientras que), mientras que un cierre es una variable que contiene algún código que se puede ejecutar.

Si tiene un cierre, por lo general, puede pasarlo como un parámetro para funciones, currificarlo y desurrificarlo, ¡y principalmente llamarlo!

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

de los cierres del curso son más poderosos, que son variables y pueden ser utilizados para definir un comportamiento personalizado de objetos (por lo general, mientras que se tenía que utilizar las interfaces u otros enfoques programación orientada a objetos en la programación).

Puede pensar en un cierre como una función que contiene lo que hace esa función en su interior.

Los bloques son útiles porque permiten determinar el alcance de las variables. Por lo general, cuando define una variable dentro de un ámbito, puede anular las definiciones externas sin ningún problema y existirán nuevas definiciones solo durante la ejecución del bloque.

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

t se define dentro del bloque (el cuerpo de la declaración for) y durará justo dentro de ese bloque.

+0

un bloque también marca el comienzo y fin de un "ámbito de objeto". – jldupont

+0

tiene razón, se olvidó de mencionar que .. acaba de actualizar – Jack

+0

El ejemplo for-loop no vuela genéricamente, ya que "cierre" es verbosidad utilizada con Javascript más que con otros idiomas y para bloques de bucle no encapsula sus variables en absoluto excepto * solo * con declaraciones de funciones. Sospecho que tu ejemplo es Java? Por favor especifica. –

16

Un bloque es algo sintáctico - Una unidad lógica de los enunciados (más relacionado con el alcance que al cierre ).

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

Un cierre está relacionado con funciones Anoymous o clases - un objeto anónimo (función), una pieza de código que está enlazado a un entorno (con sus variables).

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

Aquí foo devuelve un cierre! La variable local x persiste a través del cierre incluso después de que finalizó el foo y puede incrementarse mediante llamadas de la función anónima devuelta.

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

Tenga en cuenta que es sólo de Ruby en el que el bloque y el cierre son tratados de manera similar ya que lo que Rubí llama bloque es un cierre:

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

Hay each -method se pasa una función de cierre (teniendo un parámetro x) que se llama bloque en Ruby.

+0

... luego está la confusión con Smalltalk. ¡Lo que los programadores de Ruby llaman un bloque, Smalltalk llama un 'BlockClosure'! – daf

+0

En realidad, en tu ejemplo de Ruby, el bloque * no * es un cierre, porque no se cierra sobre nada. Más interesante sería 'a = 7; (1..10). Cada do | x | p a << x end' o algo así. –

1

Los términos que está utilizando son los más utilizados juntos actualmente en Ruby, aunque los constructos aparecieron previamente en Algol, Smalltalk y Scheme. Citaría el estándar Ruby, si hubiera uno.

No estoy seguro de poder responder a su pregunta exacta, pero puedo ilustrarlo. Mis disculpas si usted sabe esto ya ...

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 

Y ...

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

Así que un bloque es una secuencia de funciones como el anonimato de código adjunto a una llamada al método. Se usa en todo Ruby API. Cuando haces que sea más fácil crear una función anónima resulta que son útiles para todo tipo de cosas.

Pero tenga en cuenta que después de f vuelve, entonces vuelve g, llevamos a cabo en el bloque devolviéndolo a partir f (como x) y luego desde g (como t). Ahora llamamos al bloque por segunda vez. Una vez más, tenga en cuenta que g() ha regresado. Pero el bloque se refiere a una variable local en una instancia de función (y alcance) que ya no existe. Y obtiene el nuevo valor de y?!

Así que un cierre es un objeto similar a una función que se cierra sobre su alcance léxico. Son bastante difíciles de implementar porque destruyen el modelo do-it-with-a-stack que es tan útil para variables locales en instancias de llamadas a funciones.


1. Ruby tiene varios sabores de objetos de función de cierre-similares; este es solo uno de ellos.

+0

El fragmento de código en esta respuesta es una ilustración perfecta de por qué no uso Ruby. –

2

La voz alta, uno con barba tiene esto que decir acerca de cierres y Bloques:

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

En un momento dado, dice un cierre es un bloque que se puede pasar como argumento a un método.

+0

Acabo de encontrar que el concepto de cierre es mucho más general y mejor definido que un bloque. No vi la necesidad de bloques si ya hay cierres reales. –

+0

¡Gracias por el enlace! –

+0

@WeiQiu Como he dicho más o menos en mi respuesta anterior, el comportamiento de 'retorno' comprende la mayoría de las razones para el cierre de bloque como entidades separadas de cierres de función. –

4

Hay mucha confusión aquí porque hay términos con varias definiciones y múltiples cosas distintas que se combinan simplemente porque generalmente se encuentran juntas.

Primero, tenemos "bloque". Eso es solo una porción léxica de código que forma una unidad, el cuerpo de un bucle, por ejemplo. Si el lenguaje realmente tiene alcance de bloque, entonces se pueden definir variables que solo existen dentro de ese bloque de código.

En segundo lugar, tenemos código invocable como tipo de valor. En los lenguajes funcionales, estos son valores de funciones, a veces llamados "funs", "funciones anónimas" (porque la función se encuentra en el valor, no el nombre asignado, no necesita un nombre para llamarlos) o " lambdas "(del operador utilizado para crearlos en el cálculo Lambda de Church). Se los puede llamar "cierres", pero no son automáticamente cierres verdaderos; para calificar, deben encapsular ("cerrar") el alcance léxico que rodea su creación, es decir, las variables definidas fuera del alcance de la función en sí, pero dentro del alcance de su definición todavía están disponibles cada vez que se llama a la función, incluso si el punto de llamada es después de que la variable referenciada saliera del alcance y se haya reciclado su almacenamiento.

Sin embargo, puede tener valores de código invocables que no son funciones completas. Smalltalk llama a estos "cierres de bloque", mientras que Ruby los llama "procs". Pero la mayoría de los Rubyistas simplemente los llaman "bloques", porque son la versión reificada de lo creado por { ... } o do ... end sintaxis. Lo que los diferencia de lambdas (o "cierres de funciones") es que no introducen un nuevo nivel de subrutina. Si el código en el cuerpo de un bloqueo de bloque llama a return, se devuelve de la función/método externo el cierre de bloque existente dentro, no solo el bloque en sí.

Ese comportamiento es crítico para preservar lo que R.D. Tennent etiquetó como el "principio de correspondencia", que establece que debería poder reemplazar cualquier código con una función en línea que contenga ese código en el cuerpo y llamarlo inmediatamente. Por ejemplo, en Javascript, puede reemplazar esto:

x = 2; 

con esto:

(function(){x = 2;})(); 

Mi ejemplo no es muy interesante, pero la capacidad de hacer este tipo de transformación sin afectar el comportamiento de la programa juega un papel clave en la refactorización funcional. El problema es que, tan pronto como haya incrustado return declaraciones, el principio ya no se cumple.

Es por eso que Ruby tiene procs y lambdas, una fuente perenne de confusión para los novatos. Ambos procs y lambdas son objetos de la clase Proc, pero se comportan de manera diferente, como se indicó anteriormente: un return acaba de regresar del cuerpo de una lambda, pero regresa del método que rodea a un proceso. (Además, aunque no es relevante para la distinción que estoy dibujando aquí, lambdas comprueba arity y se queja si se llama con el número incorrecto de argumentos. Puede decir qué tipo tiene llamando al .lambda? en el objeto.)

Javascript actualmente solo tiene cierres de función, aunque hay una propuesta sobre la mesa para introducir cierres de bloque en el idioma.

0

Eso es un número entero .

Int workDaysInAWeek = 5

Esa es una número entero variable de y puede ser ajustado a un diferente número entero. (Si las circunstancias le impiden modificar ese valor, que puede ser llamado una constante .)

Mientras que los números se refieren anteriores, bloques y cierres preocupación algoritmos. La distinción entre bloques y cierres, respectivamente, también es equivalente a la anterior.

Cuestiones relacionadas