Nim: ¿Un sustituto de Python? Pruebe el mejor lenguaje de programación que no conocía
Conozca a Nim: el lenguaje con sintaxis similar a Python y eficiencia C
Nim
Hace unas semanas, encontré un repositorio que me llamó la atención. Albergaba un proyecto que estaba escrito íntegramente en Nim.
¿Qué rayos es Nim? Pensé.
Inmediatamente llegué a la conclusión de que este era uno de los muchos lenguajes de programación que usa mucha gente, pero yo era el tipo estúpido que no lo sabía. Pero en lugar de dejarlo de lado, decidí: aprendamos un poco sobre esto.
Entonces tuve dos grandes descubrimientos:
- No, mucha gente no usa este idioma.
- Pero talvez deberia ser.
Así que aquí va un poco sobre mi experiencia con Nim, un tutorial de programación rápido, y por qué el lenguaje me parece extremadamente prometedor.
¡Muéstrame el código!
Aquí hay un programa inútil escrito en Nim:
Parece bastante limpio. También se siente tan simple que probablemente pueda descubrir qué hace sin esfuerzo, aunque nunca antes haya oído hablar de Nim. (Pista: imprime num: 5 i: 5.)
Así que analicemos lo que parece familiar aquí:
Declaraciones de variables
Es muy familiar para los desarrolladores de JavaScript. Mientras que algunos lenguajes usan var y otros usan let, JS y Nim permiten declaraciones usando cualquiera de los dos. Sin embargo, es importante tener en cuenta que no tienen el mismo significado en ambos idiomas. Pero más sobre eso más adelante.
Sintaxis de bloque
Para marcar un nuevo bloque en Nim, usamos dos puntos seguidos de una línea con sangría. Eso es Python justo ahí.
Palabras clave
Ambos bucles, así como la declaración if, parecen extraídos directamente de Python. De hecho, todo desde la línea 5 en adelante es Python válido (asumiendo que tenemos una función de eco definida).
Entonces, sí, muchas de las palabras clave y operadores de Python también son válidas en Nim, como [ no ], [ is ], [ and ], [ or ], etc.
Hasta ahora, Nim no tiene nada de especial. Simplemente parece una versión peor de Python (en cuanto a sintaxis), ya que necesitamos usar [ let ] o [ var ].
Pero, ¿y si te dijera esto? Nim es un lenguaje escrito de forma estática que se ejecuta casi tan rápido como C.
Oh, ahora estamos hablando.
Una carrera amistosa
Antes de profundizar un poco más en la sintaxis de Nim (especialmente la parte escrita estáticamente, que todavía no hemos visto), intentemos respaldar las afirmaciones sobre su velocidad. Para hacerlo, escribí un programa para calcular ingenuamente (es decir, sin programación dinámica) el número n-ésimo de Fibonacci en Nim, Python y C.
Para mantener las cosas justas, estandaricé la implementación en función de la solución Leetcode sugerida para este problema (Enfoque 1) y me aseguré de cumplirla tanto como fuera posible en los tres idiomas.
Editar: La gente me sigue contando sobre LRU Cache. Soy consciente de ello. Sin embargo, las implementaciones en todos los lenguajes se podrían mejorar con la memorización. El punto aquí es simplemente elegir una implementación estándar y usarla, no tratar de optimizar tanto como sea posible. Por eso elegí una implementación ingenua.
Para cronometrar la ejecución, utilicé el valor “real” de la salida de [ time ] en el shell Bash.
Estos son los resultados para calcular el número 40 de Fibonacci:
Sí, eso pasó.
Ahora, esto es muy limitado y está lejos de ser un experimento científico, pero es consistente con los hallazgos de otros que han realizado evaluaciones comparativas más serias [1] [2] [3].
Sin embargo, todo el código que analizaré en este artículo está disponible en GitHub, incluidas las instrucciones sobre cómo probar este experimento.
Editar: Me ha llamado la atención que simplemente pasando una bandera al compilador de Nim podría haber mejorado su velocidad de ejecución en más de 10 veces. Algunos han hecho las pruebas y han descubierto que Nim es incluso más rápido que C. Esto sucede porque, como se indica en los documentos oficiales: “De forma predeterminada, el compilador de Nim genera una gran cantidad de comprobaciones en tiempo de ejecución con el objetivo de que usted pueda depurar. Con -d: libera algunas comprobaciones están desactivadas y las optimizaciones están activadas “.
El gráfico no se actualizará en aras de la finalidad, pero pensé que esta nota era importante. Consulte este problema para obtener más información.
Entonces, ¿por qué Nim es mucho más rápido que Python?
Bueno, yo diría que hay dos razones principales. Simplificando mucho, estos son:
- Nim se compila mientras se interpreta Python (sé que es un debate, pero lo estoy extrayendo de los Documentos para que sea breve). Esto significa que cuando se ejecuta un programa Python, se hace más trabajo que simplemente ejecutar el programa, ya que debe interpretarse antes de que realmente pueda ejecutarse. Esto generalmente hace que los idiomas sean mucho más lentos.
- Nim está tipado estáticamente. Si bien el ejemplo que mostré anteriormente no tenía una declaración o anotación de un solo tipo, veremos más adelante que, de hecho, es un lenguaje escrito de forma estática. En el caso de Python, que se escribe dinámicamente, el intérprete necesita hacer mucho más trabajo para descubrir y manejar adecuadamente los tipos, lo que ralentiza la ejecución.
Más rápido de ejecutar, más lento de escribir
Esto es lo que los documentos de Python tienen que decir sobre los lenguajes interpretados:
“Los lenguajes interpretados suelen tener un ciclo de desarrollo / depuración más corto que los compilados, aunque sus programas generalmente también se ejecutan más lentamente”.
Esta oración es un buen resumen de la compensación entre Python y C, por ejemplo. Todo lo que pueda hacer con Python también lo puede hacer con C, y su programa se ejecutará muchos órdenes de magnitud más rápido.
Sin embargo, pasará mucho más tiempo escribiendo y depurando su código en C, además de que será más largo y menos legible. Y es por eso que C ya no está tan de moda y Python es tan popular. En pocas palabras: Python es “fácil” (comparativamente, por supuesto).
Entonces, si Python está en un extremo del espectro y C en el otro, Nim está tratando de estar en algún lugar en el medio: ¿algo rápido y algo fácil? Algo como eso.
Sin embargo, lo que hace que Nim se destaque para mí es que, a primera vista, parece que ha minimizado la compensación. En otras palabras, es mucho más rápido que Python, pero no igualmente más difícil de programar, como C (o eso se siente tras una breve inspección).
Para ilustrar este punto, veamos el código de nuestro experimento de Fibonacci.
Aquí está el código C:
Python:
Y Nim:
Si bien Nim tiene este proceso [ proc ] extraño y usa [ = ] para declarar funciones (o procedimientos, como se les llama), todavía es mucho más limpio que C.
Por lo tanto, ¿tal vez sea una compensación digna? Un poco más difícil de escribir que Python, pero diez veces más rápido, podría vivir con eso.
Sintaxis de Nim
A continuación, se ofrece una breve descripción general de algunos puntos clave sobre la sintaxis de Nim:
Variables
Las variables se declaran con [ var ], [ let ] o [ const ].
[ var ] y [ const ] funcionan esencialmente como JavaScript, pero [ let ] es una historia diferente.
Mientras que [ let ] en JavaScript difiere de var en términos de alcance, [ let ] en Nim denota una variable cuyo valor no puede cambiar después de la inicialización. Esto es aparentemente similar a Swift, me han dicho ahora.
¿Pero no es eso una constante?
Bueno, en Nim la distinción es la siguiente:
Para [ const ], el compilador debe poder determinar el valor en tiempo de compilación, mientras que [ let ] se puede determinar en tiempo de ejecución.
La documentación ofrece este ejemplo:
Además, también puede declarar variables como esta:
Funciones
Las funciones en Nim se llaman procedimientos y su declaración se hace así:
Dado que el lenguaje se parece a Python en muchos aspectos, los procedimientos definitivamente se destacan por ser un poco extraños cuando los ves por primera vez.
Usar [ = ] en lugar de [ { ] o: es especialmente extraño. Sin embargo, se ve un poco mejor en procedimientos de una sola línea:
Además, puedes regresar de funciones como esta:
Parece que aún debería devolver el resultado, pero el resultado no es una variable, es una palabra clave. El fragmento anterior es Nim perfectamente válido.
Y también puede sobrecargar los procedimientos:
Flujo de control
Es muy parecido a Python.
Para iterar sobre un rango, en lugar de un rango, puede usar la [ countup (start, finish) ] o la [ countdown (start, finish) ]. O puede simplificar todo y usar: [ for i in start..finish ].
Imprimir y obtener información del usuario
Cuando se compara con Python, [ readLine (stdin) ] es el equivalente de [ input () ] y [ echo ] es el equivalente de [ print ].
[ echo ] se puede utilizar con o sin paréntesis.
Mi objetivo aquí es darte una muestra de Nim, no revisar todo su manual. Como tal, creo que me detendré aquí para ver la sintaxis simple y, a continuación, repasaré algunas características adicionales.
Características adicionales
Programación orientada a objetos
Nim no está orientado a objetos pero tiene soporte minimalista para objetos. Sin embargo, no son tan elegantes como las clases de Python.
Macros
Nim admite macros y metaprogramación y, de hecho, parece enfatizarlo mucho. Una parte completa de su serie de tutoriales de tres partes está dedicada a ello.
Aquí tienes un ejemplo rápido:
Tipos básicos
Los tipos básicos en Nim son: [ string ], [ char ], [ bool ], [ int ], [ uint ] y [ float ].
Estos también son válidos:
Además, las cadenas son mutables en Nim, a diferencia de Python.
Comentarios
Probablemente ya haya visto mis comentarios en la sintaxis de Python anterior, pero a diferencia de Python, los comentarios de varias líneas también utilizan el símbolo de almohadilla (seguido de [ o ] ):
Compilación de JavaScript
Desde el sitio web de Nim:
“Nim incluye un backend de JavaScript de primera clase para que pueda dirigirse al cliente y al servidor sin esfuerzo al mismo tiempo”.
Eso es bastante bueno, aunque no estoy seguro de cuántas personas realmente lo usarían. Pero si quieres jugar a Browser Snake escrito en Nim, puedes hacerlo. Sin embargo, esta vez no lo construí.
Iteradores
En lugar de definir un [ proc ], también se puede definir un [ iterador ]. Sin embargo, los iteradores de Nim son en realidad más como generadores de Python. Aquí tienes un ejemplo:
Caso y subrayar la indiferencia
Nim no distingue entre mayúsculas y minúsculas y guiones bajos (excepto para el primer carácter).
Por lo tanto, [ HelloWorld ] y [ helloWorld ] son diferentes, pero [ helloWorld ], [ helloworld ] y [ hello_world ] son todos iguales, lo que hace que esto sea válido:
Popularidad
En una nota positiva, Nim tiene casi 10,000 estrellas en GitHub
Quizás leyó el título y se dijo a sí mismo: ¡Uh, he oído hablar de Nim o he usado a Nim!
En ese caso, oye, me alegro por ti. Sin embargo, intenté obtener un poco de información sobre la popularidad del idioma, y seguramente no es tan alta.
Por ejemplo, Nim ni siquiera fue mencionado en la Encuesta de desbordamiento de pila de 2020. No pude encontrar ningún trabajo para desarrolladores de Nim en LinkedIn (Ubicación establecida en Todo el mundo), y la etiqueta Stack Overflow para el idioma solo tiene 349 preguntas. (Compare eso con los ~ 1,500,000 de Python, o los de un lenguaje más nuevo, como los 270,000 de Swift).
Por lo tanto, es bastante justo asumir que la mayoría de los desarrolladores no lo han usado y que muchos ni siquiera han escuchado el nombre de Nim.
¿Una verdadera alternativa a Python?
Seré honesto contigo, Nim me parece bastante genial.
Para escribir este artículo, repasé lo mínimo, por lo que aún no lo he profundizado demasiado, pero puedo verme usándolo para algo en el futuro.
Sin embargo, si bien la sintaxis básica es muy similar a la de Python, se vuelve más complicada bastante rápido, lo que estoy seguro eliminaría gran parte de la base de usuarios / desarrolladores de Python.
Personalmente, soy un gran admirador de Python, pero también de los lenguajes de tipado estático, por lo que para mí, la mejora del rendimiento en ciertos casos compensaría con creces la verbosidad agregada.
Entonces, al escribir este artículo me di cuenta: ¿Qué pasa con Go?
Estoy seguro de que muchos de ustedes estaban pensando en eso mientras leían, y es un punto válido. Por mucho que la sintaxis de Nim pueda estar más cerca de la de Python, realmente está compitiendo en el espacio de los lenguajes de alto rendimiento pero más agradables que C ++, que actualmente está liderado por Go.
Dato curioso: también ejecuté furtivamente la prueba de velocidad con Go. Para [ fibonacci (40) ] específicamente, fue tan rápido como C.
Entonces, ¿puede Nim competir con Python? Lo dudo mucho. Vemos una tendencia en la que las computadoras se vuelven más rápidas y la programación más fácil, hasta el punto de que incluso si Nim ofrece una buena compensación, como señalé, no creo que sea suficiente para asumir el Python limpio y versátil.
Editar: hablé con uno de los desarrolladores de Nim Core, quien me dijo que cree que Nim es más adecuado para las personas que hacen la transición de C ++ que las personas que hacen la transición de Python.
Sin embargo, ¿puede competir con Go? Quizás (si Google no estuviera detrás de Go). La sintaxis es amigable, el lenguaje es poderoso y tiene mejor soporte para las características de C / C ++ que las ofertas de Go (por ejemplo, macros y sobrecarga).
¿Quizás eso es lo que debería investigar a continuación?
¡Gracias por leer!