2009-11-11 11 views
14

Me encontré con this question en las preguntas frecuentes de Go, y me recordó algo que me ha estado molestando por un tiempo. Desafortunadamente, realmente no veo a qué se dirige la respuesta.¿Por qué muchos lenguajes de programación ponen el tipo * después de * el nombre de la variable?

Parece que casi todos los idiomas no C-como pone el tipo después de que el nombre de la variable, así:

var : int 

Sólo por curiosidad, ¿por qué es esto? ¿Hay ventajas para elegir uno u otro?

+0

@Jurily - No discutiré eso. Solo tenía curiosidad si había alguna ventaja en hacer las cosas de una manera frente a la otra. –

+3

@Jurily, para ser completamente exacto, _everyone_ tiene su apellido último :-). Y para ser justos, creo que si la mayoría de la gente lo mirara de manera imparcial, estarían de acuerdo en que el enfoque general a específico (como en chino o, como usted dice, húngaro) tiene más sentido. –

+0

https://stackoverflow.com/questions/1891775/any-reason-for-having-val-capacity-int-instead-of-val-int-capacity-in-scal/1893263 – starblue

Respuesta

12

Hay un problema de análisis sintáctico, como dice Keith Randall, pero no es lo que él describe. El "no saber si es una declaración o una expresión" simplemente no importa; no importa si se trata de una expresión o una declaración hasta que haya analizado todo el asunto de todos modos, momento en que se resuelve la ambigüedad.

Al usar un analizador sin contexto, no importa en absoluto si el tipo viene antes o después del nombre de la variable. Lo que importa es que no necesita buscar nombres de tipos definidos por el usuario para comprender la especificación de tipo: no necesita haber entendido todo lo que vino antes para comprender el token actual.

La sintaxis de Pascal no tiene contexto, si no completamente, al menos WRT este problema. El hecho de que el nombre de la variable sea lo primero es menos importante que los detalles, como el separador de dos puntos y la sintaxis de las descripciones de los tipos.

La sintaxis de C es sensible al contexto.Para que el analizador determine dónde termina una descripción de tipo y qué token es el nombre de la variable, ya debe haber interpretado todo lo que venía antes para poder determinar si un token identificador dado es el nombre de la variable o simplemente otro token que contribuye a la descripción del tipo.

Como la sintaxis de C es sensible al contexto, es muy difícil (si no imposible) analizar utilizando herramientas de generador de análisis tradicionales como yacc/bison, mientras que la sintaxis de Pascal es fácil de analizar utilizando las mismas herramientas. Dicho esto, ahora hay generadores de analizadores que pueden hacer frente a la sintaxis C y hasta C++. Aunque no está debidamente documentado o en un 1.? lanzamiento, etc., mi favorito personal es Kelbt, que utiliza LTR de retroceso y admite "deshacer" semántico, básicamente deshacer anotaciones en la tabla de símbolos cuando los análisis especulativos resultan ser incorrectos.

En la práctica, los analizadores de C y C++ generalmente se escriben a mano, mezclando el descenso recursivo y el análisis de precedencia. Supongo que lo mismo se aplica a Java y C#.

Por cierto, problemas similares con la sensibilidad del contexto en el análisis de C++ han creado muchas cosas desagradables. El "Alternative Function Syntax" para C++ 0x está trabajando en torno a un problema similar al mover una especificación de tipo hasta el final y colocarla después de un separador, muy parecido a los dos puntos de Pascal para los tipos de devolución de funciones. No elimina la sensibilidad del contexto, pero adoptar esa convención similar a Pascal lo hace un poco más manejable.

+0

* EDIT * - confesión - con descenso recursivo, * es * algo más fácil de analizar si el constructo es fácilmente identificable cerca de su inicio. Tener una palabra clave cerca del inicio es bueno para eso. Realmente no cuento C type-then-variable-name en esto, sin embargo, porque realmente no identifica el constructo antes que variable-then-type. Podría ser una declaración de variable, o una declaración de función, o un tipo de función de tipocast en una variable en el lado izquierdo de una asignación, o ... – Steve314

+0

¿No es esto más una función del colon, aunque ? Como puedo decir que 'var: int' es un nombre de variable debido a los dos puntos. Parece que sería igual de fácil hacer 'int: var' (aunque tal vez un poco más feo :-)). –

+1

@Jason Baker: disculpa por la demora. Un compilador puede manejar "varname int" o "int varname", suponiendo que "int" es una palabra clave. Sin embargo, "varname mytype" o "mytype varname" es más un problema, no porque "mytype" sea un identificador exacto, sino porque necesita la búsqueda del diccionario para determinar qué construcciones sintácticas podrían aplicarse. La antigua sintaxis de C donde los nombres de las estructuras no eran nombres de tipos válidos (se escribiría "struct structname myvar;") era más simple, ya que el prefijo "struct" muestra sintácticamente que el tipo * es * un tipo. Un dos puntos puede ayudar, pero no es ni la solución completa ni la única. – Steve314

1

Así es como se diseñó el lenguaje. Visual Basic siempre ha sido así.

La mayoría (si no todos) los idiomas de llaves colocan primero el tipo. Esto es más intuitivo para mí, ya que la misma posición también especifica el tipo de devolución de un método. De modo que las entradas entran en el paréntesis y la salida sale por detrás del nombre del método.

+4

laguages ​​que también ponen el tipo ponga el tipo de retorno último, por ejemplo, nombre (arg: tipo): tipo_de_volumen –

+0

C++ 0x le permite poner la función tipo de retorno último: 'auto func (int arg1) -> int' – jmucchiello

10

los "otros" idiomas de los que habla son los que son más declarativos. Su objetivo es permitirle programar más a lo largo de las líneas en las que piensa (suponiendo que no esté encasillado en el pensamiento imperativo).

último tipo se lee como 'crear una variable llamada nombre del tipo TIPO'

esto es lo contrario, por supuesto, al decir 'crear un tipo llamado NOMBRE', pero cuando se piensa en ello, cuál es el valor de es más importante que el tipo, el tipo es simplemente una restricción programática en los datos

+1

+1 Bien dicho ... y 15 personajes más – wheaties

1

No estoy seguro, pero creo que tiene que ver con el concepto "nombre vs. sustantivo".

Básicamente, si coloca el tipo primero (como "int varname"), está declarando un "entero llamado 'varname'"; es decir, le está dando un nombre a una instancia de un tipo. Sin embargo, si coloca el nombre primero, y luego el tipo (como "varname: int"), está diciendo "esto es 'varname'; es un número entero". En el primer caso, le está dando a una instancia de algo un nombre; en el segundo, estás definiendo un sustantivo y diciendo que es una instancia de algo.

Es un poco como si estuvieras definiendo una mesa como un mueble; decir "esto es muebles y lo llamo 'mesa'" (tipo primero) es diferente de decir "una mesa es un tipo de mobiliario" (tipo último).

0

Poner el tipo primero ayuda en el análisis. Por ejemplo, en C, si se declaran las variables como

x int; 

al analizar sólo el x, entonces usted no sabe si x es una declaración o una expresión. Por el contrario, la

int x; 

Al analizar el int, sabes que estás en una declaración (tipos comienzan siempre una declaración de algún tipo).

Dado el progreso en el análisis de idiomas, esta ligera ayuda no es terriblemente útil hoy en día.

+1

Si su objetivo es la facilidad de análisis, tendría una palabra clave que presenta todas las declaraciones de variables, como var: 'var i: int' o' var int i' – jmucchiello

+0

Y para los tipos definidos por el usuario (typedefs): xyz abc; - ¿Cuál es el tipo y cuál es el nombre? Mientras el lenguaje acepte las reglas, no hay ningún problema, y ​​si el lenguaje no puede ponerse de acuerdo sobre las reglas, probablemente no sea analizable. –

-3

¿Qué hay de dinámicamente (cheers @wcoenen) typed languages? Solo usa la variable.

+8

Te refieres a "tipeado dinámicamente". "débilmente contra fuertemente tipado" no es la misma distinción que "estático frente a tipeado dinámicamente". Por ejemplo, python es un lenguaje de tipado dinámico y fuerte: http://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language –

+0

Lenguajes débilmente tipados como awk o (viejo) Perl; o Fortran con sus variables tipadas implícitamente; los nombres que comienzan con I hasta N son enteros; el resto es REAL. –

7

Si el nombre de la variable comienza en la columna 0, es más fácil encontrar el nombre de la variable.

Compare

QHash<QString, QPair<int, QString> > hash; 

y

hash : QHash<QString, QPair<int, QString> >; 

Ahora imagínese cuánto más fácil de leer podría ser su cabecera ++ típica C.

+0

El nombre +1 primero es más fácil de leer, te muestra en qué está actuando la afirmación de inmediato ... suponiendo, por supuesto, que estás utilizando nombres de variables significativos. – bobince

6

En la teoría del lenguaje formal y la teoría de tipos, casi siempre se escribe como var: type. Por ejemplo, en el cálculo lambda escrito verá pruebas que contiene afirmaciones como:

x : A y : B 
------------- 
\x.y : A->B 

No creo que lo que realmente importa, pero me parece que son dos justificaciones: una es que "x: Un" se lee "x es de tipo A", el otro es que un tipo es como un conjunto (por ejemplo, int es el conjunto de enteros), y la notación está relacionada con "x ε A".

Algunas de estas cosas son anteriores a los idiomas modernos que estás pensando.

8

Una tendencia creciente es no indicar el tipo en absoluto, u opcionalmente indicar el tipo. Esto podría ser un lenguaje tipado dinámicamente donde realmente no hay ningún tipo de letra en la variable, o podría ser un lenguaje estáticamente tipado que infiere el tipo del contexto.

Si el tipo a veces se da y algunas veces se deduce, entonces es más fácil de leer si el bit opcional viene después.

También hay tendencias relacionadas con si un idioma se considera procedente de la escuela C o la escuela funcional o lo que sea, pero estos son una pérdida de tiempo. Los idiomas que mejoran a sus predecesores y que vale la pena aprender son los que están dispuestos a aceptar la opinión de todas las escuelas diferentes en función del mérito, y no ser exigentes con el patrimonio de una característica.

0

Fortran pone el primer tipo:

REAL*4 I,J,K 
INTEGER*4 A,B,C 

Y sí, hay un (muy débil) broma allí para aquellos familiarizados con Fortran.

Hay espacio para argumentar que esto es más fácil que C, que coloca la información de tipo alrededor del nombre cuando el tipo es lo suficientemente complejo (punteros a funciones, por ejemplo).

+0

Has inventado ofuscar FORTRAN. Bien hecho. – jmucchiello

1

Siempre pensé que la manera en que C lo hace era algo peculiar: en lugar de construir tipos, el usuario tiene que declararlos implícitamente. No es solo antes/después del nombre de la variable; en general, es posible que necesite incrustar el nombre de la variable entre los atributos de tipo (o, de alguna forma, incrustar un espacio vacío donde sería ser si realmente estuviera declarando uno).

Como una forma débil de emparejamiento de patrones, es inteligible hasta cierto punto, pero tampoco parece proporcionar ninguna ventaja particular. Y, tratar de escribir (o leer) un tipo de puntero a función puede llevarlo fácilmente más allá del punto de inteligibilidad fácil. Entonces, en general, este aspecto de C es una desventaja, y me alegra ver que Go lo ha dejado atrás.

4

"Aquellos que no recuerdan el pasado están condenados a repetirlo".

Colocar el tipo antes de que la variable comenzara de manera bastante inofensiva con Fortran y Algol, pero se volvió realmente feo en C, donde algunos modificadores de tipo se aplican antes que la variable, otros después. Es por eso que en C que tiene bellezas tales como

int (*p)[10]; 

o

void (*signal(int x, void (*f)(int)))(int) 

junto con una utilidad (cdecl) cuyo propósito es descifrar tal galimatías.

En Pascal, el tipo viene después de la variable, por lo que los primeros ejemplos se convierte

p: pointer to array[10] of int 

contraste con

q: array[10] of pointer to int 

que, en C, es

int *q[10] 

En C , necesita paréntesis para distinguir esto de int (* p) [10]. No se requieren paréntesis en Pascal, donde solo importa el orden.

La función de señal sería

signal: function(x: int, f: function(int) to void) to (function(int) to void) 

Todavía un bocado, pero al menos en el ámbito de la comprensión humana.

Para ser justos, el problema no es que C coloque los tipos antes del nombre, sino que insiste perversamente en poner partes antes y después, el nombre.

Pero si se intenta poner todo antes del nombre, el orden es todavía poco intuitivo:

int [10] a // an int, ahem, ten of them, called a 
int [10]* a // an int, no wait, ten, actually a pointer thereto, called a 

Por lo tanto, la respuesta es: Un lenguaje de programación con sensatez diseñada pone las variables antes de que los tipos ya que el resultado es más legible para humanos

Cuestiones relacionadas