delphi - switch - ¿Cómo maneja el compilador las declaraciones de casos?
sintaxis de case en delphi (2)
declaración de caso
El compilador prefiere transformar la declaración de caso a una tabla de salto.
Para que esto sea posible, las etiquetas de casos duplicados no están permitidas.
Además, el compilador no tiene que probar las declaraciones de casos en el orden en que las ha declarado. Por razones de optimización, reordenará estos elementos como lo considere conveniente; por lo que incluso si no usa una tabla de salto, aún no puede permitir etiquetas de caso duplicadas.
Es por estas mismas razones (y para mantener mentalmente sanos a los programadores) que la declaración de caso no permite fallas.
declaración if
Una (serie de) declaraciones if se procesan en el orden en que se declaran.
El compilador los probará uno por uno (y saltará cuando sea apropiado).
Si el enunciado if no contiene duplicados, el código funcionará igual que un enunciado de caso equivalente, pero el código generado probablemente sea diferente.
Si las declaraciones nunca se convierten en tablas de salto.
sobre conjuntos
Los conjuntos de motivos están limitados a 256 elementos, es decir, cada elemento de un conjunto ocupa un espacio.
256 bits = 32 bytes.
Permitir más de 256 elementos en un conjunto haría crecer demasiado la representación en la memoria, lo que dificultaría el rendimiento.
El enunciado caso no usa conjuntos, simplemente usa lógica de conjunto en su semántica.
En la documentación bajo declaraciones de casos, dice:
Cada valor representado por una lista de casos debe ser único en la declaración de caso;
Y el ejemplo que se muestra,
case I of
1..5: Caption := ''Low'';
6..9: Caption := ''High'';
0, 10..99: Caption := ''Out of range'';
else
Caption := ;
end
es equivalente al condicional anidado:
if I in [1..5] then
Caption := ''Low'';
else if I in [6..10] then
Caption := ''High'';
else if (I = 0) or (I in [10..99]) then
Caption := ''Out of range''
else
Caption := ;
Así que la primera cita sugiere que se maneja como un conjunto (lea los comentarios aquí al menos una persona está conmigo en esto).
Ahora sé la parte
donde selectorExpression es cualquier expresión de un tipo ordinal menor que 32 bits
contradice con las propiedades de los conjuntos, ya que se menciona bajo los conjuntos:
El tipo base no puede tener más de 256 valores posibles, y sus ordinalidades deben estar entre 0 y 255
Lo que realmente me molesta es por qué es una necesidad tener valores únicos en CaseList. Si es equivalente a la instrucción if
, el segundo valor simplemente no se probaría porque el compilador ya encontró una coincidencia previa.
La documentación toma una declaración de caso específica que es equivalente a una declaración if específica .
En general, cualquier enunciado de caso se puede reescribir como una declaración if usando el mismo enfoque. Sin embargo, lo inverso no es verdad.
La documentación usa una declaración if equivalente para explicar el comportamiento lógico (o semántica ) de la declaración de caso . No es una representación de lo que el compilador hace internamente.
¿Cómo maneja el compilador la declaración de caso?
En primer lugar, hay dos aspectos en esta pregunta.
- Semánticamente, el compilador debe manejar la declaración de caso como se indica en la documentación. Esto incluye:
- Asegurando que los valores de cada entrada de CaseList puedan ser evaluados en tiempo de compilación.
- Asegurar que las entradas de CaseList sean únicas.
- Cualquiera que sea la entrada caseList coincida, se llama a la instrucción caseList correspondiente.
- Si ninguna de las entradas de CaseList coincide, se invocan las instrucciones else.
- Sin embargo, el compilador tiene derecho a optimizar la implementación como lo crea conveniente, siempre que el código optimizado de byte / máquina sea lógicamente equivalente.
- La respuesta de Johan describe optimizaciones comunes: listas de salto y reordenamiento.
- Estos son mucho más fáciles de aplicar dada la estricta semántica.
Lo que realmente me molesta es por qué es una necesidad tener valores únicos en CaseList .
La singularidad es necesaria para eliminar la ambigüedad. ¿Qué instrucción caseList debería usarse si hay más de una coincidencia?
- Podría llamar a la primera declaración caseList coincidente e ignorar el resto. (La sentencia SQL Server
CASE
comporta de esta manera). Consulte también[1]
continuación. - Podría llamarlos a todos. (Si no recuerdo mal, el lenguaje de programación MANTIS usa esta semántica para su versión de una declaración de caso).
- Podría informar un error que requiera que el programador elimine la ambigüedad de CaseList . (En pocas palabras, esto es lo que exige la especificación de Delphi. Muchos otros lenguajes usan el mismo enfoque. Discutir sobre esto es improductivo, especialmente dado que es poco probable que esta elección sea un gran obstáculo).
Si es equivalente a la declaración if, el segundo valor simplemente no se probará porque el compilador ya encontró una coincidencia previa.
[1]
Me gustaría señalar que esto puede hacer que el código sea mucho más difícil de leer. Este comportamiento es "correcto" cuando se usan literales mágicos, pero cuando se usan identificadores const se vuelve peligroso. Si 2 consts diferentes tienen el mismo valor, no será inmediatamente aparente que no se invocará la última declaración de Lista de casos en la que caseList también coincide. También las declaraciones de casos estarían sujetas a cambios de comportamiento debido a un simple re-orden de caseList .
const
NEW_CUSTOMER = 0;
EDIT_CUSTOMER = 1;
...
CANCEL_OPERATION = 0;
case UserAction of
NEW_CUSTOMER : ...;
EDIT_CUSTOMER : ...;
...
CANCEL_OPERATION : ...; { Compiler error is very helpful. }
end;
Contradictos con las propiedades de los conjuntos
No hay contradicción El hecho de que cada valor de CaseList debe ser único no implica de ninguna manera que deba "manejarse como un conjunto". Esa es tu suposición incorrecta. Otros haciendo la misma suposición son igualmente incorrectos.
Cómo se verifica la restricción de exclusividad depende del compilador. Solo podemos especular. Pero creo que lo más eficiente sería mantener una lista ordenada de rangos. Analice cada una de las listas de casos de valores y rangos, encuentre su posición en la lista anterior. Si se superpone, informe un error; de lo contrario, agréguelo a la lista.