La regla del fuera de juego describe la sintaxis de un lenguaje de programación informática que define los límites de un bloque de código a través de la sangría . [1] [2]
El término fue acuñado por Peter Landin , posiblemente como un juego de palabras con la ley del fuera de juego en el fútbol asociación .
Un lenguaje con reglas de fuera de juego se contrasta con un lenguaje de forma libre en el que la sangría no tiene un significado sintáctico y es estrictamente una cuestión de estilo .
Un lenguaje de reglas de fuera de juego también se describe como que tiene una sangría significativa .
Peter Landin , en su artículo de 1966 " Los próximos 700 lenguajes de programación ", definió la regla del fuera de juego de esta manera: "Cualquier token que no sea un espacio en blanco a la izquierda del primer token de este tipo en la línea anterior se toma como el comienzo de una nueva declaración". [3]
El siguiente es un ejemplo de bloques de sangría en Python , un lenguaje de reglas de fuera de juego muy popular. En Python, la regla se utiliza para definir los límites de las instrucciones en lugar de las declaraciones.
def is_even ( a : int ) -> bool : si un % 2 == 0 : imprimir ( '¡Incluso!' ) Devuelve verdadero imprimir ( '¡Qué raro!' ) devuelve falso
El cuerpo de la función comienza en la línea 2, ya que tiene una sangría de un nivel (4 espacios) más que la línea anterior. El if
cuerpo de la cláusula comienza en la línea 3, ya que tiene una sangría de un nivel adicional, y termina en la línea 4, ya que la línea 5 tiene una sangría de un nivel menos, es decir, está desangrada.
Los dos puntos ( :
) al final de una línea de instrucción de control son sintaxis de Python, no un aspecto de la regla de fuera de juego. La regla se puede implementar sin esa sintaxis de dos puntos.
La regla del off-side se puede implementar en la fase de análisis léxico , como en Python , donde aumentar la sangría da como resultado que el analizador léxico muestre un INDENT
token, y disminuir la sangría da como resultado que el analizador léxico muestre un DEDENT
token. [4] Estos tokens corresponden a la llave de apertura {
y la llave de cierre }
en lenguajes que usan llaves para bloques, y significa que la gramática de frases no depende de si se usan llaves o sangría. Esto requiere que el analizador léxico mantenga el estado, es decir, el nivel de sangría actual, y por lo tanto pueda detectar cambios en la sangría cuando esta cambia, y por lo tanto la gramática léxica no es libre de contexto : INDENT
y DEDENT
depende de la información contextual del nivel de sangría anterior.
La principal alternativa a la delimitación de bloques mediante sangría, popularizada por el amplio uso e influencia del lenguaje C , es ignorar los caracteres de espacio en blanco y marcar los bloques explícitamente con llaves (es decir, {
y }
) o algún otro delimitador. Si bien esto permite una mayor libertad de formato (un desarrollador puede optar por no sangrar pequeños fragmentos de código como las declaraciones break y continue ), el código con sangría descuidada puede llevar al lector por mal camino, como el error goto fail .
Lisp y otros lenguajes basados en expresiones S no diferencian las declaraciones de las expresiones, y los paréntesis son suficientes para controlar el alcance de todas las declaraciones dentro del lenguaje. Al igual que en los lenguajes con llaves, el lector (es decir, la función de lectura) ignora en su mayoría los espacios en blanco. Los espacios en blanco se utilizan para separar tokens. [5] La estructura explícita del código Lisp permite la sangría automática, para formar una señal visual para los lectores humanos.
Otra alternativa es que cada bloque comience y termine con palabras clave explícitas. Por ejemplo, en ALGOL 60 y su descendiente Pascal , los bloques comienzan con keyword begin
y terminan con keyword end
. En algunos lenguajes (pero no en Pascal), esto significa que las nuevas líneas son importantes [ cita requerida ] (a diferencia de los lenguajes con llaves), pero la sangría no lo es. En BASIC y Fortran , los bloques comienzan con el nombre del bloque (como IF
) y terminan con el nombre del bloque antepuesto con END
(p. ej., END IF
). En Fortran , todos y cada uno de los bloques también pueden tener su propio nombre de bloque único, lo que agrega otro nivel de explicitud al código extenso. ALGOL 68 y el shell Bourne (sh y bash ) son similares, pero el final del bloque generalmente se da por el nombre del bloque escrito al revés (p. ej., case
inicia una declaración switch y se extiende hasta el esac
; de manera similar, los condicionales if
... then
...[ elif
...[ else
...]] fi
o los bucles for for
... do
... od
en ALGOL68 o for
... do
... done
en bash).
Una variante interesante de esto ocurre en Modula-2 , un lenguaje similar a Pascal que elimina la diferencia entre bloques de una y varias líneas. Esto permite que el abridor de bloque ( {
o BEGIN
) se omita para todos los bloques excepto el de nivel de función, requiriendo solo un token de terminación de bloque ( }
o END
). También corrige el else pendiente . La costumbre es que el end
token se coloque en el mismo nivel de sangría que el resto del bloque, lo que da una estructura de bloque que es muy legible.
Una ventaja del enfoque Fortran es que mejora la legibilidad de código largo, anidado o complejo. Un grupo de sangrías o corchetes de cierre por sí solos no proporciona pistas contextuales sobre qué bloques se están cerrando, lo que requiere volver atrás y un escrutinio más minucioso durante la depuración . Además, los lenguajes que permiten un sufijo para palabras clave similares a END mejoran aún más dichas pistas, como continue
versus continue for x
, y el marcador de fin de bucle que especifica la variable de índice NEXT I
versus NEXT
, y bucles con nombre único CYCLE X1
versus . Sin embargo, los editores de código fuenteCYCLE
modernos a menudo proporcionan indicadores visuales, como resaltado de sintaxis , y funciones como plegado de código para ayudar con estos inconvenientes.
En el lenguaje Scala , las primeras versiones solo permitían llaves. Scala 3 agregó una opción para usar sangría para estructurar bloques. El diseñador Martin Odersky dijo que esta fue la forma más importante en que Scala 3 mejoró su propia productividad, que hace que los programas sean un 10% más cortos y mantiene a los programadores "en el flujo", y recomienda su uso. [6]
Lenguajes de programación notables con la regla del fuera de juego:
#light
se especifica cuándo; en versiones posteriores, #light "off"
no se especifica cuándo [7]where
, let
, do
o case ... of
cuando se omiten las llavesFormatos de archivos de texto y lenguajes no de programación destacados con sangría significativa: