E es un lenguaje de programación orientado a objetos para computación distribuida segura , creado por Mark S. Miller , [1] Dan Bornstein , Douglas Crockford , [2] Chip Morningstar [3] y otros en Electric Communities en 1997. E desciende principalmente del lenguaje concurrente Joule y de Original-E, un conjunto de extensiones de Java para programación distribuida segura. E combina computación basada en mensajes con sintaxis similar a Java . Un modelo de concurrencia basado en bucles de eventos y promesas garantiza que nunca se produzca un bloqueo . [4]
El lenguaje E está diseñado para la seguridad informática y la computación segura. Esto se logra principalmente mediante una estricta adherencia al modelo de computación orientada a objetos, que en su forma pura, tiene propiedades que respaldan la computación segura. El lenguaje E y su biblioteca estándar emplean una filosofía de diseño basada en capacidades en todo momento para ayudar a los programadores a crear software seguro y permitir que los componentes de software cooperen incluso si no confían completamente entre sí. En E, las referencias a objetos sirven como capacidades, por lo tanto, las capacidades no agregan costos computacionales o conceptuales. La sintaxis del lenguaje está diseñada para que sea fácil para las personas auditar en busca de fallas de seguridad. Por ejemplo, el alcance léxico limita la cantidad de código que se debe examinar para determinar sus efectos en una variable dada. Como otro ejemplo, el lenguaje utiliza el ==
operador para comparación y el :=
operador para asignación; para evitar la posibilidad de confusión, no hay =
operador.
En E, todos los valores son objetos y el cálculo se realiza enviando mensajes a los objetos. Cada objeto pertenece a un vat (análogo a un proceso ). Cada vat tiene un único hilo de ejecución, un marco de pila y una cola de eventos. La programación distribuida es simplemente una cuestión de enviar mensajes a objetos remotos (objetos en otros vats). Toda la comunicación con las partes remotas está cifrada por el entorno de ejecución de E. Los mensajes que llegan se colocan en la cola de eventos del vat; el bucle de eventos del vat procesa los mensajes entrantes uno por uno en orden de llegada.
E tiene dos formas de enviar mensajes: una llamada inmediata y un envío eventual . Una llamada inmediata es como una llamada a una función o método típico en un lenguaje no concurrente: un remitente espera hasta que un receptor finalice y devuelva un valor. Un envío eventual envía un mensaje mientras produce un marcador de posición para un resultado llamado promesa . Un remitente procede inmediatamente con la promesa. Más tarde, cuando un receptor finaliza y produce un resultado, la promesa se resuelve en un resultado. Dado que solo se permiten envíos eventuales cuando se comunica con objetos remotos, no pueden ocurrir bloqueos . En sistemas distribuidos, el mecanismo de promesa también minimiza los retrasos causados por la latencia de la red.
La sintaxis de E es muy similar a la de Java , aunque también tiene algunas similitudes con Python y Pascal . Las variables tienen tipos dinámicos y un alcance léxico . Sin embargo, a diferencia de Java o Python, E está compuesto completamente de expresiones . A continuación, se muestra un programa de E extremadamente simple:
println ( "¡Hola, mundo!" )
Aquí hay una función recursiva para calcular el factorial de un número, escrita en E. Las funciones se definen utilizando la def
palabra clave.
def factorial ( n : int ) : int { if ( n == 1 ) { return 1 } else if ( n > 0 ) { return n * factorial ( n - 1 ) } else { throw ( "argumento inválido para factorial: " + n ) } }
En la primera línea, :int
hay una protección que restringe el argumento y el resultado de la función. Una protección no es exactamente lo mismo que una declaración de tipo; las protecciones son opcionales y pueden especificar restricciones. La primera :int
garantiza que el cuerpo de la función solo tendrá que manejar un argumento entero. Sin la segunda :int
, la función no podría devolver un valor. Poder ver de antemano que la información se escapa de la función es útil para la auditoría de seguridad.
Dado que E está pensado para apoyar la cooperación segura, el ejemplo canónico para los programas E es la Casa de la Moneda, un sistema de dinero electrónico simple en tan solo unas pocas líneas de E. El código siguiente define una función que crea casas de la moneda, donde cada casa de la moneda tiene su propia moneda. Cada casa de la moneda puede crear monederos que contengan su moneda, y cualquier poseedor de dos monederos de la misma moneda puede transferir dinero de forma segura entre los monederos. Mediante un examen rápido del código fuente, un programador E puede verificar fácilmente que solo las casas de la moneda pueden cambiar la cantidad de dinero en circulación, que el dinero solo puede crearse y no destruirse, que las casas de la moneda solo pueden crear dinero de su propia moneda y que solo el poseedor de un monedero puede cambiar su saldo.
def makeMint ( nombre ) : any { def [ sellador , dessellador ] := makeBrandPair ( nombre ) def mint { para makePurse ( var saldo :( int > = 0 )) : any { def decr ( cantidad :( 0 ... saldo )) : void { saldo - = cantidad } def wallet { para getBalance () : int { devolver saldo } para sprout ( ) : any { devolver mint.makePurse ( 0 ) } para getDecr ( ) : any { devolver sellador.sellar ( decr ) } para depositar ( cantidad : int , src ) : void { dessellador.dessellar ( src.getDecr ( ) ) ( cantidad ) saldo + = cantidad } } devolver wallet } } devolver mint }
Los objetos en E se definen con la def
palabra clave y, dentro de la definición del objeto, la to
palabra clave comienza cada método. Las expresiones de protección en este ejemplo ilustran cómo especificar una restricción de valor (como en :(int >= 0)
o :(0..balance)
).
El ejemplo de la Casa de Moneda utiliza un mecanismo integrado llamado sellador . La función makeBrandPair
crea dos objetos asociados, un sellador y un dessellador, de modo que el sellador puede sellar un objeto en una caja y el dessellador es el único objeto que puede recuperar el contenido de la caja. Consulte el sitio web de E para obtener una explicación más detallada de este ejemplo de dinero. [5]
Antes de presentar el siguiente ejemplo simple de dinero basado en capacidades, debemos intentar evitar una confusión que este ejemplo causa repetidamente. ¡No estamos proponiendo realmente hacer dinero de esta manera! Un sistema monetario deseable también debe prever...