versión 2003 (Modificado)
Tipos de variables
4D tiene tres categorías de variables:
Variables locales,
Variables proceso,
Variables interproceso.
Para mayor información sobre este punto, consulte la sección Variables. Las variables proceso e interproceso son estructuralmente de la misma naturaleza del compilador.
Como el compilador no puede determinar el proceso en el cual la variable será utilizada, las variables proceso deben utilizarse con más cuidado que las variables interproceso. Todas las variables proceso se duplican sistemáticamente cuando comienza un nuevo proceso. Una variable proceso puede tener un valor diferente en cada proceso, pero tiene el mismo tipo en toda la base.
Tipos de variables
Todas las variables tienen un tipo. Como se describe en la sección Tipos de datos, hay 12 tipos diferentes de variables:
Booleano
Alfanumérico (o cadena fija)
Fecha
Entero
Entero largo
Gráfico
Hora
Imagen
Número (o Real)
Puntero
Texto
BLOB
Hay nueve tipos diferentes de arrays:
Array Booleano
Array Alfa
Array Fecha
Array Entero
Array Entero largo
Array Imagen
Array Real
Array Puntero
Array Texto
Creación de la tabla de símbolos
En modo interpretado, una variable puede tener más de un tipo de datos. Esto es posible porque el código es interpretado en lugar de compilado. 4D interpreta cada instrucción por separado y comprende su contexto. Cuando trabaja en modo compilado, la situación es diferente. Mientras la interpretación se realiza línea por línea, el proceso de compilación mira a una base en su globalidad.
La manera de operar el compilador es la siguiente:
El compilador analiza sistemáticamente los objetos en la base. Los objetos son los métodos base, proyecto, formulario, trigger y objeto.
El compilador escanea los objetos para determinar el tipo de dato de cada variable utilizada en la base y genera la tabla de variables y métodos (la tabla símbolo).
Una vez establecidos los tipos de datos de todas las variables, el compilador traduce (compila) la base. Sin embargo, no puede compilar la base a menos que pueda determinar el tipo de dato de cada variable.
Si el compilador encuentra el mismo nombre de variable en dos tipos diferentes de datos, no tiene ninguna razón para favorecer a uno de ellos. En otras palabras, para clasificar un objeto y darle una dirección de memoria, el compilador debe saber la identidad precisa del objeto (es decir, su nombre y su tipo). El tipo le permite al compilador determinar el tamaño. Para cada base compilada, el compilador crea un mapa que lista, para cada variable, su nombre (o identificador), su ubicación (o dirección de memoria), y el espacio que ocupa (indicado por su tipo). Este mapa se llama la tabla de símbolos. Una opción en las preferencias le permite generar o no esta tabla en forma de archivo durante la compilación.
Este mapa también se utiliza para la generación automática de métodos compilador.
Dar tipo a las variables
El compilador debe respetar el criterio de identificación de las variables.
Hay dos posibilidades:
Si la variable no tiene tipo, el compilador se ocupará de eso automáticamente. Siempre que sea posible siempre y cuando no haya ambigüedadel compilador determina un tipo de variable dependiendo de su uso. Por ejemplo, si escribe:
V1 := True
el compilador determina que la variable V1 es de tipo booleano.
De la misma forma, si escribe:
V2:= "Esta es una frase de ejemplo"
el compilador determina que V2 es una variable de tipo texto.
El compilador también es capaz de establecer el tipo de dato de una variable en casos menos fáciles:
V3:= V1 `V3 es del mismo tipo que V1 V4:= 2*V2 `V4 es del mismo tipo que V2
El compilador también determina el tipo de datos de sus variables de acuerdo a los llamados a los comandos 4D y a sus métodos. Por ejemplo si pasa un parámetro tipo booleano y un parámetro tipo fecha a un método, el compilador asigna el tipo booleano y el tipo fecha a las variables locales $1 y $2 del método llamado.
Cuando el compilador determina el tipo de dato por deducción, a menos de que se indique de otra forma en las Preferencias, nunca asigna tipos limitantes: Entero, Entero largo o Alfanumérico. Por defecto, el compilador asigna el tipo de dato más amplio posible. Por ejemplo, si escribe:
Número:=4
el compilador asigna el tipo de dato Real, aunque 4 sea un entero. En otras palabras, el compilador no descarta la posibilidad de que, bajo otras circunstancias, el valor de la variable pueda ser 4.5.
Si es conveniente darle a una variable un tipo Entero, Entero largo, o Alfa, puede hacer utilizando una directiva de compilación. Es una ventaja hacerlo, porque estos tipos de datos ocupan menos memoría y es mucho más rápido efectuar operaciones en ellos.
Si usted ya ha asignado un tipo a sus variables y está seguro de que su tipo coherente y completo, puede pedirle explícitamente al compilador no hacer nuevamente este trabajo, utilizando las Preferencias de compilación. En caso de que los tipos que asignó no estén completos, al momento de la compilación, el compilador devolverá errores solicitándole hacer las modificaciones necesarias.
Los comandos de las directivas de compilación le permiten declarar explícitamente las variables utilizadas en sus base.
Se utilizan de la manera siguiente:
C_BOOLEAN(Var)
A través de tales directivas, usted le dice al compilador que cree una variable Var que será de tipo Booleano.
Cuando una aplicación incluye directivas de compilación, el compilador las detecta y evita hacer conjeturas.
Una directiva de compilación tiene prioridad sobre una deducción hecha de una asignación o uso.
Las variables declaradas por la directiva de compilación C_INTEGER en realidad son iguales a las declaradas por la directiva C_LONGINT. De hecho son enteros largos entre 2147483648 y +2147483647.
¿Cuándo utilizar directivas de compilación? ______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Las directivas de compilación son útiles en dos casos:
cuando el compilador no puede determinar el tipo de dato de una variable por su contexto,
cuando usted no quiere que el compilador determine el tipo de la variable por su uso.
Adicionalmente, utilizar directivas de compilación le permite reducir el tiempo de compilación.
Casos de ambigüedad
Algunas veces el compilador no puede determinar el tipo de dato de una variable y genera un mensaje de error.
Hay tres causas principales que pueden evitar que el compilador determine el tipo de dato: tipos de datos múltiples, ambigüedad sobre una deducción forzada y la imposibilidad de determinar un tipo.
Tipos de datos múltiples
Si una variable tiene diferentes tipos en diferentes instrucciones en la base, el compilador genera un error que es fácil de solucionar.
El compilador selecciona la primera variable que encuentra y le asigna su tipo de dato a la siguiente ocurrencia de la variable con el mismo nombre pero un tipo diferente.
Este es un ejemplo sencillo:
en un método A,
Variable:=True
en un método B,
Variable:="La luna es verde"
Si el método A se compila antes que el método B, el compilador considera que Variable:="La luna es verde" es un cambio de tipo de una variable encontrada anteriormente. El compilador le notifica que ha ocurrido un cambio de tipo. Esto genera un error que debe corregir. En la mayoría de los casos, el problema puede solucionarse renombrando la segunda ocurrencia de la variable.
Ambigüedad sobre una deducción forzada
Algunas veces, por una secuencia, el compilador puede deducir que un tipo de objeto no es el apropiado. En este caso, usted debe explícitamente darle tipo a la variable con una directiva de compilación.
Este es un ejemplo utilizando los valores por defecto para un objeto activo:
En un formulario, puede asignar valores por defecto para los siguientes objetos: combo boxes, pestañas, listas y menús desplegables y áreas de desplazamiento utilizando el botón de edición de Valores por defecto (en el tema Fuente de datos de la Lista de propiedades) (para mayor información, consulte el Manual de Diseño). Los valores por defecto se cargan automáticamente en un Array cuyo nombre es el mismo del objeto.
Si el objeto no se utiliza en un método, el compilador puede deducir el tipo, sin ambigüedad, como un array de texto.
Sin embargo, si se debe efectuar una inicialización, la secuencia podría ser:
Case of : (Form event=On Load) MiPopUp:=2 ... End case
En este caso, aparece la ambigüedaddurante el análisis de los métodos, el compilador deducirá un tipo de dato Real para el objeto MiPopUp. En este caso, es necesario declarar explícitamente el Array en el método de formulario o en un método compilador:
Case of : (Form event=On Load) ARRAY TEXT(MiPopUp;2) MiPopUp:=2 ... End case
Imposibilidad para determinar un tipo
Este caso puede surgir cuando una variable se utiliza sin haber sido declarada, en un contexto que no ofrece información sobre su tipo. En este caso, sólo una directiva de compilación puede guiar el compilador.
Este fenómeno ocurre principalmente en cuatro contextos:
- cuando utiliza punteros,
- cuando utiliza un comando con más de una sintaxis,
- cuando utiliza un comando con parámetros opcionales de diferentes tipos de datos,
- cuando utiliza un método 4D llamado vía un URL.
- Punteros
No se puede esperar que un puntero devuelva un tipo diferente al propio.
Considere la siguiente secuencia:
Var1:=5.2 (1) Puntero:=->Var1 (2) Var2:=Puntero-> (3)
Aunque la línea (2) defina el tipo de variable apuntada por el puntero, el tipo de Var2 no se determina. En el momento de la compilación, el compilador puede reconocer un puntero, pero no tiene ningún medio de saber a que tipo de variable apunta. Por lo tanto no puede deducir el tipo de Var2. Se necesita una directiva de compilación, por ejemplo C_REAL(Var2).
- Comandos de sintaxis múltiple
Cuando utiliza una variable asociada con la función Year of, la variable sólo puede ser de tipo Fecha, considerando la naturaleza de esta función. Sin embargo, las cosas no siempre son simples. Este es un ejemplo:
El comando GET FIELD PROPERTIES acepta dos sintaxis:
GET FIELD PROPERTIES(tablaNo;campoNo;Tipo;longitud;indice)
GET FIELD PROPERTIES(campoPuntero;Tipo;longitud;indice)
Cuando utiliza un comando de sintaxis múltiple, el compilador no puede adivinar la sintaxis y los comandos que usted escogío. Debe utilizar directivas de compilación para darle un tipo a las variables que se pasan al comando, si no tienen un tipo de acuerdo a su uso en la base.
- Comandos con parámetros opcionales de diferentes tipos
Cuando utiliza un comando que contiene varios parámetros opcionales de diferentes tipos, el compilador no puede determinar cuáles parámetros opcionales han sido utilizados. Este es un ejemplo:
El comando GET LIST ITEM acepta dos parámetros opcionales; el primero es de tipo Entero largo y el segundo de tipo Booleano.
El comando puede ser utilizado:
GET LIST ITEM(lista;posición;itemRef;texto;sublista;expandido)
o como:
GET LIST ITEM(lista;posición;itemRef;texto;expandido)
Debe utilizar directivas de compilación para dar tipo a los parámetros opcionales pasados al comando, si no tienen tipos de acuerdo a su uso en la base.
- Métodos llamados vía URLs
Si usted escribe métodos 4D que deben ser llamados vía un URL, y si usted no utiliza $1 en el método, debe declarar explícitamente la variable texto $1 con la siguiente secuencia:
C_TEXT($1)
De hecho, el compilador no puede determinar que el método 4D será llamado vía un URL.
Reducción de tiempos de compilación
Si todas las variables utilizadas en la base se declaran explícitamente, no es necesario que el compilador revise los tipos. En este caso, puede fijar las opciones de manera que el compilador sólo ejecute la fase de traducción del método. Esto ahorra por lo menos el 50% del tiempo de compilación.
Código de optimización
Usted puede acelerar sus métodos utilizando directivas de compilación. Para mayor información al respecto, consulte la sección Consejos de optimización . Para dar un ejemplo simple, imagine que necesita incrementar un contador utilizando una variable local. Si no declara la variable, el compilador asume que es de tipo Real. Si la declara como de tipo Entero largo, la ejecución de la base compilada será más eficiente. En un PC, por ejemplo, un Real ocupa 8 bytes, mientras que el tipo Entero largo, sólo utiliza 4 bytes. Incrementar un contador de 8 bytes obviamene toma más tiempo que aumentar un contador de 4 bytes.
¿Dónde ubicar sus directivas de compilación?
Las directivas de compilación se pueden manejar de dos formas diferentes, dependiendo de si quiere que el compilador verifique o no los tipos de sus variables.
Variables declaradas por el compilador
Si quiere que el compilador verifique los tipos de sus variables o que declare las variables él mismo, es fácil colocar una directiva de compilación para este propósito. Puede elegir entre dos posibilidades diferentes, dependiendo de sus métodos de trabajo:
Utilice la directiva en el método en el cual aparece la variable por primera vez, dependiendo si es una variable local, proceso o interproceso. Asegúrese de utilizar la directiva la primera vez que utilice la variable, en el primer método a ejecutar. Recuerde que durante la compilación, el compilador toma los métodos en el orden de su creación en 4D, y no en el orden en el cual aparecen en el Explorador.
O, si usted es sistemático, agrupe todos las variables proceso e interproceso con las diferentes directivas de compilación en el Método base On Startup o en un me´todo llamado por el Método de base de datpos On Startup.
Para las variables locales, agrupe las directivas al comienzo del método en el cual aparecen.
Variables declaradas por el desarrollador
Si no quiere que el compilador revise los tipos, debe darle un código para identificar las directivas de compilación.
La convención es la siguiente:
Las directivas de compilación de las variables proceso e interproceso y los parámetros deben ubicarse en uno o más métodos, cuyos nombres comiencen con la palabra clave Compiler.
Por defecto, el compilador le permite generar automáticamente cinco tipos de métodos Compiler, los cuales agrupan la directivas para las variables, arrays y los parámetros de los métodos (para mayor información sobre este punto, consulte el Manual de Diseño).
Nota: La sintaxis para la declaración de estos parámetros es:
Directiva (nombreMétodo;Parámetro). Esta sintaxis no es ejecutable en modo interpretado.
Parámetros particulares
Los parámetros recibidos por los métodos base
Si estos parámetros no han sido declarados explícitamente, son declarados por el compilador. Sin embargo, si los declara, la declaración se debe hacer dentro de los métodos de base de datos.
La declaración de estos parámetros no puede hacerse en un método compilador.
Ejemplo: Método de base de datos On Web Connection recibe seis parámetros, $1 a $6, de tipo texto. Al comienzo del método, debe escribir: C_TEXT($1;$2;$3;$4;$5;$6)
Triggers
El parámetro $0 (Entero largo), es el resultado de un trigger, es declarado por el compilador el parámetro no ha sido declarado explícitamente. Sin embargo, si quiere declararlo, debe hacerlo en el trigger.
La declaración de este parámetro no puede hacerse en un método compilador.
Los objetos aceptan el evento de formulario "On Drag Over"
El parámetro $0 (Entero largo), es el resultado de un evento de formulario "On Drag Over", es declarado por el compilador si el parámetro no ha sido declarado explícitamente. Sin embargo, si quiere declararlo, debe hacerlo en el método de objeto.
La declaración de este parámetro no puede escribirse en un método compilador.
Nota: El compilador no inicializa el parámetro $0. De manera que tan pronto utilice el evento de formulario On Drag Over, debe inicializar $0. Por ejemplo:
C_LONGINT($0) If (Form event=On Drag Over) $0:=0 ... If ($DataType=Is Picture) $0:=-1 End if ... End if
La directiva de compilación C_STRING
el comando C_STRING utiliza una sintaxis diferente que las otras directivas porque acepta un parámetro adicional la longitud máxima de la cadena.
C_STRING(longitud;var1{;var2; ;varN})
Como C_STRING declara cadenas de longitud fija, usted especifica la longitud máxima de las cadenas. En una base compilada, debe especificar la longitud de la cadena con una constante en vez de una variable.
En una base interpretada, se acepta la siguiente secuencia:
LaLongitud:=15 C_STRING(LaLongitud;LaCadena)
4D interpreta LaLongitud, luego reemplaza LaLongitud por su valor en la directiva de compilación C_STRING.
Sin embargo, el compilador utiliza este comando durante la declaración de las variables sin asignación especifica. El compilador no puede saber que LaLongitud es igual a 15. Sin conocer la longitud de la cadena, el compilador no puede reservar espacio en la tabla de símbolos. Por lo tanto, pensando en la compilación, utilice una constante para especificar la longitud de la cadena de caracteres declarada. Por ejemplo, utilice una declaración como esta:
C_STRING(15;LaCadena)
La misma regla aplica para declarar arrays de tipo alfa, declarados con el comando:
ARRAY STRING(longitud;nombreArray;tamaño)
El parámetro que indica la longitud de las cadenas en el array debe ser una constante.
Sin embargo, puede especificar la longitud de la cadena con una constante 4D o un valor hexadecimal en estas dos directivas de compilación. Por ejemplo:
C_STRING(Constante4d;LaCadena) ARRAY STRING(Constante4d;ElArray;2) C_STRING(0x000A;LaCadena) ARRAY STRING(0x000A;ElArray;2)
No confunda la longitud de un campo alfanumérico, que tiene un máximo de 80 caracteres, con una variable alfa fija. La máxima longitud de una cadena declarada por la directiva C_STRING, o que pertenezca a ARRAY STRING, está entre 1 y 255.
Nota: La sintaxis de este comando le permite declarar muchas variables de la misma longitud en una sola línea. Si quiere declarar varias cadenas de longitud diferente, hágalo en líneas separadas.
Una libertad permitida por el compilador
Las directivas de compilación eliminan toda ambigüedad sobre los tipos y en el caso de las cadenas alfanuméricas, sobre las longitudes. Aunque es necesario cierto rigor, eso no significa que el compilador no sea tolerante con cualquier inconsistencia.
Por ejemplo, si asigna un valor real a una variable declarada como de tipo Entero, o si asigna una cadena de 30 caracteres a una variable declarada como una cadena de 10 caracteres, el compilador no considera que haya un conflicto de tipo y asigna los valores correspondientes de acuerdo a sus directivas. De manera que si escribe:
C_INTEGER(vEntero) vEntero:=2.5
El compilador no verá esto como un conflicto de datos que impida la compilación; el compilador simplemente redondeará al valor entero más cercano (3 en lugar de 2.5).
Del mismo modo, si declara una cadena más corta que la cadena con la que está trabajando, el compilador sólo tomará el número de caracteres declarado en las directivas. Por lo tanto, en la siguiente secuencia:
C_STRING(8;MiCadena) MiCadena:="Es un día hermoso"
el compilador toma los primeros ocho caracteres de la constante, es decir "Es un dí".
Ver también
Consejos de optimización , Detalles de sintaxis, Guía de declaración, Mensajes de error .