Nim for Python Programmers ES - nim-lang/Nim GitHub Wiki
Caracteristica | 🐍 Python | 👑 Nim |
---|---|---|
Modelo de Ejecucion | Maquina Virtual (Interprete) | Codigo Maquina via C/C++ (Compilador) |
Escrito usando | C | Nim |
Licencia | Python Software Foundation License | MIT |
Version (Mayor) | 3.x |
1.x |
Meta-programacion | ✔️ metaclass, eval | ✔️ template, macro |
Manejo de Memoria | Garbage collector | Estrategias de manejo de memoria multi-paradigma (garbage collectors o ARC o manual) |
Tipado | Dinamico | Estatico |
Tipos Dependientes | ❎ | ✔️ |
Genericos | Duck typing | ✔️ |
Tipos int8/16/32/64 | ❎ | ✔️ |
Tipos float32/float64 | ❎ | ✔️ |
Tipo Char | ❎ | ✔️ |
Tipo Subrange | ❎ | ✔️ |
Tipo Enum | ✔️ | ✔️ |
Tipo Bigint | ✔️ | ✔️ |
Tipo Array | ✔️ | ✔️ |
Tipado con Inferencia | Duck typing | ✔️ |
Closures | ✔️ | ✔️ |
Sobrecarga de Operadores | ✔️ | ✔️ en cualquier Tipo |
Operadores Personalizados | ❎ | ✔️ |
Orientado a Objetos | ✔️ | ✔️ |
Metodos | ✔️ | ✔️ |
Excepciones | ✔️ | ✔️ |
Funciones Anonimas | ✔️ 1-linea solamente | ✔️ multi-linea |
Comprension de Lista | ✔️ | ✔️ |
Comprension de Diccionario | ✔️ | ✔️ |
Comprension de Set | ✔️ | ✔️ |
Comprension de Objetos Personalizados | ❎ | ✔️ |
Inmutabilidad | Limitado (frozenset, tupla, etc) | ✔️ |
Inmutabilidad de Argumentos de Funcion | Mutable | Inmutable |
String Literales Formateados | ✔️ F-Strings | ✔️ strformat |
FFI | ✔️ CTypes (solo C) | ✔️ C/C++/JS |
Async | ✔️ | ✔️ |
Threads | ✔️ (Global Interpreter Lock) | ✔️ |
Regex | ✔️ No Perl-compatible | ✔️ Perl Compatible Regular Expressions |
Comentarios de Auto-Documentacion | ✔️ Strings Texto-plano | ✔️ ReStructuredText/Markdown |
Publicacion de Paquetes | ✔️ No integrado, requiere twine
|
✔️ Integrado, nimble
|
Manejador de Paquetes | ✔️ pip
|
✔️ nimble
|
AutoFormateador de Codigo | ✔️ black via PIP |
✔️ nimpretty Integrado |
Extensiones de Archivo | .py, .pyi, .pyd, .pyo, .pyw, .pyz, .pyx | .nim, .nims |
Formato Temporario de Representacion Intermedia | .pyc | C |
Usa SheBang en Archivos | ✔️ | ❎ |
Indentacion | Tabuladores y Espacios | Espacios |
Crear una nueva usa var
o let
o const
.
Nim tiene inmutabilidad y ejecucion de funciones en tiempo de compilacion.
Podes asignar funciones a variables.
Declaracion | Tiempo de Compilacion | Tiempo de Ejecucion | Inmutable | Requiere Asignacion | Auto-Inicializado |
---|---|---|---|---|---|
var |
❎ | ✔️ | ❎ | ❎ | ✔️ |
let |
❎ | ✔️ | ✔️ | ✔️ | ✔️ |
const |
✔️ | ❎ | ✔️ | ✔️ | ✔️ |
Para usuarios avanzados, es posible saltarse la Auto-Initializacion de variables.
Las variables pueden ser multi-linea sin "escaparlas", es util para lineas largas y operadores ternarios largos, ejemplo minimo:
variable = 666 + \
420 * \
42 - \
9
assert variable == 18297
⬆️ Python ⬆️ ⬇️ Nim ⬇️
var variable = 666 +
420 *
42 -
9
assert variable == 18297
Funciona para las funciones tambien:
import strutils
var variable = " 12345 "
.strip
.parseInt
assert variable == 12345
Podes usar guion bajo (underscore), espacios y salto de linea en los nombres de variables:
let `this must be
positive`: Positive = 42
assert this_must_be_positive == 42
const `this is my nice named variable` = 42
Podes usar nombres reservados como nombre de variable.
Si estas recien comenzando desde cero, podes usar var
para todo cuando estas aprendiendo, no produce error por hacerlo.
Los espacios deben ser consistentes en el codigo, principalmente en operadores:
echo 2 - 1 # OK
echo 2-1 # OK
Espacios inconsistentes:
echo 2 -1 # Error
# ^ es leido como "-1"
Omitir espacios en el codigo no mejora en nada. Todos los operadores son funciones en Nim.
for x in range(0, 9):
if x == 6:
print(x)
print(x)
Resultados:
6
8 # Leak!
⬆️ Python ⬆️ ⬇️ Nim ⬇️
for x in 0..9:
if x == 6:
echo x
echo x
Resultados:
Error: undeclared identifier: 'x'
Mas ejemplos:
x = 0
y = 0
def example():
x = 1
y = 1
class C:
assert x == 0 and y == 1 # ???
x = 2
example()
⬆️ Python ⬆️ ⬇️ Nim ⬇️
var x = 0
var y = 0
proc example() =
var x = 1
var y = 1
type C = object
assert x == 1 and y == 1
x = 2
example()
Mas del mismo ejemplo:
x = 0
y = 0
def example():
x = 1
y = 1
class C:
assert x == 0 and y == 0 # ???
x = 2
try:
raise
except Exception as y:
pass
example()
⬆️ Python ⬆️ ⬇️ Nim ⬇️
var x = 0
var y = 0
proc example() =
var x = 1
var y = 1
type C = object
assert x == 1 and y == 1
x = 2
try:
raise
except Exception as y:
discard
example()
def example(argument = [0]):
argument.append(42)
return argument
print(example())
print(example())
print(example())
Output:
[0, 42]
[0, 42, 42]
[0, 42, 42, 42]
⬆️ Python ⬆️ ⬇️ Nim ⬇️
func example(argument = @[0]): auto =
argument.add 42
return argument
echo example()
echo example()
echo example()
Output:
Error: type mismatch: got <seq[int], int literal(42)>
but expected one of:
proc add[T](x: var seq[T]; y: sink T)
first type mismatch at position: 1
required type for x: var seq[T]
but expression 'argument' is immutable, not 'var'
Import | 🐍 Python | 👑 Nim |
---|---|---|
Solo 1 simbolo, usar sin calificar | from math import sin |
from math import sin |
Todos los simbolos, usar sin calificar | from math import * |
import math (recomendado) |
Todos los simbolo, usar calificado | import math (recomendado) |
from math import nil |
"import as" con otro nombre | import math as papota |
import math as papota |
Todos los simbolos excepto 1, usar sin calificar | ❎ | import math except sin |
Todos los simbolos excepto 3, usar sin calificar | ❎ | import math except sin, tan, PI |
Incluir otro modulo en este modulo | ❎ | include algunmodulo |
En Nim, import math
importa todos los simbolos del modulo math
(sin()
, cos()
, etc) entonces se pueden usar sin calificar. El equivalente en Python es from math import *
.
Si preferis no importar todos los simbolos, y usar los nombres calificados, en Nim es from math import nil
. Entonces puedes llamar math.sin()
etc. El equivalente en Python es import math
.
Las razon por la cual es seguro importar todos los nombres en Nim es que el compilador realmente no incluira ninguna funcion o nombre no usado (entonces no hay un costo extra), y por que Nim es estaticamente tipado entonces puede distinguir entre dos funciones importadas con el mismo nombre basandose en los Tipos y argumentos de la funcion. Y aun asi en casos muy raros donde los nombres y tipos y argumentos son todos iguales, puedes usar el nombre completo calificado para desambiguar.
Nim puede usar los imports en una misma linea. De Python a Nim ejemplo lo mas minimo posible:
import foo
import bar
import baz
⬆️ Python ⬆️ ⬇️ Nim ⬇️
import foo, bar, baz
Si tu linea queda demasiado larga, los import tambien pueden estar en un bloque indentado:
import
foo, bar, baz, more, imports,
here, we, split, multiple, lines
Si preferis 1 import por linea, por los Diff de Git, los import tambien pueden estar 1 por linea:
import
foo,
bar,
baz
La forma con 1 import
por linea es comun en in Python y Nim, pero en Nim la forma import foo, bar, baz
es mas frecuente.
Mas ejemplos:
## Esto es documentacion del modulo.
# Esto es un comentario.
include prelude
import sugar as stevia
from math import nil
from with as what import nil
Si estas recien comenzando desde cero, podes usar los import como en Python para todo cuando estas aprendiendo, no produce error por hacerlo.
__import__("math")
⬆️ Python ⬆️ ⬇️ Nim ⬇️
template imports(s) = import s
imports math
A veces veras ejemplos de codigo o archivos sin los imports pero funcionan igualmente (?).
Nim puede usar import
desde la linea de comando de compilacion, o dese un archivo .nims
:
nim c --import:sugar file.nim
nim c --import:folder/mymodule file.nim
nim js --import:strutils --include:mymodule file.nim
Algunas veces los projectos o ejemplos de codigo usan esto para salvar tipear tanto.
Ver:
Puede parecer que Python tiene mas simbolos disponibles por defecto sin ningun import
comparado con Nim,
para tener una experiencia similar puedes usar
prelude:
include prelude
echo now()
echo getCurrentDir()
echo "Hello $1".format("World")
prelude funciona para JavaScript tambien.
- Si los simbolos son no calificados, como saber de donde vienen?
Si foo()
es un simbolo:
- Python: Tipicamente tenes
object.foo()
en lugar demodule.foo()
, sin UFCS. - Nim: Tipicamente tenes
foo()
, con UFCS.
Typicamente el Editor/IDE debe mostrar de donde viene un simbolo, como cualquier otro lenguaje de programacion:
Nim viene con NimSuggest para Editor/IDE.
Contrario a Python, el sistema de tipos de Nim tiene toda la info de los simbolos:
import macros
macro findSym(thing: typed) = echo thing.getType.lineInfo
findSym:
echo # De donde sale echo?.
echo
viene de:
lib/system.nim(1929, 12)
En Python todos los simbolos en un modulo son visibles desde otro modulo que lo importa, incluido simbolos "dunder" y cosas que no deberian ser mutadas desde afuera.
En Nim todo es privado por defecto y no es visible desde otro modulo que lo importa,
para hacer un simbolo Publico y visible desde afuera podes usar la Star *
:
let variable* = 42
const constante* = 0.0
proc unaFuncion*() = discard
template unTemplate*() = discard
type Platipo* = object
fufflyness*: int
Star hace el simbolo visible desde el mundo exterior,
hace el simbolo aparecer en la documentacion generada,
cuando importas el modulo el simbolo estara en el namespace,
pero los simbolos internos de detalles de implementacion sin *
no son visibles,
y las cosas que no deberian ser mutadas desde afuera no seran visibles,
tiene el beneficio visual para humanos que es facil reconocer "la API Publica" de un modulo con solo ver el codigo.
Para entender mejor, es recomendado leer (en Ingles): https://narimiran.github.io/2019/07/01/nim-import.html
A veces en Python ves este tipo de construcciones:
try:
import modulo
except: # ImportError
pass # Explota en run-time (?)
try:
import modulo
except: # ImportError
def funcion(): # Ultimo recurso definicion de "emergencia" (duplicacion de codigo)
return algunvalor
# Mas codigo aca...
Nim resuelve todos los import en tiempo de compilacion, no hay ImportError
en tiempo de ejecucion.
No hay necesidad de try: import
en Nim.
Los Arrays son de capacidad fija, comienzan en indice 0
y contienen elementos del mismo Tipo.
Cuando pasas un array a una funcion en Nim, el argumento es una referencia inmutable. Nim va agregar chequeos de limite de capacidad en tiempo de ejecucion en los array.
Podes usar openarray
para aceptar un array de cualquier capacidad en argumentos de funcion,
y podes usar low(el_array)
y high(el_array)
para averiguar los limites de capacidad del array.
string
es compatible con openArray[char]
para omitir copias innecesarias por optimizacion,
char
es compatible con int
, entonces la manipulacion de string
puede hacerse usando matematica transparentemente,
una funcion que toma openArray[char]
acepta "abcd"
y ['a', 'b', 'c', 'd']
.
Ver:
Los Objetos en Nim son un poco diferentes de classes en Python.
Los Objetos soportan herencia y Orientacion a Objetos. Classes son Tipos nombrados en Nim.
Las Funciones flotan sueltas libremente, no estan metidas dentro de los objetos
(igualmente, podes usarlas como en Python),
podes llamar a una funcion de objeto con Objeto.funcion()
.
Nim no tiene un self
o this
implicito.
Imagina que las funciones son "pegadas" a los objetos durante la compilacion, entonces podes usarlas en tiempo de ejecucion como si fueran classes y metodos de Python.
Objetos Python que internamente usan generacion de codigo son muy muy lentos,
dataclass
, metaclass
, Decoradores, etc pueden ser mas de 30x mas lentos que un class
normal,
y derrota cualquier optimizacion, incluyendo un archivo .pyc
,
Expansion de codigo en Nim es realizada en tiempo de compilacion, haciendolo costo cero en tiempo de ejecucion.
De Python a Nim ejemplo lo mas minimo posible:
class Gatito(object):
""" Documentacion Aca """
def purr(self):
print("Miau Miau")
Gatito().purr()
⬆️ Python ⬆️ ⬇️ Nim ⬇️
type Gatito = object ## Documentacion Aca
proc purr(self: Gatito) = echo "Miau Miau"
Gatito().purr()
Ejemplo de Orientacion a Objetos estilo Python:
type Animal = ref object of RootObj ## Animal objeto base.
edad: int
nombre: string ## Atributos de objeto base.
type Gato = ref object of Animal ## Gato heredado.
jugueton: float ## Atributos de objeto heredado.
func incrementar_edad(self: Gato) =
self.edad.inc() # Gato funcion de objeto, accede y *modifica* el objeto.
var gatito = Gato(nombre: "Tom") # Gato instancia de objeto.
gatito.incrementar_edad() # Gato funcion de objeto usado.
assert gatito.nombre == "Tom" # Assert en objeto Gato.
assert gatito.edad == 1
Luego del ejemplo de Gato probablemente estas pensando como hacer un def __init__(self, arg):
.
El __init__()
de Python es el newObject()
o initObject()
de Nim, podemos hacer un __init__()
para el Gato:
type Gato = object # Gato objeto.
edad: int
nombre: string # Atributos de Gato.
func initGato(edad = 2): Gato = # Gato.__init__(self, edad=2)
result.edad = edad # self.edad = edad
result.nombre = "adoptame" # self.nombre = "adoptame"
var gatito = initGato() # Gato instancia de objeto.
assert gatito.nombre == "adoptame" # Assert en el Gato.
assert gatito.edad == 2
Los nombres son una convencion y mejores practicas,
cuando quieras un init para Foo
simplemente hace newFoo()
o initFoo()
.
Como habras notado initGato
es solo una funcion que retorna un Gato
.
-
initFoo()
paraobject
. -
newFoo()
pararef object
.
Lee la documentation para Nombrar cosas siguiendo las mejores practicas.
El constructor de Objeto es tambien la forma de poner valores personalizados por defecto a los atributos de tus objetos:
type Cat = object
age: int # AutoInicializado a 0
name: string # AutoInicializado a ""
playfulness: float # AutoInicializado a 0.0
sleeping: bool # AutoInicializado a false
func initCat(): Cat =
result.age = 1 # Poner el valor a 1
result.name = "Bastet" # Poner el valor a "Bastet"
result.playfulness = 9.0 # Poner el valor a 9.0
result.sleeping = true # Poner el valor a true
En Python, los bucles de enteros usan el range
.
Para los usos de 1 y 2 argumentos de esta funcion,
El ..
iterador de Nim funciona igual:
for i in 0..10:
echo i # Muestra 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
for i in 5..10:
echo i # Muestra 5, 6, 7, 8, 9, 10
Nota que ..
incluye el final del rango (es inclusivo), donde en Python range(a, b)
no incluye b
(no inclusivo).
Si preferis la forma Python, usa el ..<
iterador:
for i in 0..<10:
echo i # Muestra 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
El Python range()
tambien tiene un tercer parametro opcional,
que es el valor de incrementacion de cada paso, que puede ser positivo o negativo.
Si necesitas este comportamiento, usa countup
o
countdown
:
for i in countup(1, 10, 2):
echo i # Muestra 1, 3, 5, 7, 9
Ver:
La sintaxis de slice es un poco diferente. El a[x:y]
de Python es a[x..<y]
de Nim.
let variable = [1, 2, 3, 4]
assert variable[0..0] == @[1]
assert variable[0..1] == @[1, 2]
assert variable[0..<2] == @[1, 2]
assert variable[0..3] == @[1, 2, 3, 4]
En Nim los indices reversos usan ^
con el numero, por ejemplo ^1
,
los indices reversos tiene un Tipo especifico BackwardsIndex
,
y tambien pueden ser "preparados" en tiempo de compilacion como un const
:
const ultimo = ^1 # Compile-time
assert ultimo is BackwardsIndex
assert [1, 2, 3, 4, 5][2 .. ultimo] == @[3, 4, 5]
assert [1, 2, 3, 4, 5][2 .. ^1] == @[3, 4, 5]
var otro = ^3 # Run-time
assert [1, 2, 3, 4, 5][0 .. otro] == @[1, 2, 3]
assert [1, 2, 3, 4, 5][^3 .. ^1] == @[3, 4, 5]
Comparemos unos ejemplos simplificados:
[0, 1, 2][9] # No existe el Indice 9
Explota en tiempo de ejecucion por que no existe el indice 9:
$ python3 ejemplo.py
Traceback (most recent call last):
File "ejemplo.py", line 1, in <module>
[0, 1, 2][9]
IndexError: list index out of range
$
Veamos que hace Nim:
discard [0, 1, 2][9] # No existe el Indice 9
Compilar y ejecutar:
$ nim compile --run ejemplo.nim
ejemplo.nim(1, 19) Warning: can prove: 9 > 2 [IndexCheck]
ejemplo.nim(1, 18) Error: index 9 not in 0..2 [0, 1, 2][9]
$
Nim chequea en tiempo de compilacion que [0, 1, 2]
no tiene indice 9
, por que 9 > 2
, no compila ni ejecuta.
Esto tambien funciona con Subrange, digamos que tenes una variable con un numero entero que debe ser positivo:
let debe_ser_positivo: Positive = -9
Compilar y ejecutar:
$ nim compile --run ejemplo.nim
ejemplo.nim(1, 34) Warning: can prove: 1 > -9 [IndexCheck]
ejemplo.nim(1, 34) Error: conversion from int literal -9 to Positive is invalid.
$
Nim chequea en tiempo de compilacion que debe_ser_positivo
no es Positive
por que 1 > -9
, no compila ni ejecuta.
Podes controlar esto con --staticBoundChecks:on
o --staticBoundChecks:off
.
Con --staticBoundChecks:off
puede lanzar error en tiempo de ejecucion como en Python.
- Para una mejor documentacion ver: https://nim-lang.github.io/Nim/drnim.html
Python no tiene un Null Coalescing Operator (al tiempo de escribir).
Python usa este tipo de construcciones:
otro = bar if bar is not None else "valor por defecto" # "bar" puede ser Null?, o no ?.
Nim tiene el modulo wrapnils con el Null Coalescing Operator ?.
,
que simplifica el codigo reduciendo la necesidad de ramas de if..elif...else
en valores intermedios que pueden ser Null.
assert ?.foo.bar.baz == "" # "bar" puede ser Null?, o no ?.
Null es None
en Python. Null es nil
en Nim.
Ver https://nim-lang.github.io/Nim/wrapnils.html
Para un "With Context Manager" (Manejador de Contextos) en Nim tenes las siguientes opciones:
Lenguaje | String | Multi-line string | Raw String | Multi-line Raw string | Formatted Literals | Quote |
---|---|---|---|---|---|---|
🐍 Python | "foo" |
"""foo""" |
r"foo" |
r"""foo""" |
f"""{1 + 2}""" |
" '
|
👑 Nim | "foo" |
"""foo""" |
r"foo" |
r"""foo""" |
fmt"""{1 + 2}""" |
" |
Ops | 🐍 Python | 👑 Nim |
---|---|---|
Minuscula | "ABCD".lower() |
"ABCD".toLowerAscii() |
Desnudar | " ab ".strip() |
" ab ".strip() |
Dividir | "a,b,c".split(",") |
"a,b,c".split(",") |
Concatenacion | "a" + "b" |
"a" & "b" |
Buscar | "abcd".find("c") |
"abcd".find("c") |
Comienza Con | "abc".startswith("ab") |
"abc".startswith("ab") |
Termina Con | "abc".endswith("ab") |
"abc".endswith("ab") |
Dividir Lineas | "1\n2\n3".splitlines() |
"1\n2\n3".splitlines() |
Partir | "abcd"[0:2] |
"abcd"[0..<2] |
Partir 1 char | "abcd"[2] |
"abcd"[2] |
Partir Revertido | "abcd"[-1] |
"abcd"[^1] |
Normalizar | unicodedata.normalize("NFC", "Foo") |
"Foo".normalize() |
Contar Lineas | len("1\n2\n3".splitlines()) |
"1\n2\n3".countLines() |
Repetir | "foo" * 9 |
"foo".repeat(9) |
Indentar | textwrap.indent("foo", " " * 9) |
"a".indent(9) |
Desindentar |
textwrap.dedent("foo") ❓ |
"foo".unindent(9) |
Parsear Booleano |
bool(distutils.util.strtobool("fALse")) ❓ |
parseBool("fALse") |
Parsear Entero | int("42") |
parseInt("42") |
Parsear Flotante | float("3.14") |
parseFloat("3.14") |
String Literal Formateado | f"foo {1 + 2} bar {variable}" |
fmt"foo {1 + 2} bar {variable}" |
Distancia de Levenshtein | ❎ | editDistance("Kitten", "Bitten") |
- Las operaciones de string de Nim requieren
import strutils
. - Comparacion detallada.
Strings con 1 sola alocacion de memoria son posibles con newStringOfCap(capacity = 42)
,
que retorna 1 nuevo string vacio ""
pero con capacidad alocada de 42
,
pero si pasas mas alla de esa capacity
no va a dar error (buffer overflow):
variable = ""
assert variable == "" # longitud 0, capacidad 0, 1 alloc, 0 copias
variable += "a" # longitud 1, capacidad is 1, 2 alloc, 1 copias
variable += "b" # longitud 2, capacidad is 2, 3 alloc, 2 copias
variable += "c" # longitud 3, capacidad is 3, 4 alloc, 3 copias
variable += "d" # longitud 4, capacidad is 4, 5 alloc, 4 copias
assert variable == "abcd"
# TOTAL: 5 alloc, 4 copias
⬆️ Python ⬆️ ⬇️ Nim ⬇️
var variable = newStringOfCap(2)
assert variable == "" # longitud 0, capacidad is 2, 1 alloc, 0 copias
variable.add "a" # longitud 1, capacidad is 2, 1 alloc, 0 copias
variable.add "b" # longitud 2, capacidad is 2, 1 alloc, 0 copias
variable.add "c" # longitud 3, capacidad is 3, 2 alloc, 0 copias
variable.add "d" # longitud 4, capacidad is 4, 3 alloc, 0 copias
assert variable == "abcd"
# TOTAL: 3 alloc, 0 copias
Esta diferencia es mas grande para strings adento de bucles for o while.
Nim strformat
implementa string literales formateados inspirados de Python F-string.
strformat
es implementado usando metaprogramming y la expansion de codigo es en tiempo de compilacion.
Funciona para JavaScript tambien.
Similar a Python F-string se puede
debugear usando el simbolo igual,
fmt"{key=}"
expande a fmt"key={value}"
:
let x = "hello"
assert fmt"{x=}" == "x=hello"
assert fmt"{x = }" == "x = hello"
Nim strformat
soporta Backslash, pero Python F-string no:
>>> print( f"""{ "yep\nope" }""" ) # Run-time error.
Error: f-string expression part cannot include a backslash.
⬆️ Python ⬆️ ⬇️ Nim ⬇️
echo fmt"""{ "yep\nope" }""" # Nim works.
yep
ope
Se puede elejir los caracteres delimitadores:
import strformat
let variable = 42
assert fmt("( variable ) { variable }", '(', ')') == "42 { variable }"
assert fmt("< variable > { variable }", '<', '>') == "42 { variable }"
Caracteres Backtick y Space ' '
tambien funciona:
import strformat
let variable = 42
assert fmt(" variable`{variable}", ' ', '`') == "42{variable}"
Ver:
Uso | 🐍 Python | 👑 Nim |
---|---|---|
Sistema Operativo | os | os |
Operaciones String | string | strutils |
Fecha y Hora | datetime | times |
Cosas Al Azar | random | random |
Expresiones Regulares | re | re |
HTTP | urllib | httpclient |
Logs | logging | logging |
Ejecutar comandos | subprocess | osproc |
Manipulacion de ruta | pathlib, os.path | os |
Matematica | math, cmath | math |
Tipos MIME | mimetypes | mimetypes |
SQLite SQL | sqlite3 | db_sqlite |
Postgres SQL | ❎ | db_postgres |
Serializacion | pickle | json, marshal |
Base64 | base64 | base64 |
Abrir URL en web browser | webbrowser | browsers |
Async | asyncio | asyncdispatch, asyncfile, asyncnet, asyncstreams |
Unittests | unittests | unittest |
Diff | difflib | diff |
Colores | colorsys | colors |
MD5 | hashlib.md5 | md5 |
SHA1 | hashlib.sha1 | sha1 |
Servidor HTTP | http.server | asynchttpserver |
Lexer | shlex | lexbase |
Multi-Hilos | threading | threadpool |
URL & URI | urllib.parse | uri |
CSV | csv | parsecsv |
Argumentos de linea de comando | argparse | parseopt |
SMTP | smtplib | smtp |
Galletitas de HTTP | http.cookies | cookies |
Estadisticas | statistics | stats |
Recorte de Texto | textwrap | wordwrap |
Registro de Windows | winreg | registry |
POSIX | posix | posix, posix_utils |
SSL | ssl | openssl |
CGI | cgi | cgi |
Parsear JSON | json | parsejson, json |
Parsear INI | configparser | parsecfg |
Parsear XML | xml | parsexml, xmltree |
Parsear HTML | html.parser | htmlparser |
Parsear SQL | ❎ | parsesql |
Colores en la Terminal | ❎ | terminal |
Detectar Distro Linux | ❎ | distros |
Generador HTML | ❎ | htmlgen |
Azucares de Sintaxis | ❎ | sugar |
JavaScript & Frontend | ❎ | dom, asyncjs, jscore, jsffi |
- No es una lista completa solo un repaso rapido. Para mas info ver https://nim-lang.org/docs/lib.html
Tuplas son capacidad fija, comienzan en index 0
, pueden contener tipos mixtos,
pueden ser anonimas o nombrada, named tuple no tiene costo extra sobre anonymous tuple.
(1, 2, 3)
⬆️ Python ⬆️ ⬇️ Nim ⬇️
(1, 2, 3)
- Keys con nombre, Tupla sin nombre. Python NamedTuple requiere
import collections
.
collections.namedtuple("_", "key0 key1")("foo", 42)
⬆️ Python ⬆️ ⬇️ Nim ⬇️
(key0: "foo", key1: 42)
- Keys con nombre, Tupla con nombre. Python NamedTuple requiere
import collections
.
collections.namedtuple("NameHere", "key0 key1")("foo", 42)
⬆️ Python ⬆️ ⬇️ Nim ⬇️
type NameHere = tuple[key0: string, key1: int]
var variable: NameHere = (key0: "foo", key1: 42)
Tuplas Nim son similares a las Python NamedTuple.
Ver manual para mas acerca de tuplas.
Nim sequencias no son de capacidad fija,
pueden crecer y achicarse, comienzan en indice 0
y pueden contener elementos del mismo Tipo.
["foo", "bar", "baz"]
⬆️ Python ⬆️ ⬇️ Nim ⬇️
@["foo", "bar", "baz"]
variable = [item for item in (-9, 1, 42, 0, -1, 9)]
⬆️ Python ⬆️ ⬇️ Nim ⬇️
let variable = collect(newSeq):
for item in @[-9, 1, 42, 0, -1, 9]: item
La Comprension puede ser asignada a const
tambien, y correra en tiempo de compilacion.
La comprehension es implementada con macro
que es expandido en tiempo de compilacion,
podes ver la expansion de codigo usando la opcion de compilador --expandMacro
en la terminal:
let variable =
var collectResult = newSeq(Natural(0))
for item in items(@[-9, 1, 42, 0, -1, 9]):
add(collectResult, item)
collectResult
Comprehension puede ser anidada, multi-linea, multi-expresion, costo cero:
import sugar
let values = collect(newSeq):
for val in [1, 2]:
collect(newSeq):
for val2 in [3, 4]:
if (val, val2) != (1, 2):
(val, val2)
assert values == @[@[(1, 3), (1, 4)], @[(2, 3), (2, 4)]]
One-liner:
print([i for i in range(0, 9)])
⬆️ Python ⬆️ ⬇️ Nim ⬇️
echo(block: collect newSeq: (for i in 0..9: i))
Python Comprehension convierte el codigo en un Generator, pero Nim Comprehension no convierte el codigo en un Iterator:
import sugar
func example() =
discard collect(newSeq):
for item in @[-9, 1, 42, 0, -1, 9]:
if item == 0: return
item
example()
⬆️ Nim ⬆️ ⬇️ Python ⬇️
def example():
[item for item in [-9, 1, 42, 0, -1, 9] if item == 0: return]
example()
Python se queja:
SyntaxError: invalid syntax.
Codigo que no funciona en Python funcionara en Nim, cosas como return
, etc
por que el codigo es silenciosamente convertido a un Generador por Python, pero es expandido a codigo normal por Nim.
- Que es
collect()
?.
collect()
toma de argumento lo que sea que tu Tipo de retorno usa como constructor.
variable = {key: value for key, value in enumerate((-9, 1, 42, 0, -1, 9))}
⬆️ Python ⬆️ ⬇️ Nim ⬇️
let variable = collect(initTable(4)):
for key, value in @[-9, 1, 42, 0, -1, 9]: {key: value}
-
collect()
requiereimport sugar
.
variable = {item for item in (-9, 1, 42, 0, -1, 9)}
⬆️ Python ⬆️ ⬇️ Nim ⬇️
let variable = collect(initHashSet):
for item in @[-9, 1, 42, 0, -1, 9]: {item}
-
collect()
requiereimport sugar
.
Lenguaje | Set | Set Ordenado | Bitset | Bit Fields | Imports |
---|---|---|---|---|---|
🐍 Python | set() |
❎ | ❎ | ❎ | |
👑 Nim | HashSet() |
OrderedSet() |
set |
Bit Fields | import sets |
- Python Set puede ser reemplazado con HashSet.
Python Set no es igual a Nim Set,
el Set "por defecto" es un Bitset,
que por cada posible valor contenido en el set,
guarda 1 Bit indicando si el valor esta presente,
entonces deberias usarlo para valores finitos limitados a un rango de posibles valores,
si los valores posibles son conocidos en tiempo de compilacion, podes crear un Enum
para los valores.
El numero entero mas grande que entra en un Set por defecto es 65535
equivalente a high(uint16)
.
Podes usar valores mas grandes usando un Subrange, si no necesitas valores mas chicos,
un ejemplo stresando un set para poner 2_147_483_647
equivalente a high(int32)
en un set en tiempo de compilacion:
const x = {range[2147483640..2147483647](2147483647)}
assert x is set # Equals to {2147483647}
Los Set de Python no son iguales a los Set de Nim. Se debe saber el tipo de los valores que van en el Set y deben ser finitos. Podes imitar el Set de Python usando un HashSet. El Set de Nim es mas rapido y es muy eficiente en memoria. De hecho, el Set de Nim esta implementado con un Bit Vector, y HashSet esta implementado como dicionario. Para simples Tipos bandera y sets matematicos, usa Set.
- Ver HashSet.
Tablas son como los diccionarios Python.
Lenguaje | Diccionario | Diccionario Ordenado | Contador | Import |
---|---|---|---|---|
🐍 Python | dict() |
OrderedDict() |
Counter() |
import collections |
👑 Nim | Table() |
OrderedTable() |
CountTable() |
import tables |
dict(clave="valor", otro="cosas")
⬆️ Python ⬆️ ⬇️ Nim ⬇️
to_table({"clave": "valor", "otro": "cosas"})
collections.OrderedDict([(8, "hp"), (4, "laser"), (9, "motor")])
⬆️ Python ⬆️ ⬇️ Nim ⬇️
to_ordered_table({8: "hp", 4: "laser", 9: "motor"})
collections.Counter(["a", "b", "c", "a", "b", "b"])
⬆️ Python ⬆️ ⬇️ Nim ⬇️
to_count_table("abcabb")
Examples:
import tables
var diccionario = to_table({"hola": 1, "ahi": 2})
assert diccionario["hola"] == 1
diccionario["hola"] = 42
assert diccionario["hola"] == 42
assert len(diccionario) == 2
assert diccionario.has_key("hola")
for clave, valor in diccionario:
echo clave, valor
Tablas son solamente azucar (syntax sugar) sobre un array de tuplas:
assert {"key": "value", "k": "v"} == [("key", "value"), ("k", "v")]
assert {"key": true, "k": false} == @[("key", true), ("k", false)]
B-Tree Table usando la misma API.
Ver:
"resultado0" if condicional else "resultado1"
⬆️ Python ⬆️ ⬇️ Nim ⬇️
if condicional: "resultado0" else: "resultado1"
Como habras notado el Operador Ternario es simplemente un if..else
en-linea.
Leer archivos linea por linea
with open("elarchivo.txt", "r") as f:
for line in f:
print(line)
⬆️ Python ⬆️ ⬇️ Nim ⬇️
for linea in lines("elarchivo.txt"):
echo linea
- Documentacion de
lines()
https://nim-lang.org/docs/io.html#lines.i%2Cstring
Leer y escribir archivos:
write_file("elarchivo.txt", "esto simula datos")
assert read_file("elarchivo.txt") == "esto simula datos"
Leer archivos en tiempo de compilacion:
const constante = static_read("elarchivo.txt") # Retorna un string en tiempo de compilacion
Cambiar permisos a archivos.
import os
os.chmod("file.txt", 0o777)
⬆️ Python ⬆️ ⬇️ Nim ⬇️
import filepermissions
chmod "file.txt", 0o777
Ejemplo asume que un archivo llamado "file.txt"
existe.
Usa permisos tipo Unix (Octal Unix permissions).
Ver https://nim-lang.github.io/fusion/src/fusion/filepermissions.html
Cambiar de carpeta temporalmente, y volver.
import os
class withDir:
# Unsafe without a __del__()
def __init__(self, newPath):
self.newPath = os.path.expanduser(newPath)
def __enter__(self):
self.savedPath = os.getcwd()
os.chdir(self.newPath)
def __exit__(self, etype, value, traceback):
os.chdir(self.savedPath)
with withDir("subcarpeta"):
print("Adentro de subcarpeta")
print("Volver fuera de subcarpeta")
⬆️ Python ⬆️ ⬇️ Nim ⬇️
import scripting
withDir "subcarpeta":
echo "Adentro de subcarpeta"
echo "Volver fuera de subcarpeta"
Ver https://nim-lang.github.io/fusion/src/fusion/scripting.html
def isPositive(arg: int) -> bool:
return arg > 0
map(isPositive, [1, 2,-3, 5, -9])
filter(isPositive, [1, 2,-3, 5, -9])
⬆️ Python ⬆️ ⬇️ Nim ⬇️
proc esPositivo(arg: int): bool =
return arg > 0
echo map([1, 2,-3, 5, -9], esPositivo)
echo filter([1, 2,-3, 5, -9], esPositivo)
- Map y Filter requiere
import sequtils
.
variable: typing.Callable[[int, int], int] = lambda var1, var2: var1 + var2
⬆️ Python ⬆️ ⬇️ Nim ⬇️
var variable = proc (var1, var2: int): int = var1 + var2
Multi-linea:
var anon = func (x: int): bool =
if x > 0:
result = true
else:
result = false
assert anon(9)
Funciones Anonimas en Nim es basicamente una funcion sin nombre.
- Templates y Macros pueden ser usados como Decoradores Python.
def decorator(argument):
print("This is a Decorator")
return argument
@decorator
def function_with_decorator() -> int:
return 42
print(function_with_decorator())
⬆️ Python ⬆️ ⬇️ Nim ⬇️
template decorador(argumento: untyped) =
echo "Esto imita un Decorador"
argumento
func funcion_con_decorador(): int {.decorador.} =
return 42
echo funcion_con_decorador()
- Por que Nim no usa
@decorator
?.
Nim usa {.
y .}
por que puede tener muchisimos decoradores juntos.
Ademas los de Nim funcionan en variables y Tipos:
func funcion_con_decorador(): int {.discardable, inline, compiletime.} =
return 42
let variable {.compiletime.} = 1000 / 2
type Colores {.pure.} = enum Rojo, Verde, Azul
Python usa strings multi-linea con JSON adentro, Nim usa JSON literal directamente en el codigo.
import json
variable = """{
"key": "value",
"other": true
}"""
variable = json.loads(variable)
print(variable)
⬆️ Python ⬆️ ⬇️ Nim ⬇️
import json
var variable = %*{
"key": "value",
"other": true
}
echo variable
-
%*
convertira todo dentro de los corchetes a JSON, JSON es de TipoJsonNode
. -
%*
puede tener variables y literales adentro. - JSON puede tener comentarios adentro de
%*
, comentarios de Nim. - Si el JSON no es JSON valido el codigo no compila.
-
JsonNode
puede ser muy util en Nim por que es un Tipo que puede tener Tipos mezclados y crecer/achicarse. - Podes leer JSON en tiempo de compilacion, y guardarlo en una constante.
- Para parsear JSON desde string usa
parseJson("{}")
. - Para parsear JSON desde archivo usa
parseFile("file.json")
. - Documentacion de JSON
if __name__ == "__main__":
main()
⬆️ Python ⬆️ ⬇️ Nim ⬇️
when is_main_module:
main()
import unittest
def setUpModule():
"""Setup: Ejecuta una sola vez antes de todos los tests."""
pass
def tearDownModule():
"""Teardown: Ejecuta una sola vez despues de todos los tests."""
pass
class TestName(unittest.TestCase):
"""Nombre del Test"""
def setUp(self):
"""Setup: Ejecuta una sola vez antes de cada test."""
pass
def tearDown(self):
"""Teardown: Ejecuta una sola vez despues de cada test."""
pass
def test_ejemplo(self):
self.assertEqual(42, 42)
if __name__ == "__main__":
unittest.main()
⬆️ Python ⬆️ ⬇️ Nim ⬇️
import unittest
suite "Nombre del Test":
echo "Setup: Ejecuta una sola vez antes de todos los tests."
setup:
echo "Setup: Ejecuta una sola vez antes de cada test."
teardown:
echo "Teardown: Ejecuta una sola vez despues de cada test."
test "ejemplo":
assert 42 == 42
echo "Teardown: Ejecuta una sola vez despues de todos los tests."
- Documentacion de Unittest.
- Nimble el manejador de paquetes puede tambien ejecutar Unittests.
- NimScript puede tambien ejecutar Unittests.
-
Podes ejecutar la documentation como si fueran Unittests con
runnableExamples
.
-
assert
puede tomar como argumento unblock
, podes personalizar el mensaje para una mejor experiencia de usuario:
let a = 42
let b = 666
doAssert a == b, block:
("\nCustom Error Message!:" &
"\n a equals to " & $a &
"\n b equals to " & $b)
Alternativa a unittest
, preparado para proyectos grandes.
- https://nim-lang.github.io/Nim/testament.html (Recomendado)
DocStrings en Nim son comentarios en ReSTructuredText y MarkDown comenzando con ##
,
ReSTructuredText y MarkDown pueden estar mezclados juntos si queres.
Genera HTML, Latex (PDF) y JSON desde el codigo fuente Nim con nim doc archivo.nim
.
Nim puede generar un grafico de dependencias internas DOT .dot
con nim genDepend archivo.nim
.
Podes ejecutar la documentation como si fueran Unittests con runnableExamples
.
""" Documentation of Module """
class Kitten(object):
""" Documentation of Class """
age: int
def purr(self):
""" Documentation of function """
print("Purr Purr")
⬆️ Python ⬆️ ⬇️ Nim ⬇️
## Documentacion del Modulo *ReSTructuredText* y **MarkDown**
type Gatito = object ## Documentacion del Tipo *ReSTructuredText* y **MarkDown**
edad: int ## Documentacion del Atributo *ReSTructuredText* y **MarkDown**
proc purr(self: Gatito) =
## Documentacion de Funcion *ReSTructuredText* y **MarkDown**
echo "Miau Miau"
Para lineas cortas, podes escribir el codigo en una sola linea.
let a = try: 1 + 2 except: 42 finally: echo "Inline Try"
let b = if true: 2 / 4 elif false: 4 * 2 else: 0
for i in 0..9: echo i
proc foo() = echo "Funcion"
(proc () = echo "Funcion Anonima")()
template bar() = echo "Template"
macro baz() = echo "Macro"
var i = 0
while i < 9: i += 1
when is_main_module: echo 42
- Por que Nim es CamelCase en vez de snake_case?.
Realmente no es, Nim es Agnostico de Estilos.
let camelCase = 42 # Declara como camelCase
assert camel_case == 42 # Usa como snake_case
let snake_case = 1 # Declara como snake_case
assert snakeCase == 1 # Usa como camelCase
let `free style` = 9000
assert free_style == 9000
Esta caracteristica le permite a Nim interoperar transparentemente con muchisimos lenguajes de programacion con diferentes estilos.
Para un codigo mas homogeneo existe una forma por defecto, y puedes inclusive forzarla si quieres,
para forzar la forma por defecto en el estilo de codigo puedes agregar al comando de compilacion --styleCheck:hint
,
Nim va a chequear estilos para tu codigo antes de compilar, similar a pycodestyle
o black
de Python,
si quieres aun mas estricto usa --styleCheck:error
.
Nim viene con un auto-formateador de codigo llamado Nimpretty.
Muchos lenguajes de programacion tienen algun tipo de Case Insensitivity, como: PowerShell, SQL, PHP, Lisp, Assembly, Batch, ABAP, Ada, Visual Basic, VB.NET, Fortran, Pascal, Forth, Cobol, Scheme, Red, Rebol.
Si estas recien comenzando desde cero, podes usar los estilos como en Python para todo, no produce error por hacerlo.
- Por que Nim no usa
def
en vez deproc
?.
Nim usa proc
para funciones del nombre "Procedimiento" (Procedure).
Usa func
para Programacion Funcional Libre de side-effects funciones de "funcion matematica".
Nim tiene seguimiento de side-effects.
No se puede usar echo
dentro de func
, por que echo
muta stdout
, es un Side-Effect, usa debugEcho
.
Si estas recien comenzando desde cero, podes usar proc
para todo, no produce error por hacerlo.
Nim tiene Async integrado desde hace mucho tiempo, funciona como esperas con async
, await
, Future
, etc.
asyncdispatch es el modulo para escribir codigo concurrente usando sintaxis async
/await
.
Future
es un Tipo (como Future en Python, como Promise en JavaScript).
{.async.}
es el Pragma que transforma funciones a Async (como async def
en Python).
Hagamos el Hola Mundo official de Python Asyncio en Nim:
async def main():
print("Hello ...")
await asyncio.sleep(1)
print("... World!")
asyncio.run(main())
⬆️ Python ⬆️ ⬇️ Nim ⬇️
proc main() {.async.} =
echo("Hello ...")
await sleep_async(1)
echo("... World!")
wait_for main()
Internamente Async esta implementado usando metaprogramacion (Macros, Templates, Pragmas, etc).
Descripcion | asyncCheck | waitFor | await |
---|---|---|---|
Espera que el Future este completo | ❎ | ✔️ | ✔️ |
Ignora el Future | ✔️ | ❎ | ❎ |
Retona el resultado dentro del Future | ❎ | ✔️ | ✔️ |
Solo disponible dentro de async | ❎ | ❎ | ✔️ |
- Por que Nim no usa
async def
?.
Async es simplemente un macro
en Nim, no hay necesidad de cambiar la sintaxis de todo el lenguaje, es como un Decorator en Python.
Ademas la misma funcion puede ser Async Y Sync al mismo tiempo, con el mismo codigo, con el mismo nombre.
En Python cuando tenes una libreria "foo", tal vez tenes foo
(Sync) y aiofoo
(Async),
usualmente proyectos, repos, devs, APIs completamente diferentes,
esto no es necesario en Nim, gracias a esa caracteristica.
Ver tambien asyncfile, asyncnet, asyncstreams, asyncftpclient, asyncfutures.
Nunca tenes realmente que manualmente editar C, de la misma manera que en Python nunca tenes que manualmente editar PYC.
En Nim programas escribiendo Nim, de la misma manera que en Python programas escribiendo Python.
Templates reemplazan su invocacion con su contenido en tiempo de compilacion.
Imagina que el compilador va a copiar&pegar un pedazo de codigo por vos.
Template permite tener construcciones como funcion pero sin costos extra de performance, permite partir funciones gigantes en construcciones mas diminutas.
Demasiados nombres de funciones y variables pueden contaminar y saturar el namespace local, variables dentro de templates no existen afuera del template, templates no existen en el namespace en tiempo de ejecucion (si no lo exportas), templates pueden optimizar ciertos valores si son conocidos en tiempo de compilacion.
Templates no pueden hacer import
or export
de librerias automaticamente implicitamente,
templates no pueden hacer "auto-import" de simbolos usandos dentro de si mismo,
si usas alguna libreria importada en el cuerpo de un template,
debes importar esa libreria cuando llamas ese template.
Adentro de los templates no se puede usar return
por que no es una funcion.
Templates te permiten implementear una bonita API de muy alto nivel para uso habitual, mientras mantienen las cosas de optimizaciones y de bajo nivel fuera de tu cabeza y DRY.
Python with open("file.txt", mode = "r") as file:
implementado usando 1 template:
GIF no es perfecto, pero es una aproximacion simplificada!.
Esta no es la manera de leer y escribir archivos en Nim, es solo un ejercicio.
Template no es perfecto, pero es una aproximacion simplificada!, ejercicio para el lector el tratar de mejorarlo ;P
template with_open(name: string, mode: char, body: untyped) =
let flag = if mode == 'w': fmWrite else: fmRead # "flag" No existe fuera de este template
let file {.inject.} = open(name, flag) # Crea e injecta variable "file", "file" existe fuera de este template por {.inject.}
body # El codigo "body" es pasado como argumento
file.close() # Codigo luego de body
with_open("testin.nim", 'r'): # Imita Python with open("file", mode='r') as file
echo "Hello Templates" # Codigo dentro del template, estas 2 lineas son "body" del template
echo file.read_all() # Esta linea usa la variable "file"
Si estas recien comenzando desde cero, podes usar Funciones como en Python para todo, no produce error por hacerlo.
Compartir variables entre funciones es similar a Python.
Variable Global:
global_variable = ""
def function0():
global global_variable
global_variable = "cat"
def function1():
global global_variable
global_variable = "dog"
function0()
assert global_variable == "cat"
function1()
assert global_variable == "dog"
function0()
assert global_variable == "cat"
⬆️ Python ⬆️ ⬇️ Nim ⬇️
var global_variable = ""
proc function0() =
global_variable = "cat"
proc function1() =
global_variable = "dog"
function0()
assert global_variable == "cat"
function1()
assert global_variable == "dog"
function0()
assert global_variable == "cat"
Object Attribute:
class IceCream:
def __init__(self):
self.object_attribute = None
def function_a(food):
food.object_attribute = 9
def function_b(food):
food.object_attribute = 5
food = IceCream()
function_a(food)
assert food.object_attribute == 9
function_b(food)
assert food.object_attribute == 5
function_a(food)
assert food.object_attribute == 9
⬆️ Python ⬆️ ⬇️ Nim ⬇️
type IceCream = object
object_attribute: int
proc functiona(food: var IceCream) =
food.object_attribute = 9
proc functionb(food: var IceCream) =
food.object_attribute = 5
var food = IceCream()
functiona(food)
assert food.object_attribute == 9
functionb(food)
assert food.object_attribute == 5
functiona(food)
assert food.object_attribute == 9
Podes pasar funciones como argumento de funciones como en Python tambien.
- https://github.com/yglukhov/nimpy/wiki#publish-to-pypi
- https://github.com/sstadick/ponim/blob/master/README.md#nim--python--poetry--
- https://github.com/sstadick/nython#nython
Si queres la compilacion completamente silenciosa (vas a perder errores y consejos importantes),
podes agregar al comando de compilacion --hints:off --verbosity:0
.
La ayuda del compilador es larga, para hacerla mas amigable al usuario solo las cosas mas frecuentes se muestran con --help
,
para ver la ayuda completa usa --fullhelp
.
Cuando tu codigo esta listo para produccion debes usar el Release build,
podes agregar al comando de compilacion -d:release
.
Caracteristica | Release Build | Debug Build |
---|---|---|
Velocidad | Rapido | Lento |
Archivo | Chico | Grande |
Optimizado | ✔️ | ❎ |
Tracebacks | ❎ | ✔️ |
Chequeos Run-time | ✔️ | ✔️ |
Chequeos Compile-time | ✔️ | ✔️ |
assert |
❎ | ✔️ |
doAssert |
✔️ | ✔️ |
Nim compila a C, puede correr en Arduino y hardware similar.
Nim tiene varios tipos de manejo de memoria para satisfacer tu necesidad, incluido manejo de memoria manual. Binarios Nim son chicos cuando se compilan en Release Build y pueden entrar en poco espacio de disco.
- https://github.com/zevv/nim-arduino
- https://gitlab.com/endes123321/nimcdl/tree/master#nimcdl-nim-circuit-design-language
- https://github.com/cfvescovo/Arduino-Nim#arduino-nim
- https://gitlab.com/nimbed/nimbed#nimbed
- https://gitlab.com/endes123321/led-controller-frontend#led-controller-frontend
- https://ftp.heanet.ie/mirrors/fosdem-video/2020/AW1.125/nimoneverything.webm
SuperCollider es C++ entonces puede ser re-utilizado con Nim.
Teoricamente, plugins Nim de SuperCollider son rapidos como codigo C. La metaprogramacion de Nim permite hacer DSL amigables para LiveCoding.
Algunos proyectos para Nim LiveCoding: