Aprende a programar con Nim
Tags: nim, python, typescript, spanish
Published: 2021-03-11 14:28:43

# Copipastear

- **Todos los ejemplos se pueden copiar y pegar para ejecutarlos directamente!**

[Playground para practicar desde el navegador web.](https://play.nim-lang.org)

[Instalar en la computadora.](https://nim-lang.org/install.html)


# Hola Mundo

`echo` sirve para imprimir por la terminal los argumentos

```nim
echo "Hola Mundo"
```

Otro ejemplo

```nim
echo 1, true, 2.0, "OwO", false, -9, 0
```


# Comentarios

Los comentarios son texto ignorado por el programa,
es decir el texto en un comentario no existe para la computadora,
usualmente se usa para documentar el codigo para que las personas lo puedan entender mejor.

Comentario es una linea que empieza con `#`.

```nim
# Esto es un comentario
echo "Hola" , " ", "Mundo" # Otro comentario
```


# Tipos Basicos

`assert` comprueba que el argumento evalua a Verdadero.

`is` sirve para comprobar el tipo de algo, 
se usa de la forma `valor is Tipo`.

```nim
assert 42 is int
assert 3.14 is float
assert true is bool
assert "x" is string
assert 'z' is char
```


# Variables

Las variables se declaran con `var`, `let`, `const`.

```nim
var nombre = "valor"
```

Mas ejemplos:

```nim
var a = 42

var
  b = "Para no repetir tanto el 'var' "
  c = "podes agrupar las variables asi"
  d = true

let e = 666 +
  420 *
  42
```

| | Tiempo de Compilacion | Tiempo de Ejecucion | Inmutable | Requiere Asignamiento | 
|-------------|--------------|----------|-----------|---------------------|
`var`   | No | Si | No | No |
`let`   | No | Si | Si | Si | 
`const` | Si | No | Si | Si |


# Matematica Basica

Division entera usa el operador `div`

Modulo usa el operador `mod`

```nim
echo 1 + 2
echo 2 - 1
echo 2 * 2
echo 4 / 2
echo 4 div 2
echo 4 mod 2
```


# Valores Numericos

Puedes usar numeros Binarios, Hexadecimales, Octales, etc.

```nim
echo 0b1100  # Binario
echo 0xFFFF  # Hexadecimal
echo 0o777   # Octal

# _ es ignorado, es util para numeros grandes
echo 2_000_000

# Se comprobara que este numero siempre sea Positivo.
echo 0.Positive  # >= 0

# Se comprobara que este numero siempre sea Natural.
echo 1.Natural   # > 0
```


# If Elif Else

Control de flujo con bloques If Elif Else

```nim
if 9 > 0:
  echo "Ejemplo"
```

```nim
var condicional = true

if condicional:
  echo 42
else:
  echo 0
```

Un If Elif Else en una linea es un "Operador Ternario"

```nim
var condicional = true

if condicional: echo 42 else: echo 0
```

Mas ejemplos

```nim
var valor = 5

if valor == 0:
  echo "valor es cero"
if valor < 0:
  echo "valor es negativo"
else:
  echo "valor es positivo"
```

# Case Switch

Case Switch es similar a un If Elif Else pero funciona distinto.
Tambien puede tener un `else:`

```nim
var valor = "gato"

case valor
of "perro":
  echo "valor es perro"
of "gato", "gatito":
  echo "valor es gato"
else:
  echo "valor es otro animal"
```

case switch puede coincidir con multiples condiciones 
`of 1, 2, 3, 4, 5:` en el ejemplo de abajo.

case switch puede usar `elif` como se observa abajo.

```nim
var valor = 42

case valor
of 0:
  echo "valor es cero"
of 1, 2, 3, 4, 5:
  echo "valor esta entre 0 y 5"
of 6..9:
  echo "valor esta entre 6 y 9"
elif valor < 0:
  echo "valor es negativo"
else:
  echo "valor es otro numero"
```


# Bloques

Bloques de codigo con un nuevo Contexto (Scope) se crean con `block`

```nim
let ejemplo = "Afuera del block"

block:
  let ejemplo = "Adentro del block"
  echo ejemplo

echo ejemplo
```

Tambien puede usarse para evaluar codigo a un valor

```nim
let valor = block:
  let a = 1
  let b = 2
  a + b

assert valor == 3
```

Bloques pueden tener un nombre etiqueta.

Se puede salir explicitamente de un bloque usando `break`

```nim
echo "Afuera del block"

block el_bloque_loco:
  echo "Adentro del block"
  break el_bloque_loco

echo "Afuera del block"
```


# Bucle For

El bucle `for` sirve para iterar un valor iterable,
para aplicar algun tipo de logica a los items individualmente.

`for` se puede interrumpir con `break` tambien.

```nim
for i in 5..9:
  echo i
  if i == 7: 
    break
```

Otro ejemplo

```nim
for item in [1, 2, 3, 4, 5, 6]:
  if item mod 2 == 0:
    echo "item es par"
  else:
    echo "item es impar"
```


# Bucle While

El bucle `while` es similar al `for`,
pero sirve para repetir un bloque de codigo,
siempre y cuando un argumento de condicion booleana sea verdadera.

`while` se puede interrumpir con `break` tambien.

```nim
var z = 0
while z < 9:
  echo z
  inc z
```


# Leer y Escribir archivos

`readFile` sirve para leer archivos.

`writeFile` sirve para escribir archivos.

```nim
writeFile("/tmp/ejemplo.txt", "Los datos van aca.")
var contenido = readFile("/tmp/ejemplo.txt")
echo contenido
```

# Leer y Escribir Variables de Entorno

`getEnv` sirve para leer Variables de Entorno.

`putEnv` sirve para escribir Variables de Entorno.

```nim
import os
putEnv("EXAMPLE", "value")
echo getEnv("EXAMPLE")
```


# Funciones

`proc` declara una nueva funcion, 
los argumentos llevan su tipo y el tipo de retorno va al final.

```nim
proc nombre(argumento0: int, argumento1: int): int =
  argumento0 + argumento1
```

Tambien se puede escribir en una linea

```nim
proc nombre(argumento0: int, argumento1: int): int = argumento0 + argumento1
```

Puede no retornar ningun tipo

```nim
proc nombre(argumento0: int, argumento1: int) = 
  echo argumento0 + argumento1
```

Puede no tomar ningun argumento

```nim
proc nombre(): int = 
  return 42
```

Una funcion sin nombre es una funcion anonima

```nim
proc (argumento0: float): float = argumento0 + 1.0
```

Mas ejemplos

```nim
proc saludar() = 
  echo "Hola Mundo"
```

Funcion que retorna muchas cosas juntas

```nim
proc retornaMuchasCosas(): auto =
  result = (clave0: 9, clave1: true, clave2: "texto")
```

Funcion Flecha (Arrow Functions) esta en [el modulo de azucar](https://nim-lang.github.io/Nim/sugar.html)

`import` importa modulos de la libreria estandard, o de terceros.

```nim
import sugar

let saludar = (argumento: int) => echo "Hola ", argumento
```

Otro ejemplo, pero sin argumentos

```nim
import sugar

let saludar = () => echo "ejemplo"
```

Arrow Function multi-linea

```nim
import sugar

let ejemplo = (c: int) => (
  let a = 1
  let b = 2
  a + b + c)

assert ejemplo(42) == 45
```


# Estructura de Programa

Para darle mas estructura puedes crear una funcion principal `main`, 
no es obligatorio, pero es recomendado.

`when` es un `if` pero que se evalua durante la compilacion.

`isMainModule` es `true` cuando es el modulo principal que se esta ejecutando.

```nim
proc main() =
  echo "Hola Mundo"

when isMainModule:
  main()
```

Programa de conversion de escalas de Temperatura

```nim
proc main(celsius: int) =
  let kelvin = celsius + 273
  let fahrenheit = float(celsius) * 1.8 + 32.0
  echo "Temperatura Celsius: ", celsius
  echo "Temperatura Fahrenheit: ", fahrenheit
  echo "Temperatura Kelvin: ", kelvin

when isMainModule:
  main(celsius = 22)
```


# Base64

`base64` sirve para convertir a Base64.

```nim
import base64
let datos = encode("Hello World")
assert datos == "SGVsbG8gV29ybGQ="
```


# Abrir navegador web

`browsers` sirve para abrir una direccion web en el navegador web.

```nim
import browsers
openDefaultBrowser("https://nim-lang.org")
```


# Busqueda Binaria

`algorithm` contiene algoritmos comunes, como ser la Busqueda Binaria.

```nim
import algorithm
assert binarySearch([0, 1, 2, 3, 4], 4) == 4
assert binarySearch([0, 1, 2, 3, 4], 2) == 2
```


## JSON

`json` tiene todo lo necesario para manipular datos JSON.

JSON se escribe literal en el codigo, 
el operador `%*` se encarga de "entender" el JSON.

```nim
import json

let datos = %*{
  "clave": "valor",
  "otro": 42,
  "ultimo": 2.5
}

assert datos is JsonNode
echo datos.pretty

writeFile("/tmp/ejemplo.json", datos.pretty)
echo parseFile("/tmp/ejemplo.json")
```


# Distancia de Levenshtein

`editdistance` implementa la Distancia de Levenshtein.

```nim
import std/editdistance
assert editdistance("Gatito", "Patito") == 1
```


# Random

`random` implementa generador de numeros al azar y utilidades de random.

```nim
import random
randomize()

let num = rand(99)  # Numero al azar entre 0 y 99
assert num in 0..99

let colores = ["rojo", "verde", "azul"]
let alazar = sample(colores)
assert alazar in colores
```


# HTTP

`httpclient` tiene un Cliente HTTP.

```nim
import httpclient
var cliente = newHttpClient()
echo cliente.getContent("http://nim-lang.org")
```


# Tipos

Puedes crear tus propios tipos usando `type`.

Los nombres de los tipos deben usar siempre la primer letra en mayuscula.

Este es un tipo vacio sin ningun atributo

```nim
type Nombre = object
```

Este tipo tiene atributos

```nim
type Nombre = object
  atributo: string  # Atributo de tipo string
  otro: int         # Atributo de tipo int
```

Tambien se puede agrupar tipos en un bloque `type`

```nim
type 
  TipoVacio = object

  Nombre = object
    atributo: string  # Atributo de tipo string
    otro: int         # Atributo de tipo int

  Otro = object
    foo: bool         # Atributo de tipo bool
```


# Orientacion a Objetos

Un tipo puede heredar de otro tipo usando `object of`

Todos los tipos heredan de un tipo raiz,
que es la madre de todos los tipos,
el objeto raiz es `RootObj`.

En este ejemplo `Gatito` hereda de `Animal`,
a su vez `Animal` hereda de `RootObj`.

```nim
type 
  Animal = ref object of RootObj
  
  Gatito = ref object of Animal
```


# Metodos en Objetos

Para tener funcionalidades en los objetos se puede darle funciones,
se le otorgan funcionalidad usando `self: Objeto`,
`self: Objeto` siempre debe ser el primer argumento.

```nim
type 
  Animal = ref object of RootObj
  Gatito = ref object of Animal

proc miau(self: Gatito) =
  echo "Miau Miau"

let gato = Gatito()
gato.miau()
```


# Constructores de Objeto

Para darle valores por defecto a los atributos de algun tipo se puede usar un Constructor,
un constructor es simplemente una funcion que retorna el tipo.

Por convencion usualmente se nombra al constructor como "new+tipo" o "init+tipo",
es decir para el tipo `Gatito` deberia ser
`newGatito()` o `initGatito()`

```nim
type 
  Animal = ref object of RootObj
  Gatito = ref object of Animal
    edad: int
    nombre: string

proc newGatito(edad: int, nombre: string): Gatito =
  Gatito(edad: edad, nombre: nombre)

proc miau(self: Gatito) =
  echo "Miau Miau"

let gato = newGatito(edad: 2, nombre: "Bastet")
assert gato.edad == 2
assert gato.nombre == "Bastet"
gato.miau()
```

Volvamos a darle mas estructura de programa

```nim
type 
  Animal = ref object of RootObj
  Gatito = ref object of Animal
    edad: int
    nombre: string

proc newGatito(edad: int, nombre: string): Gatito =
  Gatito(edad: edad, nombre: nombre)

proc miau(self: Gatito) =
  echo "Miau Miau"

proc main(edad: int, nombre: string) =
  let gato = newGatito(edad: edad, nombre: nombre)
  assert gato.edad == 2
  assert gato.nombre == "Bastet"
  gato.miau()

when isMainModule:
  main(edad = 2, nombre = "Bastet")
```


# Colecciones

Colecciones sirven para agrupar valores dentro de un mismo contenedor.

No veremos cada una en detalle por que eso ya es parte de la libreria estandard, 
pero aqui esta un resumen rapido de los contenedores:

|       | Indexado | Indice | Tipos     | Capacidad | Longitud |
|-------|----------|--------|-----------|-----------|----------|
| [array](https://nim-lang.github.io/Nim/manual.html#types-array-and-sequence-types) | Si       | `0`    | Homogeneo | Estatica | Estatica |
| [set](https://nim-lang.github.io/Nim/manual.html#types-set-type)   | No       | Valor  | Homogeneo | Dinamica | Dinamica |
| [seq](https://nim-lang.github.io/Nim/manual.html#types-array-and-sequence-types)   | Si       | `0`    | Homogeneo | Dinamica  | Dinamica |
| [tabla](https://nim-lang.github.io/Nim/tables.html) | No       | Clave  | Homogeneo | Dinamica  | Dinamica |
| [tupla](https://nim-lang.github.io/Nim/manual.html#types-tuples-and-object-types) | Si       | `0`/Clave | Heterogeneo | Estatica  | Estatica |
| [JSON](https://nim-lang.github.io/Nim/json.html)  | No       | Clave  | Heterogeneo    | Dinamica  | Dinamica |
| [BTrees](https://nim-lang.github.io/fusion/src/fusion/btreetables.html)  | No       | Clave  | Homogeneo | Dinamica  | Dinamica |
| [CritBits](https://nim-lang.github.io/Nim/critbits.html) | No     | Clave  | Homogeneo | Dinamica  | Dinamica |

- Si necesitas una lista usa `seq`.
- Si necesitas un diccionario mapeado usa `table`.
- Si necesitas tipos mezclados usa `JSON`.
- Si necesitas retornar muchos valores de una funcion usa `tuple`.

Existen mas contenedores pero esos son los mas comunes.

Existen mas contenedores en paquetes de terceros.

Un contenedor no es mas que un Tipo,
puedes crear tus propios contenedores personalizados.


# Frontend

Puede correr el codigo en el navegador web,
hay modulos en la libreria estandard orientados a la web.

Los modulos que solo funcionan para JavaScript,
su nombre comienza con "js",
por ejemplo [jsfetch](https://nim-lang.github.io/Nim/jsfetch.html), [jsre](https://nim-lang.github.io/Nim/jsre.html), [jsbigints](https://nim-lang.github.io/Nim/jsbigints.html), etc etc.

[Tambien puede correr el codigo en NodeJS,
con paquetes de terceros.](https://github.com/juancarlospaco/nodejs)

...y en cualquier contexto que tenga un interprete de JavaScript.


# Documentacion

- [Pagina de la libreria estandard.](https://nim-lang.github.io/Nim/lib.html)
- [Manual de usuario](https://nim-lang.github.io/Nim/manual.html)
- [Indice de documentacion de la libreria estandard.](https://nim-lang.github.io/Nim/theindex.html)
- [Indice de documentacion de las extensiones de stdlib.](https://nim-lang.github.io/fusion/theindex.html)
- [Guia detallada para desarrolladores Python.](https://github.com/nim-lang/Nim/wiki/Nim-for-Python-Programmers#table-of-contents)
- [Guia detallada para desarrolladores TypeScript.](https://github.com/nim-lang/Nim/wiki/Nim-for-TypeScript-Programmers#table-of-contents)


# Gracias por leer

[![](https://thepracticaldev.s3.amazonaws.com/i/4huq62a5r8tck64apdtd.png)](https://nim-lang.org)

- [Chat en Espanol, grupo de usuarios](https://t.me/NimArgentina)
- [Chat en Ingles, official.](https://discord.gg/nim)

👑