Me encontré luchando por ver de qué se trata este principio y por qué es tan importante para el diseño del lenguaje.
Básicamente, establece que para cada expresión expr
en el lenguaje debe ser exactamente la misma que esta construcción:
(function () { return expr; })()
Además, he oído que Ruby obedece este principio, mientras que Python no. No entiendo por qué esto es cierto, o si es cierto en absoluto.
design
language-agnostic
Andrés
fuente
fuente
expr
obtiene el seguimiento de la pila actual.Respuestas:
Nunca antes había oído hablar del "Principio de correspondencia de Tennent" y mucho menos de que fuera importante en el diseño del lenguaje. Buscar en Google las expresiones parece llevar a un blog de Neal Gafter de 2006 que establece lo que él cree que es y cómo cree que debería aplicarse también a los cierres. Y la mayoría de los demás en los foros parecen referirse a la entrada de Gafter.
Sin embargo, aquí hay una mención de dicho "TCP" por Douglas Crockford (un nombre que conozco y en el que confío): http://java.sys-con.com/node/793338/ . En parte
Por lo tanto, parece que el nombre "Principio de correspondencia de Tennent" está mal utilizado, y lo que sea que Neal habla posiblemente debería llamarse "TCP imaginado y posiblemente generalizado de Gafter" ... o algo así. En cualquier caso, no es suficiente para esconderse detrás de una cortina de nombre de libro agotado
fuente
Veo esto como parte de una regla general de que un lenguaje bien diseñado hace lo que un programador esperaría naturalmente. Si tengo un bloque de código que quiero refactorizar en un cierre, y envuelvo ese bloque con la sintaxis adecuada sin pensar realmente en las líneas de código individuales, entonces espero que ese bloque haga lo mismo en el cierre. hizo en línea. Si algunas declaraciones usan la palabra clave "this" (quizás implícitamente) y el lenguaje hace que "this" usado dentro del cierre se refiera a una clase anónima usada para representarlo en lugar de la clase que define el método que define el cierre, entonces el significado de esas declaraciones han cambiado, mi bloque de código ya no hace lo que creo que hace, y tengo que rastrear un error y descubrir cómo cambiar mi código para que funcione en el cierre.
El problema también podría mitigarse con un IDE con herramientas de refactorización inteligentes, que podrían extraer cierres, detectar posibles problemas e incluso ajustar automáticamente el código extraído para resolver los problemas.
fuente
Claus Reinke: con respecto al "Diseño del lenguaje basado en principios semánticos" de Tennent,
ofrece una interpretación interesante de los principios:
"La correspondencia es el principio que nos permite decir que
y
debería ser equivalente, y que cualquier cosa que podamos hacer en las listas formales de parámetros, también deberíamos poder hacerlo en las declaraciones, y viceversa. "[ver también, Reinke, a continuación.]
Tendencia RD: Métodos de diseño del lenguaje basados en principios semánticos
"Dos métodos de diseño del lenguaje basados en principios derivados del enfoque denotacional para la semántica del lenguaje de programación se describen e ilustran mediante una aplicación al lenguaje Pascal. Los principios son, en primer lugar, la correspondencia entre lo paramétrico y mecanismos declarativos y, en segundo lugar, un principio de abstracción para lenguajes de programación adaptados de la teoría de conjuntos. Varias extensiones y generalizaciones útiles de Pascal surgen mediante la aplicación de estos principios, incluida una solución al problema de los parámetros de la matriz y una instalación de modularización ".
Claus Reinke: "Sobre programación funcional, diseño de lenguaje y persistencia" en Haskell
fuente
Para responder a la pregunta de por qué el CP de Tennent es tan importante para el diseño del lenguaje, me gustaría citar a Neal Gafter :
Es probable que cualquier violación de TCP perjudique a algún programador en el futuro cuando espera que los cierres funcionen como un código de no cierre, pero descubre que, en violación de TCP, no lo hacen.
fuente
RE Python no sigue este principio. En general, sigue el principio. Ejemplo básico:
Sin embargo, Python define expresiones y declaraciones por separado. Dado que las
if
ramas, loswhile
bucles, la asignación destructiva y otras declaraciones no se pueden usar enlambda
expresiones, la letra del principio de Tennent no se aplica a ellos. Aun así, restringirse a usar solo expresiones de Python todavía produce un sistema completo de Turing. Así que no veo esto como una violación del principio; o más bien, si viola el principio, entonces ningún lenguaje que defina declaraciones y expresiones por separado puede ajustarse al principio.Además, si el cuerpo de la
lambda
expresión capturara un rastro de la pila o realizara otra introspección en la máquina virtual, eso podría causar diferencias. Pero en mi opinión, esto no debe considerarse como una violación. Siexpr
y(lambda: expr)()
necesariamente compila al mismo bytecode, entonces el principio realmente concierne a los compiladores, no a la semántica; pero si pueden compilar a diferentes bytes, no deberíamos esperar que el estado de la VM sea idéntico en cada caso.Se puede encontrar una sorpresa usando la sintaxis de comprensión, aunque creo que esto tampoco es una violación del principio de Tennent. Ejemplo:
La sorpresa es el resultado de cómo se definen las comprensiones de listas. La comprensión 'sorpresa' anterior es equivalente a este código:
Visto de esta manera, la comprensión 'sorpresa' anterior es menos sorprendente, y no una violación del principio de Tennent.
fuente