Umka: nuevo lenguaje de script estáticamente tipado


La primera versión del lenguaje de script embebido estático de tipos Umka que he desarrollado se acaba de publicar . Su objetivo es combinar la flexibilidad de los lenguajes de scripting familiares con protección contra errores de tipo en la etapa de compilación en bytecode. La idea principal del lenguaje - explícito es mejor que implícito - está tomada del "Zen de Python", sin embargo, debe adquirir un significado ligeramente diferente y más obvio aquí.

No importa cuán privadas y subjetivas sean las impresiones que me llevaron a emprender el desarrollo del lenguaje, espero que el plan no sea ingenuo. Debajo del corte, hablaré brevemente sobre las capacidades del lenguaje y los motivos para su creación.

Motivos


La primera virtud del tipeo dinámico generalmente se denomina acortar el ciclo de desarrollo / depuración y ahorrar tiempo al programador. A riesgo de causar disgusto público, debo admitir que mi propia experiencia no confirma esto de ninguna manera. Cada vez que realizo una pequeña corrección de mi secuencia de comandos de entrenamiento de redes neuronales en Python, tengo que esperar a que Python, NumPy, PyTorch se carguen, lean una gran variedad de datos de los archivos, los transfieran a la GPU, comiencen a procesar, y solo entonces descubran que PyTorch esperaba un tensor de tamaño (1, 1 , m, n, 3) en lugar de (1, m, n, 3).

Admito fácilmente que muchas personas prefieren los idiomas escritos dinámicamente por sus razones personales. Incluso es posible que la tendencia u hostilidad hacia la tipificación dinámica sea un fenómeno del mismo orden que la actitud hacia las aceitunas y el jugo de tomate. Los intentos de un estudio objetivo de este tema aparentemente conducen a resultados no concluyentes .

Al mismo tiempo, la popularidad de TypeScript, la introducción de anotaciones de tipo en Python, las acaloradas discusiones sobre Reddit y Habré nos hacen pensar que la identificación real de los lenguajes de script con lenguajes de escritura dinámica no es un dogma en absoluto, sino una coincidencia, y un lenguaje de script de escritura estática tiene todo el derecho de existir.

Entonces había un lenguaje que lleva el nombre de un gato que lleva el nombre de un oso.

Lengua


La sintaxis del lenguaje en su conjunto fue inspirada por Go. Se pueden encontrar ejemplos de construcciones de sintaxis en la página del proyecto . Al declarar variables, se puede usar una notación abreviada con inferencia de tipos. Cabe destacar la desviación de las reglas Go realizadas en la sintaxis de punteros. Los creadores de Go se quejaron de que, literalmente, siguiendo el ejemplo C resultó ser una sintaxis innecesariamente complicado aquí y que sería más razonable introducir un operador de sufijo eliminación de referencias como Pascal p^lugar *p. Eso es exactamente lo que hizo Umka.

TraductorUmka se compila en bytecode, que luego es ejecutado por la máquina virtual de la pila. Todos los controles de tipo se realizan en la etapa de compilación. Los datos en la pila ya no llevan ningún tipo de información. El traductor viene en forma de una biblioteca dinámica con su propia API y un pequeño "contenedor": un archivo ejecutable. El código fuente está escrito en C99 y portado a diferentes plataformas. Las versiones para el procesador x86-64 (Windows y Linux) ya están disponibles .

Gestión de la memoriahasta ahora hecho sobre la base de contadores de referencia. Si el lenguaje causa algún interés y se intenta utilizarlo, tendrá sentido organizar un recolector de basura más avanzado. El lenguaje admite los tipos de datos compuestos clásicos (matrices y estructuras) ubicados en la pila, y las matrices dinámicas ubicadas en el montón. Cualquier matriz o estructura clásica también se puede colocar en el montón con una llamada explícita new().

El polimorfismo es proporcionado por las interfaces de estilo Go. No hay conceptos de clase, objeto y herencia.

MultitareaSe basa en el concepto de "fibras": flujos simplificados que se ejecutan dentro de la misma máquina virtual y claramente se causan entre sí. En esencia, esto es sinónimo de corutinas. Dado que la lógica de usar estas rutinas se desvía ligeramente de la tradición de Go y se acerca a Lua y Wren, tiene sentido dar una muestra de código:

fn childFunc(parent: std.Fiber, buf: ^int) {
    for i := 0; i < 5; i++ {
        std.println("Child : i=" + std.itoa(i) + " buf=" + std.itoa(buf^))
        buf^ = i * 3
        fibercall(parent)
    }
}

fn parentFunc() {
    a := 0
    child := fiberspawn(childFunc, &a)    
    for i := 0; i < 10; i++ {
        std.println("Parent: i=" + std.itoa(i) + " buf=" + std.itoa(a))
        a = i * 7
        if fiberalive(child) {
            fibercall(child)
        }
    }    
    fiberfree(child)
}

Ejemplos


Como ejemplo básico que demuestra las capacidades del lenguaje, recomiendo mirar un programa de renderizado para escenas tridimensionales basadas en el trazado de rayos inversos. Se utiliza muy orgánicamente recursividad, interfaces, matrices dinámicas; algo más artificial: multitarea.

Un ejemplo de incrustar el traductor Umka en un proyecto en C es el código fuente del contenedor ejecutable del traductor. También hay una extensión de muestra de lenguaje Umka con funciones externas en C.

imagen

All Articles