Magik (lenguaje de programación)
Magik es un lenguaje de programación orientada a objetos que soporta herencia múltiple, polimorfismo y cuyos tipos de datos son dinámicos. GE Energy lo proporciona como parte de la plataforma Smallworld y fue diseñado en un principio para implementar aplicaciones complejas para empresas como telecomunicaciones.
Magik fue creado originalmente en 1990, y a través de los años fue mejorado y actualizado. La versión actual es la 4.0 o Magik SF (Small Footprint).
Similitudes con Smalltalk
Magik tiene algunas similitudes con Smalltalk en términos de características del lenguaje y arquitectura: el lenguaje Magik se compila en bytecode que es interpretado por la Máquina virtual de Magik. La máquina virtual de Magik está disponible en varias plataformas, entre ellas Microsoft Windows, varias versiones de Unix y Linux.
Magik está basado en consola, y el código puede ser cambiado mientras la aplicación se está ejecutando. La consola puede ser utilizada tanto para ejecutar código Magik como para ver los resultados.
El código compilado se guarda en un único archivo llamado archivo imagen. Cada archivo imagen contiene el bytecode completo y el estado de la sesión (por ejemplo valores de variables) del momento del último guardado de la imagen.
Características del lenguaje
- Comentarios
Magik usa el #
para marcar secciones de código como comentario:
# Esto es un comentario.
- Asignaciones
Magik usa el operador <<
para hacer asignaciones:
a << 1.234 b << b + a
Esta notación se lee como "a se convierte en 1.234" o "b se convierte en b+a". Esto sirve para diferenciar correctamente asignación de comparación.
Magik soporta también una variación comprimida del operador que funciona de forma similar a los que podemos encontrar en C:
b +<< a # Equivalente a b << b + a
- Símbolos
Así como los tipos de datos convencionales como enteros, números en coma flotante y cadenas, Magik también implementa símbolos. Los símbolos son un tipo de dato especial que son usados extensamente en Magik para identificar de forma única los objetos. Se representan mediante dos puntos ":" seguidos de una cadena de caracteres. Los símbolos se pueden escapar mediante la barra vertical "|". Por ejemplo:
a << :hello # Cuando se encuentre :hello se referirá a la misma instancia b << :|hello world|
- Tipos dinámicos
Las variables de Magik no tienen tipos fijados como en C# y pueden referenciar diferentes objetos en la ejecución. Cualquier cosa en Magik es un objeto (No hay distinción entre objetos y tipos de datos primitivos como los enteros):
a << 1.2 # un número en coma flotante asignado a la variable 'a' a << "1.2" # más tarde se le asigna una cadena a la variable 'a'
- Objetos
Los objetos se implementan en Magik usando ejemplares. Los ejemplares son parecidos a las clases de otros lenguajes de programación como Java, pero con importantes diferencias. Magik soporta herencia múltiple y mezclas. Las nuevas instancias se crean clonando una ya existente (que típicamente es el ejemplar, pero no tiene por qué serlo).
Los nuevos ejemplares se crean con la sentencia def_slotted_exemplar()
, por ejemplo:
def_slotted_exemplar(:my_object, { {:slot_a, 34}, {:slot_b, "hello"} }, {:parent_object_a, :parent_object_b})
Este fragmento de código define un ejemplar llamado my_object
que tiene dos huecos (o campos) llamados slot_a
(preinicializado con el valor 34) y slot_b
(preinicializado con el valor "hello") que hereda de dos ejemplares ya existentes llamados parent_object_a
y parent_object_b
.
- Comparación
Magik implementa todos los operadores binarios típicamente usados (=
, <
, <=
, >
, >=
, ~=/<>
) para la comparación, así como algunos más inusuales. Los operadores _is
y _isnt
se usan para comparar instancias específicas de objetos, o referencias de objetos en lugar de valores.
Por ejemplo:
a << "hello" b << "hello"
a = b retorna True (_true) porque los valores de a y b son iguales a _is b returna False (_false) porque a y b no son la misma instancia
a << "hello" b << a
a = b retorna True (_true) porque los valores de a y b son iguales a _is b retorna True (_true) porque b se asigna a una instancia específica del mismo objeto que a, en lugar del mismo valor que a.
- Métodos
Los métodos se definen en los ejemplares usando las sentencias _method
y _endmethod
:
_method my_object.my_method(a, b) _return a + b _endmethod
Esta es una forma de sustituir los métodos new()
(para crear nuevas instancias) y init()
(para inicializar una instancia).
# Método New _method person.new(name, age) _return _clone.init(name, age) _endmethod
# Método Initialize _private _method person.init(name, age) # Llama la implementación del padre. _super.init(name, age) # Inicializa los campos. .name << name .age << age _return _self _endmethod
El _clone
crea una copia física del objeto person
. La sentencia _super
permite a los objetos invocar una implementación de un método en un ejemplar padre. Los objetos pueden referenciarse a sí mismos usando la sentencia _self
. A los campos de un objeto se accede usando la notación de punto ".".
Los métodos que no son parte de la interfaz pública de un objeto pueden ser marcados como privados usando la sentencia _private
. Los métodos privados solo pueden ser llamados por _self
, _super
y _clone
.
Hay argumentos opcionales que se pueden declarar con la sentencia _optional
. Los argumentos opcionales que no son pasados son asignados por Magik a un objeto especial _unset
(el equivalente a NULL). La sentencia _gather
se puede usar para declarar una lista de argumentos opcionales.
_method my_object.my_method(_gather values) _endmethod
- Iteración
En Magik las senencias _for
, _over
, _loop
y _endloop
permiten iterar.
_method my_object.my_method(_gather values) total << 0.0 _for a _over values.elements() _loop total +<< a _endloop _return total _endmethod
m << my_object.new() x << m.my_method(1.0, 2, 3.0, 4) # x = 10.0
Los nuevos metedos de iteración se definen usando las sentencias _iter
y _loopbody
:
_iter _method my_object.even_elements() _for a _over _self.elements() _loop _if a.even? _is _true _then _loopbody(a) _endif _endloop _endmethod
- Procedimientos
Magik también soporta funciones llamadas procedimientos. Los procedimientos son también objetos, declarados con las sentencias _proc
y _endproc
. Los procedimientos son asignados avariables que pueden ser invocadas:
my_procedure << _proc @my_procedure(a, b, c) _return a + b + c _endproc
x << my_procedure(1, 2, 3) # x = 6
- Peculiaridades lingüísticas
Puesto que Magik fue desarrollado originalmente en Inglaterra, los métodos del núcleo y las librerías de Smallworld está esctitas en inglés británico British English. Por ejemplo:
Se usa "initialise", en vez de "initialize".
Ejemplo Hello World
El siguiente fragmento de código es el programa que emite el mensaje "hello world" escrito en Magik:
write ("Hello World!")