¿Qué es exactamente la regla "como si"?

89

Como dice el título,

¿Qué es exactamente la regla "como si"?

Una respuesta típica que se obtendría es:

La regla que permite todas y cada una de las transformaciones de código que no cambian el comportamiento observable del programa.

De vez en cuando seguimos obteniendo comportamientos de ciertas implementaciones que se atribuyen a esta regla. Muchas veces equivocadamente. Entonces, ¿qué es exactamente esta regla? El estándar no menciona claramente esta regla como una sección o párrafo, entonces, ¿qué cae exactamente bajo el alcance de esta regla? A mí me parece un área gris que no está definida en detalle por el estándar. ¿Alguien puede ampliar los detalles citando las referencias del estándar?

Nota: Etiquetar esto como C y C ++ ambos, porque es relevante para ambos lenguajes.

Alok Save
fuente
2
Se refiere a la máquina abstracta.
Alexey Frunze
" Etiquetar esto como C y C ++, porque es relevante para ambos lenguajes " Es relevante en cualquier idioma.
curioso
@AlexeyFrunze " Se refiere a la máquina abstracta " Se refiere al estado de la "máquina abstracta" siendo una herramienta y no un fin, y siendo irrelevante en términos de conformidad, porque es "abstracto" que es una herramienta de especificación no real.
curioso

Respuestas:

98

¿Qué es la regla " como si "?

La regla " como si " básicamente define qué transformaciones puede realizar una implementación en un programa C ++ legal. En resumen, se permiten todas las transformaciones que no afecten el " comportamiento observable " de un programa (ver más abajo para una definición precisa).

El objetivo es dar a las implementaciones libertad para realizar optimizaciones siempre que el comportamiento del programa siga siendo compatible con la semántica especificada por el estándar C ++ en términos de una máquina abstracta.


¿Dónde introduce la Norma esta regla?

El estándar C ++ 11 introduce la regla " como si " en el párrafo 1.9 / 1:

Las descripciones semánticas de esta Norma Internacional definen una máquina abstracta no determinista parametrizada. Esta Norma Internacional no impone ningún requisito sobre la estructura de las implementaciones conformes. En particular, no necesitan copiar ni emular la estructura de la máquina abstracta. Más bien, se requieren implementaciones conformes para emular (solo) el comportamiento observable de la máquina abstracta como se explica a continuación.

Además, una nota explicativa a pie de página agrega:

Esta disposición a veces se denomina la regla "como si" , porque una implementación es libre de ignorar cualquier requisito de esta Norma Internacional siempre que el resultado sea como si el requisito se hubiera cumplido, en la medida en que se pueda determinar a partir del comportamiento observable. Del programa. Por ejemplo, una implementación real no necesita evaluar parte de una expresión si puede deducir que su valor no se usa y que no se producen efectos secundarios que afecten el comportamiento observable del programa.


¿Qué exige la regla exactamente?

El párrafo 1.9 / 5 especifica además:

Una implementación conforme que ejecuta un programa bien formado producirá el mismo comportamiento observable que una de las posibles ejecuciones de la instancia correspondiente de la máquina abstracta con el mismo programa y la misma entrada . Sin embargo, si tal ejecución contiene una operación no definida, esta Norma Internacional no impone ningún requisito a la implementación que ejecuta ese programa con esa entrada (ni siquiera con respecto a las operaciones que preceden a la primera operación no definida).

Vale la pena enfatizar que esta restricción se aplica cuando se "ejecuta un programa bien formado" solamente, y que los posibles resultados de ejecutar un programa que contiene un comportamiento indefinido no están restringidos. Esto también se hace explícito en el párrafo 1.9 / 4:

Algunas otras operaciones se describen en esta Norma Internacional como indefinidas (por ejemplo, el efecto de intentar modificar un objeto constante). [Nota: Esta Norma Internacional no impone requisitos sobre el comportamiento de los programas que contienen un comportamiento indefinido . —Nota final]

Por último, con respecto a la definición de " comportamiento observable ", el párrafo 1.9 / 8 dice lo siguiente:

Los requisitos mínimos para una implementación conforme son:

- El acceso a objetos volátiles se evalúa estrictamente de acuerdo con las reglas de la máquina abstracta.

- Al finalizar el programa, todos los datos escritos en archivos serán idénticos a uno de los posibles resultados que habría producido la ejecución del programa de acuerdo con la semántica abstracta.

- La dinámica de entrada y salida de los dispositivos interactivos se llevará a cabo de tal manera que la salida de avisos se entregue realmente antes de que un programa espere la entrada. Lo que constituye un dispositivo interactivo está definido por la implementación.

Estos colectivamente se conocen como el comportamiento observable del programa . [ Nota : Cada implementación puede definir correspondencias más estrictas entre la semántica abstracta y real. - nota final ]


¿Hay situaciones en las que esta regla no se aplica?

Hasta donde yo sé, la única excepción a la regla " como si " es la elisión de copiar / mover, que está permitida aunque el constructor de copia, el constructor de movimiento o el destructor de una clase tengan efectos secundarios. Las condiciones exactas para esto se especifican en el Párrafo 12.8 / 31:

Cuando se cumplen ciertos criterios, una implementación puede omitir la construcción de copiar / mover de un objeto de clase, incluso si el constructor seleccionado para la operación de copiar / mover y / o el destructor del objeto tienen efectos secundarios . [...]

Andy Prowl
fuente
2
He visto esta cita. Lo que no está claro es la definición de comportamiento observable. ¿Qué califica exactamente como comportamiento observable? La elisión de la copia es una excepción a la regla como si fuera bastante conocida y, en realidad, no forma parte de mi pregunta.
Alok Save
2
@AlokSave: Bueno, en el estándar C, vemos "Acceder a un objeto volátil, modificar un objeto, modificar un archivo o llamar a una función que realiza cualquiera de esas operaciones son todos efectos secundarios". Es de suponer que hay algo equivalente en los estándares de C ++. De manera informal, supongo "cualquier cosa que cambie su interacción con el mundo exterior".
Oliver Charlesworth
1
Cualquier comportamiento que cambie el estado de la máquina abstracta (es decir, algo que cambie una variable pasada o variable global, o que lea y escriba en dispositivos de E / S).
Mats Petersson
1
¿Significa esto que está permitido eliminar un bucle infinito que no hace nada, siempre que no ocurra nada observable después?
harold
5
Un punto a tener en cuenta en particular es que solo se aplica a los programas legales . Cualquier cosa que invoque un comportamiento indefinido está explícitamente fuera de cobertura.
vonbrand
15

En C11, la regla nunca recibe ese nombre. Sin embargo, C, al igual que C ++, define el comportamiento en términos de máquina abstracta. La regla como si está en C11 5.1.2.3p4 y p6 :

  1. En la máquina abstracta, todas las expresiones se evalúan según lo especificado por la semántica. Una implementación real no necesita evaluar parte de una expresión si puede deducir que su valor no se usa y que no se producen efectos secundarios necesarios (incluidos los causados ​​por llamar a una función o acceder a un objeto volátil).

  2. [...]

  3. Los requisitos mínimos para una implementación conforme son:

    • Los accesos a los volatileobjetos se evalúan estrictamente de acuerdo con las reglas de la máquina abstracta.
    • Al finalizar el programa, todos los datos escritos en archivos serán idénticos al resultado que habría producido la ejecución del programa de acuerdo con la semántica abstracta.
    • La dinámica de entrada y salida de los dispositivos interactivos se llevará a cabo como se especifica en 7.21.3 . La intención de estos requisitos es que la salida sin búfer o con búfer de línea aparezca lo antes posible, para garantizar que los mensajes de aviso aparezcan antes de que un programa esté esperando una entrada.

     

    Este es el comportamiento observable del programa.

Antti Haapala
fuente
-1

En C, C ++, Ada, Java, SML ... en cualquier lenguaje de programación bien especificado mediante la descripción de los comportamientos (generalmente muchos posibles, no deterministas) de un programa (expuesto a una serie de interacciones en los puertos de E / S) , no hay una regla como si fuera distinta .

Un ejemplo de regla distinta es la que dice que una división por cero genera una excepción (Ada, Caml) o una desreferencia nula genera una excepción (Java). Podrías cambiar la regla para especificar otra cosa y terminarías con un lenguaje diferente (que algunas personas prefieren llamar un "dialecto" (*). Existe una regla distinta para especificar algunos usos distintos de un lenguaje de programación como un La regla gramatical cubre algunas construcciones de sintaxis.

(*) Un dialecto según algunos lingüistas es una lengua con un "ejército". en ese contexto, eso podría significar un lenguaje de programación sin un comité y una industria específica de editores de compiladores.

La regla como si no es una regla distinta ; no cubre ningún programa en particular y ni siquiera es una regla que pueda discutirse, eliminarse o alterarse de ninguna manera : la llamada "regla" simplemente reitera que la semántica del programa está definida y solo puede ser portable (universalmente) definido, en términos de las interacciones visibles de una ejecución del programa con el mundo "externo".

El mundo externo puede ser interfaces de E / S (stdio), una GUI, incluso un intérprete interactivo que genera el valor resultante de un lenguaje aplicativo puro. En C y C ++ se incluyen los accesos (vagamente especificados) a objetos volátiles, que es otra forma de decir que algunos objetos en un punto dado deben representarse en la memoria estrictamente de acuerdo con la ABI (Application Binary Interface) sin mencionar la ABI explícitamente.

La definición de lo que es un rastro de ejecución , también llamado comportamiento visible u observable, define lo que se entiende por "regla como si". La regla como si intenta explicarlo, pero al hacerlo, confunde a las personas más que aclara las cosas, ya que da la expresión de ser una regla semántica adicional que da más libertad de acción a la implementación.

Resumen:

  • La llamada "regla como si" no relaja ninguna restricción en las implementaciones.
  • No puede eliminar la regla como si en ningún lenguaje de programación especificado en términos de comportamiento visible (trazos de ejecución compuestos para la interacción con el mundo externo) para obtener un dialecto distinto.
  • No puede agregar la regla como si a ningún lenguaje de programación no especificado en términos de comportamiento visible.
curioso
fuente
Si la gente cree que estoy equivocado y hay una "regla como si" distinta, ¿por qué no tratan de describir una variante de C ++ (un dialecto) sin esa "regla"? ¿Qué significaría la especificación C ++ sin ella? Sería absolutamente imposible saber si un compilador es conforme. O incluso para definir conformismo.
Curioso