Variables de Perl - Detrás de las Cortinas
por
No es un secreto lo fácil que es usar las variables en Perl, y lo comprobamos al usarlas día con día, y esto sin saber como funcionan realmente y lo que sucede detrás de las cortinas.
En mi travesía por el lenguaje Java me he dado cuenta de lo diferente que funcionan ambos lenguajes en el uso de variables. Por ejemplo, en Java cuando queremos inicializar una variable debemos de especificar el tipo de contenido que va a tener la variable, y en base a esa información el compilador decide como crear la variable y alojarla en memoria.
Cuando en perl hacemos:
my $num = 24;
my $float = 12.5;
En Java debemos de hacer:
int num = 24;
float f = 12.5;
Vemos como en Perl inicializamos las variables de la misma manera sin importar el tipo de valor que puedan contener. Este no es el caso con Java, en el caso de querer tener una variable cuyo contenido son números enteros usamos un int (interger), en el caso de querer un número con punto decimal tenemos que usar otro tipo de variable.
En perl nuestras variables pueden incrementar de tamaño sin problema (siempre y cuando tengamos memoria suficiente). En Java cada variable tiene un tamaño específico que no se puede superar, de lo contrario debes de usar una variable distinta. Por ejemplo en Java no se puede hacer:
int num = 1000000000000000000000;
También existe lo que se llama el cast. Hacemos cast cuando queremos que se maneje un tipo de dato como otra cosa.
Por ejemplo cuando queremos que un número sea tratado como una cadena y no como un número integral, o cuando queremos que un número integral sea un número decimal o double. Esto en Perl nos tiene sin cuidado, pues el propio interprete hace el cast automáticamente detrás de las cortinas sin que nosotros tengamos que mover un dedo:
my $num = 24;
my $palabra = "Hola";
my $juntos = $num . $palabra;
Aquí lo que hace nuestro interprete es hacer un "cast" es decir dejar de tratar el valor 24 como un número y empezar a tratarlo como una cadena "24" para juntar las dos variables de manera correcta. En otros lenguajes esta operación crearía un error y se pediría que primero se haga el cast de $num.
Para este momento ya estaba maravillado por lo fácil y poderoso que es perl. Pero vino a mi mente la pregunta ¿cómo le hace perl?
¿Cómo le hace perl para crear variables cuyo tamaño no conoce sin consumir montones de memoria? ¿Cómo le hace perl para manejar variables sin importar el valor dentro de ellas?
Estructura Básica de una variable
La estructura de una variable de perl es realmente sencilla. Una variable de perl es más que su nombre y su valor, de hecho tiene datos que perl oculta a los usuarios (nosotros) y lo vamos a ver con una sencilla interpretación gráfica:
sv
+---------------+
| ANY |
+---------------+
| REFCOUNT |
+---------------+
| FLAGS | TYPE |
+---------------+
Así es como se ve un tipo de dato sin ningún valor(NULL), este es el tipo de variable más básico que hay en Perl e internamente es llamada SvNULL o simplemente Sv, por ejemplo:
my $x;
Como vemos, cada tipo de dato o variable en realidad tiene cuatro campos que la describen.
Cada campo tiene una función distinta:
- ANY Contiene un pointer a más datos. En este caso siempre va a ser NULL. Todos los subtipos de la variable se implementan adjuntando más datos a este pointer.
- REFCNT: Este campo contiene un número con la cantidad de pointers que hacen referencia a este objeto. Cuando una variable se inicializa el contador empieza en 1. El contador se incrementa cuando un nuevo pointer apunta hacía acá, y se decrementa cuando se destruye el pointer o se crea un nuevo valor. Si el contador llega a 0 el objeto es liberado.
- FLAGS: Este campo tiene espacio de 24 bits de flags(banderas). Vamos a ver más adelante los diferentes tipos de flags que existen.
- TYPE: Contiene un número dependiendo del tipo de variable que es.
Los tipos de variables
Internamente Perl nombra a sus tipos variables de la siguiente manera:
-SV (Scalar Value)
-AV (Array Value)
-HV (Hash Value)
Aparte tiene los siguiente tipos:
-IV (Interger Value)
-NV (Numeric Value)
-PV (Pointer Value)
-RV (Reference Value)
El NV es también conocido como un double. Y el PV es un string, en C estaría representado por (char[]).
Todas las variables o tipos de dato en Perl tienen ciertas reglas:
- Todos descienden de SvNULL también conocida como Sv, que tiene la estructura más simple, la cual vimos al principio.
- Todos tienen una jerarquía. De esta manera los puede compara Perl con el operador >=.
- Todos los objetos de tipos de dato vienen con un campo de FLAG incluido para saber más acerca del tipo de datos que contienen.
A continuación viene una imagen que muestra la jerarquía de los tipos de perl:
Como habíamos visto cada variable de Perl tiene un campo de TYPE que le indica que tipo de dato es. Este es el listado enumerando los tipos de datos que existen en Perl:
0) SVt_NULL
1) SVt_IV
2) SVt_NV
3) SVt_RV
4) SVt_PV
5) SVt_PVIV
6) SVt_PVNV
7) SVt_PVMG
8) SVt_PVBM
9) SVt_PVLV
10) SVt_PVAV
11) SVt_PVHV
12) SVt_PVCV
13) SVt_PVGV
14) SVt_PVFM
15) SVt_PVIO
Dentro de la lista podemos ver unos tipos de dato interesantes. Un valor SvPVIV puede contener un script y un número integral. Un SvPVNV puede contener un string, un número integral y un double.
El SvPVMG se usa cuando hay magia incluida o el valor ha sido bendecido(blessed). SvPVBM agrega información para una búsqueda rápida (Boyer-Moore) en las cadenas. El SvPVLV contiene un objeto LValue. CV es un valor de código que representa una función, subrutina, cierre o contiene un pointer a un XSUB. GV es un valor global y IO contiene un pointer a archivos abiertos y directorios con diferente tipo de información. Finalmente el SvPVFM es usado para contener información de formas.
Una variable de perl puede cambiar de tipo dependiendo del valor que contenga, en este caso se dice que el tipo es patrocinado, es decir sube de rango en la jerarquía de los tipos de dato. Solamente se pueden cambiar el tipo de la variable yendo hacía abajo de la jerarquía.
Los Flags
Otro de los campos que existen por cada variable es el campo de FLAG. Este campo da más información acerca del tipo de contenido que tiene la variable. Los FLAGS al igual que los TYPES son representados por números integrales, y son los siguientes:
0) PADBUSY
Reservado para my o tmp
1) PADTMP
En uso como tmp
2) PADMY
En uso como variable "my"
3) TEMP
La cadena puede ser robada.
4) OBJECT
Esta bandera es accionada cuando un objeto es bendecido(blessed).
5) GMAGICAL (Get Magic)
Esta bandera indica que el objeto tiene un get o len mágico a ser invocado.
6) SMAGICAL (Set Magic)
Este objeto tiene un set mágico a ser llamado.
7) RMAGICAL (Random Magic)
Indica que el objeto tiene otro método mágico distinto a los anteriores (get len set).
Cualquiera GMAGICAL, SMAGICAL o RMAGICAL es llamado MAGICAL
8) IOK (Integer OK)
Indica que el objeto tiene un campo IVX correcto. Solo puede ser usado en valores tipo SvIV o sus subtipos.
9) NOK (Numeric OK)
Indica que el objeto tiene un campo NVX correcto. Solo puede ser usado en valores tipo SvNV o sus subtipos.
10) POK (Pointer OK)
Indica que el objeto tiene un PVX, CUR o LEN válido. Sólo puede ser usado con valores tipo SvPV.
11) ROK (Reference OK)
Indica que el valor debe de ser tratado como un SvRV y que el campo RV contiene una referencia a una pointer válido.
12) FAKE
glob o léxica sólo para copia
13) OOK (Offset OK)
Indica que el valor IVX debe de ser interpretado como una cadena. Solo puede ser usado en valores de tipo SvPVIV o sus subtipos.
14) BREAK
refcnt está bajo artificialmente
15) READONLY
Indica que el valor del objeto no puede ser modificado.
16) IOKp (Integer OK Private)
Indica que tiene un valor no público integral válido.
17) NOKp (Numeric OK Private)
Indica que tiene un valor no público double válido.
18) POKp (Pointer OK Private)
Indica que tiene un valor no público pointer válido.
19) SCREAM
20) AMAGIC
Tiene métodos mágicos
21) SHAREKEYS
22) LAZYDEL
22) TAIL
23) VALID
23) COMPILED
Estructura SvPV
Todas las variables o tipo de dato de Perl derivan de SvNULL que es la representación más sencilla de una variable y que vimos al principio. De la estructura SvNULL(conocida también simplemente como Sv) vimos más a fondo los campos TYPE y FLAG, ahora vamos a ver el campo ANY.
El campo ANY se compone a su vez de otros campos que dependen del tipo de dato que sea. Para entender más esto, ahora vamos a ver como es la estructura de una variable tipo SvPV. Si recordamos lo que significan las letras, sabremos que Sv significa String Value y PV corresponde a Pointer Value. En pocas palabras vamos a ver la estructura de una cadena.
Digamos que creamos una variable x que contiene todas las letras del abecedario:
my $x = "abcdefghijklmnopqrstuvwxyz";
Al crear la variable en realidad se esta creando una estructura similar a la mostrada en la gráfica:
Este tipo de variable adjunta tres campos al campo ANY de SvNULL. En donde PVX contiene un pointer a un array de char asignado (char[]). CUR es una integral con el tamaño actual de la cadena. Y LEN es una integral con el tamaño actual de la cadena asignada. LEN toma en cuenta el \0 al final de la cadena para un correcto funcionamiento cuando se están llamando rutinas de la librería de C.
Como vemos al campo ANY se le adhieren los campos necesarios para contener información correspondiente a cada tipo de dato.
Estructura SvPVIV y SvPVNV
Vamos a ver otro par de estructuras más para comprender un poco más a fondo. El tipo de dato SvPVIV es similar al anterior SvPV pero agrega un campo más al campo ANY de SvNULL para contener un número integral llamado IVX.
Si el valor de IVX es correcto la bandera IOK es accionada(recordemos la lista de FLAGS que vimos anteriormente). En el caso de que estén activadas las banderas IOK y POK entonces PVX "normalmente" sería una representación en cadena del valor en IVX.
El valor SvPVNV es como el SvPVIV pero contiene un campo más para contener un valor double llamado NVX. La bandera NOK es accionada.
Estructura SvRV
Si has comprendido hasta ahorita como funcionan las variables en perl, te será muy sencillo suponer como funciona una referencia a otra variable.
El tipo SvRV hace que el campo ANY de SvNULL apunte a otro SvNULL y todos sus subtipos. En el caso que este tipo de dato tenga accionada la bandera ROK, entonces significa que tiene un valor no definido.
Últimas Palabras
Desde la primera vez que leí acerca de como funcionaban los tipos de datos o variables en perl, quedé maravillado por la sencillez y total lógica que tiene esto. Es bastante información, pero no necesitas ser un genio para comprender como funciona, así de sencillo es. Y se nos hace aún más sencillo pues todo esto está oculto para nosotros, todo lo que tenemos que hacer es crear una variable y hacer lo que queramos con ella, Perl se encarga de lo demás.
Sin embargo este pequeño artículo no es más que una pequeña miradita a los que pasa detrás de las cortinas de las variables en perl. En este artículo no se trataron variables más complejas como son los arreglos y los arreglos asociativos, tampoco se vio la mayor parte de los Sv. Pero creo que es suficiente para que tengamos una idea clara de lo que sucede cuando usamos nuestras variables.
Bibliografía
PerlGuts Illustrated
http://gisle.aas.no/perl/illguts/
Pure Perl Internals (with Pure Perl Segfaults)
http://perlmonks.org/?node_id=335993
Behind the Scenes - Perl Variables
http://perlmonks.org/?node_id=449384
Las imágenes que representan los tipos de variables fueron tomadas de (http://gisle.aas.no/perl/illguts/) y pertenecen a Gisle Aas.
|
¿Quiéres más tutoriales como este? Escribir tutoriales toma una gran cantidad de tiempo y esfuerzo. Si este tutorial te ayudó a aprender o a solucionar algo, por favor considera dejar alguna donación en apoyo a Perl en Español.
Cliquea en el botón de abajo para dejar tu donación por medio de PayPal.
|
|