La primera parte con requisitos funcionales está
aquí .
Reclamado como lenguajes de programación con un ojo puesto en la fiabilidad.
Alfabéticamente: Active Oberon, Ada, BetterC, IEC 61131-3 ST, Safe-C.
A la vez, el descargo de responsabilidad (excusa) no es en modo alguno una campaña de "todos del lado izquierdo", y la revisión es más bien académica: el lenguaje no solo puede tener un entorno de desarrollo moderno respaldado activamente, sino incluso un compilador para su plataforma.
Por otro lado, para los idiomas en cuestión hay compiladores de código abierto, y con el nivel actual de desarrollo de software, con interés, la sintaxis no demasiado complicada le permite crear un compilador personal e integrarse en algún tipo de Eclipse con luz de fondo y analizador.
Como indicador de la claridad del lenguaje, elegí la implementación de la famosa tarea multihilo de Dijkstra sobre los filósofos de la gastronomía. La implementación se encuentra en los libros de texto sobre el idioma y en los foros, lo que facilitó mi trabajo; solo queda adaptarme. Por ejemplo, un
artículo reciente de
habr sobre C ++ moderno contiene una implementación en C ++ 17 para comparar.
Oberon activo (2004)
Fue creado teniendo en cuenta la experiencia de Pascal, Modula, Oberons anteriores desde 1988, Java, C #, Ada, así como la experiencia práctica en la aplicación. Tiene una implementación en forma de
OS A2 , que puede actuar como tiempo de ejecución sobre * nix o Windows.
Fuentes A2 y el compilador para el enlace .
También hay un
proyecto de compilador de Oberon2 a C (OOC) que no
está vinculado al entorno de Oberon. Este es un dialecto ligeramente diferente, las diferencias se describen a continuación.
La característica clave de Oberon es la brevedad excepcional de la especificación. Estas son 16 páginas en la base Oberon-2 más 23 páginas en la extensión activa de subprocesos múltiples.
Sintaxis simple y clara que excluye errores obvios.
Los identificadores distinguen entre mayúsculas y minúsculas.
OOP con objetos en el montón con el recolector de basura (GC).
Se diferencia de sus predecesores en la sintaxis OOP más familiar en forma de Instance.Method (solía ser Method (Instance)) y soporte para subprocesos múltiples con primitivas de sincronización.
No existe un despacho dinámico en la implementación de OOP, lo que puede conducir fácilmente a una situación: se olvidaron de agregar procesamiento para un nuevo tipo.
Se puede asignar prioridad a las transmisiones y, en tiempo real / alto, GC no las interrumpe. Cadenas en forma de matrices UTF-8.
El Rantime (Sistema Oberon) ofrece oportunidades interesantes para reiniciar un procedimiento / módulo / subproceso fallido en caso de un error de tiempo de ejecución: direccionamiento de memoria o, por ejemplo, desbordamiento de enteros.
La desventaja es la falta de RAII y el manejo conveniente de errores, todo a través de códigos de retorno, con la excepción de la opción a continuación.
Oberon-2 OOC
Es más conveniente para los experimentos, ya que Oberon no requiere sistema operativo: se compila en ANSI C y no hay problemas de interoperabilidad. Diferencias con la versión activa: no hay un lenguaje de subprocesamiento múltiple incorporado; en cambio, hay un módulo para trabajar con PThreads, pero hay UTF16, modularidad jerárquica y un módulo de sistema para trabajar con excepciones.
Módulo 3
También hay un pariente de una rama de desarrollo ligeramente diferente en forma de Modula-3. Fue creado sobre la base de Oberon en oposición a la sobredesarrollada Ada.
La implementación está aquí .
En comparación con Active Oberon, se agregan genéricos y excepciones, hay bibliotecas para el trabajo práctico con Unicode, GUI e incluso Postgress. Integración simplificada con C. Otra semántica multihilo. RAII como WITH (similar al uso en C #).
Pero parece que el desarrollo de Modula 3 se detuvo en 2010.
Descargo de responsabilidad. Después de lanzar WinAOS, me encontré con TRAPs (también conocido como abortar / stacktrace o error de tiempo de ejecución) de la nada, incluso el administrador de tareas no funciona correctamente, y aunque el sistema / tiempo de ejecución no se bloqueó, pero solo la aplicación, tuve una cierta duda de que la fiabilidad está determinada por el idioma programación = (
Además, AOC es suficientemente autónomo, con su enfoque de desarrollo.
Fuente para los filósofos gastronómicosMODULE Philo; IMPORT Semaphores := Example8, Out; CONST NofPhilo = 5; VAR fork: ARRAY NofPhilo OF Semaphores.Semaphore; i: LONGINT; TYPE Philosopher = OBJECT VAR first, second: LONGINT; PROCEDURE & Init(id: LONGINT); BEGIN IF id # NofPhilo-1 THEN first := id; second := (id+1) ELSE first := 0; second := NofPhilo-1 END END Init; PROCEDURE Think; BEGIN Out.Int(first); Out.String(".... Think...."); Out.Ln; END Think; PROCEDURE Eat; BEGIN Out.Int(first); Out.String(".... Eat...."); Out.Ln; END Eat; BEGIN LOOP Think; fork[first].P; fork[second].P; Eat; fork[first].V; fork[second].V END END Philosopher; VAR philo: ARRAY NofPhilo OF Philosopher; BEGIN FOR i := 0 TO NofPhilo DO NEW(fork[i], INTEGER(i)); NEW(philo[i], i); END; END Philo. Philo.Philo1 ~
Ada (1980, último estándar válido de 2016)
En realidad, a primera vista hay todo lo que me gustaría.
E incluso un poco más: hay números con cálculos exactos de coma flotante. Por ejemplo, hay un planificador de subprocesos en tiempo real, intercambio de subprocesos cruzados y un subconjunto verificado formalmente del lenguaje SPARK. Y mucho mas.
Creo que si la confiabilidad de Ada necesitara una maldita con cuernos, se adjuntaría con instrucciones para llamar en una situación difícil =)
Implementación -
GNUTaya Ada , está en desarrollo, ISO / IEC estandarizado.
El estándar proporciona implementación con GC, pero para las opciones compiladas a menudo no se implementa. Se requiere la gestión manual de la memoria, y aquí son posibles los errores del programador. Sin embargo, el lenguaje está orientado al uso de la pila predeterminada y existe el concepto de tipos administrados con destructores. También puede definir su implementación de GC, liberación automática o recuento de referencias para cada tipo de datos.
Ada Reference Manual 2012 contiene 950 páginas.
La desventaja de Ada, además de la complejidad, es su excesiva verbosidad, que, sin embargo, fue concebida en aras de la legibilidad. Debido a la especificidad del modelo de seguridad del idioma, la integración con bibliotecas extranjeras es difícil.
El
sitio Ada-ru tiene un buen artículo de traducción de revisión: el primer enlace.
Fuente para los filósofos gastronómicos BetterC (subconjunto de dlang 2017, D original - 2001, D 2.0 - 2007)
La implementación más moderna de lo considerado. La descripción completa del idioma es bastante larga - 649 páginas -
vea el sitio original .
En realidad, este es el lenguaje D, pero con restricciones con el modificador -betterC. ¿Por qué así?
Porque la biblioteca estándar D es Phobos, desarrollada por Alexandrescu y resultó ser muy astuta, completamente construida en plantillas. La clave de este tema es que Phobos es incontrolable en términos de consumo de memoria.
Las cosas más importantes que se pierden en el modo BetterC son multihilo, GC, cadenas, clases (las estructuras permanecen, tienen una funcionalidad cercana, solo en la pila) y las excepciones (RAII y try-finally permanecen).
Sin embargo, es posible escribir parte del programa en D completa y la parte crítica en D-BetterC. También hay una función de atributo del sistema para controlar la no utilización de efectos peligrosos: pure
safe @nogc.
Justificación del régimen del creador del lenguaje.
Y
luego el apretón : qué se corta y qué queda disponible.
Las cadenas están contenidas en Phobos, y los intentos de usarlas en BetterC resultan en errores infernales de creación de instancias de plantillas en operaciones elementales como la salida de una cadena a la consola o concatenación. Y en modo D completo, las líneas en el montón también son inmutables, por lo tanto, las operaciones con ellas conducen al desorden de memoria.
Tuve que encontrar quejas sobre errores en el compilador varias veces. Lo cual, sin embargo, no es sorprendente para un lenguaje que compite en complejidad con C ++. Al preparar el artículo, también tuve que enfrentar 4 errores: dos surgieron al intentar construir dlangide con un nuevo compilador y un par al portar el problema del filósofo (por ejemplo, bloqueo al usar beginthreadex).
El modo ha aparecido recientemente y los errores causados por la restricción del modo BetterC ya se encuentran en la etapa de vinculación. Para aprender sobre esto de antemano, qué características del lenguaje se recortan exactamente, a menudo tienen que hacerlo de primera mano.
Fuente para los filósofos gastronómicos A modo de comparación, la fuente está llena D.En la roseta también puede ver opciones para otros idiomas.
IEC 61131-3 ST (1993, último estándar 2013)
Un lenguaje de programación de nicho para microcontroladores. El estándar implica 5 opciones de programación, pero escribir una aplicación, por ejemplo, en lógica de escalera sigue siendo una aventura. Por lo tanto, nos centramos en una opción: el texto estructurado.
El texto de la norma GOST R IEC 61131-3-2016 - 230 páginas.
Hay implementaciones para PC / x86 y ARM, y comerciales, la más famosa de las cuales es
CODESYS (a menudo también con licencia con diferentes nombres) y
abierta, Beremiz , transmitida a través de C.
Como hay integración con C, es bastante posible conectar las bibliotecas necesarias para la programación aplicada. Por otro lado, en esta área se acepta que la lógica gira por separado y solo sirve como un servidor de datos para otro programa o sistema, una interfaz con un operador o con un DBMS que ya se puede escribir en cualquier cosa, sin requisitos en tiempo real o incluso temporal. en general ...
La programación multiproceso para un programa de usuario ha aparecido relativamente recientemente; en microcontroladores esto no era necesario antes.
La conversión de tipos es principalmente explícita (relajada en el último estándar). Pero el control de desbordamiento depende de la implementación.
En la última edición del estándar, apareció OOP. El manejo de errores se realiza mediante manejadores de interrupciones personalizados.
Podemos decir que no hay asignación de memoria dinámica para el usuario. Esto sucedió históricamente: la cantidad de datos procesados por el microcontrolador siempre está constantemente limitada desde arriba.
Fuente (no verificado) Philo_2: Philosopher; Philo_3: Philosopher; Philo_4: Philosopher; Philo_5: Philosopher; END_VAR RESOURCE Station_1 ON CPU_1 TASK Task_1 (INTERVAL := T#100MS, PRIORITY := 1); TASK Task_2 (INTERVAL := T#100MS, PRIORITY := 1); TASK Task_3 (INTERVAL := T#100MS, PRIORITY := 1); TASK Task_4 (INTERVAL := T#100MS, PRIORITY := 1); TASK Task_5 (INTERVAL := T#100MS, PRIORITY := 1); PROGRAM Life_1 WITH Task_1: Philo_1(Name := 'Kant', 0, 1, Forks); PROGRAM Life2 WITH Task_2: Philo_2(Name := 'Aristotel', 1, 2, Forks); PROGRAM Life3 WITH Task_3: Philo_3(Name := 'Spinoza', 2, 3, Forks); PROGRAM Life4 WITH Task_4: Philo_4(Name := 'Marx', 3, 4, Forks); PROGRAM Life5 WITH Task_5: Philo_5(Name := 'Russel', 4, 0, Forks); END_RESOURCE END_CONFIGURATION FUNCTION_BLOCK Philosopher; USING SysCpuHandling.library; VAR_INPUT Name: STRING; Left: UINT; Right: UINT; END_VAR VAR_IN_OUT Forks: USINT; END_VAR VAR Thinking: BOOL := TRUE; Hungry: BOOL; Eating: BOOL; HaveLeftFork: BOOL; TmThink: TON; TmEating: TON; END_VAR TmThink(In := Thinking; PT := T#3s); TmEating(In := Eating; PT := T#5s); IF Thinking THEN Thinking := NOT TmThink.Q; Hungry := TmThink.Q; ELSIF Hungry IF HaveLeftFork IF SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Right, bSet := 1) = ERR_OK THEN Hungry := FALSE; Eating := TRUE; ELSE RETURN; END_IF ELSIF IF SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Left, bSet := 1) = ERR_OK THEN HaveLeftFork := TRUE; ELSE RETURN; END_IF END_IF ELSIF Eating IF TmEating.Q THEN Thinking := TRUE; Eating := FALSE; HaveLeftFork := FALSE; SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Right, bSet := 0); SysCpuTestAndSetBit(Address := Forks, Len := 1, iBit := Left, bSet := 0); END_IF END_IF END_FUNCTION_BLOCK
Safe-C (2011)
Experimental C con la eliminación de chips peligrosos y con la adición de modularidad y multihilo.
Sitio del proyectoDescripción de aproximadamente 103 páginas. Si resalta las diferencias de C,
muy poco, alrededor de 10 .
Trabajar con matrices y punteros es una memoria segura y dinámica con conteo automático de referencias, con comprobaciones de doble liberación y enlaces colgantes.
La biblioteca estándar tiene un conjunto mínimo de funciones para la GUI, multihilo, funciones de red (incluido un servidor http).
Pero, esta implementación es solo para Windows x86. Aunque el código del compilador y la biblioteca está abierto.
Como parte de otra tarea de investigación, armé un diseño de servidor web que recopila datos de sensores IoT: un módulo ejecutivo de 75 Kb y un conjunto de memoria parcial de <1 MB.
Fuente para los filósofos gastronómicos from std use console, thread, random; enum philos (ushort) { Aristotle, Kant, Spinoza, Marx, Russell, }; const int cycles = 10; const ushort NUM = 5; uint lived = NUM; packed struct philosopher // 32-bit { philos name; byte left, right; } philosopher philo_body[NUM]; SHARED_OBJECT forks[NUM]; void philosopher_life(philosopher philo) { int age; for (age = 0; age++ < cycles; ) { printf("%s is thinking\n", philo.name'string); delay((uint)rnd(1, 100)); printf("%s is hungry\n", philo.name'string); enter_shared_object(ref forks[philo.left]); enter_shared_object(ref forks[philo.right]); printf("%s is eating\n", philo.name'string); delay((uint)rnd(1, 100)); leave_shared_object(ref forks[philo.right]); leave_shared_object(ref forks[philo.left]); } printf("%s is leaving\n", philo.name'string); InterlockedExchange(ref lived, lived-1); } void main() { philos i; assert philosopher'size == 4; philo_body[0] = {Aristotle, 0, 1}; philo_body[1] = {Kant, 1, 2}; philo_body[2] = {Spinoza, 2, 3}; philo_body[3] = {Marx, 3, 4}; philo_body[4] = {Russell, 0, 4}; for (i = philos'first; i <= philos'last; i++) { assert run philosopher_life(philo_body[(uint)i]) == 0; } while (lived > 0) sleep 0;
Finalmente, una
tabla resumen de cumplimiento de los requisitos funcionales.
Seguramente me perdí o malinterpreté algo, así que corríjalo.
Fuentes del artículo sobre github .