Ir al contenido principal

Punteros y referencias

 PseudoD hace énfasis en las diferencias entre punteros y referencias. Este articulo esta dedicado a mostrar y explicar estas diferencias (incluye ejemplos).

Para comenzar, vamos a asumir que al inicio de todos los ejemplos de ejecutó el siguiente código:

adquirir variable1
adquirir variable2
adquirir variable3

¿Muy sencillo no? luego de esto, la memoria de PseudoD queda similar a:
Memoria después de tres adquisiciones de memoria
Claro, esto es ignorando las variables de la BEPD y del núcleo las cuales, en PseudoD 1.9.5 (no probado en versiones recientes) eran de, aproximadamente, ~526 bloques (esto incluyendo toda la BEPD, nosotros solo utilizaremos lo autoincluido).


Primero: ¿Que es un puntero?

Un puntero (sección no-normativa, válida solo en PseudoD) es un bloque de memoria que en vez de poseer un valor propio (como variable1 posee {Hola} en la imagen superior) posee un índice de acceso rápido a otra variable, por ende, cada vez que se acceda al puntero realmente se estará accediendo al valor apuntado.

Los punteros son más rápidos de desreferenciar que las referencias, por el hecho de que esta tarea es realizada por el núcleo, no por la BEPD. Además, requiere menos niveles de recursión y es más eficiente.

Ahora: ¿Que es una referencia?

Una referencia es una variable común que en vez de una valor (como {Hola}) posee el nombre de otra variable, así, cuando se intente acceder a esta, la BEPD busca realmente la variable contenida en su valor.

 Comparación de eficiencia y algoritmos

Los punteros no son tan intuitivos como las referencias, pero son mucho más rapidos y eficientes:

El algoritmo para  desreferenciar un puntero es (implementado oficialmente en C++) :
  •  Sea indice el resultado de ejecutar una búsqueda en reversa sobre las variables.
  • De ser indice menor a cero (0): 
    • Sea indice el resultado de ejecutar una búsqueda en reversa sobre los punteros.
    • Sea ptr el valor del puntero número indice
    •  Retorna la variable número ptr
  •  En otro caso, lanzar un error (es una variable, no un puntero)
Claro, el algoritmo esta minimizado, eliminando la doble verificación y otros aspectos. Este algoritmo es principalmente iterativo y es de complejidad O(n + m) donde n es la cantidad de variables y m la de punteros (en el peor caso).

El algoritmo para desreferenciar una referencia es (implementado oficialmente en PseudoD):
  • Sea resultado la cadena vacia
  • Sea eval la cadena {fijar resultado a }
  • Concatena al final de eval el contenido de la referencia
  • Ejecuta la cadena eval 
  • Devuelve resultado
Aunque a simple vista no se vea recursivo, los pasos tomados por PseudoD son (PseudoCódigo):
Función DesReferenciar_Referencia(string nombre)
{
    Reserva resultado como un string;
    Reserva cadena como un string;
    Fijar cadena A {fijar resultado a };
    Fijar cadena Al resultado de concatenar cadena y nombre;
    Ejecutar cadena;
    Devolver resultado;
}
Esto requiere al menos 3 niveles de recursión (2 en nuevas versiones):
  1.  Dentro de DesReferenciar_Referencia, en la sentencia ejecutar
  2.  Dentro de la sentencia ejecutar, en la sentencia fijar
  3. Dentro de la sentencia fijar, en el evaluador de valores
 Esto hace a las referencias, más lentas. Lamentablemente, hasta ahora (PseudoD v2.1.0) no posee una forma de hacer a los punteros más intuitivos, siendo esta delegada a PseudoD v2.2.0 o, posiblemente a PseudoD v3.0.0.

Algunos ejemplos

Algunos ejemplos de usos son:


utilizar tipos.pseudo [ Para poder utilizar la clase Referencia ]
utilizar entsal.pseudo [ Para poder utilizar Escribir e Imprimir ]

adquirir persona

instancia Referencia refPersona
instancia PunteroInteligente ptrPersona [ Viene en builtins.pseudo, no necesitamos incluir nada :) ]

fijar refPersona#ref a persona#NOMBRE [ Apuntamos la referencia ]
llamar ptrPersona#apuntar persona finargs [ Apuntamos el puntero ]

llamar Imprimir
    {La referencia es:}
    llamar refPersona#obtenerValor finargs
    {y el puntero es:}
    ptrPersona#direccion
finargs
Las respectivas clases Referencia y PunteroInteligente son envolturas para los punteros y las referencias.

 Acorde a

PseudoD v.2.2.0 [En desarrollo] - Soporte de desreferenciado por almohadillas.
PseudoD v2.1.0 - Última versión estable de PseudoD (2016/08/16).
PseudoD v1.9.5 - Primera versión en poseer la clase Referencia.
PseudoD v1.0.0 - Primera versión en soportar punteros.

Comentarios

Entradas más populares de este blog

Futuro PseudoD 2.2.0

La futura versión de PseudoD, PseudoD 2.2.0 tendrá cambios fundamentales en la estructura del lenguaje, más estos cambios serán compatibles con versiones anteriores, de manera que no romperán con la estructura de ningún programa existente. Los cambios son: Resolución de nombres Ahora usar referencias es más cómodo que nunca con la resolución de nombres de PseudoD 2.2.0: adquirir var fijar var a {Hola Mundo} adquirir ref fijar ref a var#NOMBRE escribir <ref> Este código imprime en pantalla el texto "Hola Mundo". Mejor sintaxis para las clases y funciones clase Persona hereda Objeto implementa @Saludable atributo nombre puntero padre puntero madre metodo saludar finclase metodo Persona#saludar con yo y nombre escribir {Hola } escribir nombre escribir {, yo soy } escribir <yo>#nombre nl finmetodo Reestructuración de la BEPD parte 1/2 Ahora la BEPD posee una mejor estrucutra y nuevas funciones.

Paginas oficiales

Como primera entrada, voy a dejar una lista de enlaces a las páginas oficiales de PseudoD: http://www.pseudod.com : página oficial de PseudoD. http://www.pseudod.com/wiki/ : wiki oficial de PseudoD. http://www.pseudod.sourceforge.net/ : página de desarrolladores. http://www.sourceforge.net/p/pseudod : proyecto en sourceforge. http://www.github.com/alinarezrangel/pseudod : proyecto en github. En estas páginas se encuentra gran parte de la documentación del lenguaje.

Desreferenciación en línea

PseudoD 2.2.0 ahora incluye también un mecanismo llamado resolución de nombres , también conocido como desreferenciación en línea o nombres resueltos . Esta característica permite al desarrollador dejar de usar las molestas clases PunteroInteligente y Referencia , ahorrando tiempo y recursos para tareas más importantes. En resumen, ahora puedes resolver un nombre sin la necesidad de llamar a funciones externas o utilizar módulos del NEA. Pero primero: ¿Como se resuelve un nombre? Un nombre resuelto es aquel que puede acceder de por si solo a una dirección de memoria virtual (de PseudoD) válida: Si, PseudoD no almacena la memoria en direcciones crudas (por ejemplo: void* en C y C++) sino en direcciones virtuales, por ello, incrementar un puntero siempre devolverá dos valores: o un puntero válido a otra variable de PseudoD, o un error (memory underflow/overflow). Algunos nombres resueltos son: mensaje , NULO y foo#bar . La definición de un nombre sin resolver es un poco más com