Skip to content

Latest commit

 

History

History
627 lines (458 loc) · 15.5 KB

02-basics.adoc

File metadata and controls

627 lines (458 loc) · 15.5 KB

Nociones Básicas

Todo lenguaje de programación define estructuras base que determinan la forma de escribir el lenguaje. El siguiente capítulo detalla las normas básicas con las que funciona Wren.

Tipos de datos

Todos los tipos de datos en Wren son objetos, instancias de una clase específica. Las operaciones son métodos disponibles en dichas clases.

Wren

Estas son las clases disponibles dentro del lenguaje Wren "vainilla".

  1. Bool

  2. Class

  3. Fiber

  4. Fn

  5. List

  6. Map

  7. Null

  8. Num

  9. Object

  10. Range

  11. Sequence

  12. String

  13. System

  14. Meta

  15. Random

Importante

No se puede heredar desde estas clases debido al problema de Reentrancia (Wren no tiene esta capacidad). Para extender solo es posible usando la composición (Crear una nueva clase). Esto significa que al llamar a un método de una clase que herede de un tipo base, la máquina virtual no podrá diferenciar los métodos (Ya que son clases creadas con código de bajo nivel), lo que puede causar errores, por esta razón no está permitido heredar de las clases primitivas.

Wren CLI

Estas clases son exclusivas de la Wren CLI. No estarán disponibles fuera del entorno de ejecución de este intérprete de Wren.

  1. Directory

  2. File

  3. Stat

  4. Stdin

  5. Stdout

  6. Platform

  7. Process

  8. Scheduler

  9. Timer

Variables

Una variable es un contenedor de un valor específico. Este valor puede ser una cadena de caracteres, númerico, booleano u otro tipo de objeto.

var mensaje = "Hola mundo Wren"
System.print(mensaje)

Se puede modificar el valor posteriormente

var mensaje = "Hola mundo Wren"
System.print(mensaje)

mensaje = "El chercán es una bonita ave"
System.print(mensaje)

Si usamos una variable sin haberla declarado antes recibiremos un error similar a lo siguiente:

var mensaje = "Hola"
System.print(mensaj)
[repl line 1] Error at 'mensaj': Variable is used but not defined.

Debemos siempre procurar que todas nuestras variables estén declaradas dentro del contexto y que no existan errores de escritura en sus nombres.

Identificadores

Similar al Lenguaje C, para los indentificadores (nombres de variables, clases, metodos, funciones) se pueden utilizar los caracteres de la lista ascii y comenzar con un caracter alfabético o guión bajo. Los identificadores en Wren diferencian entre mayúsculas y minúsculas. Solo se permiten letras (A - Z, a - z), números (0 - 9) y guión bajo (_). No se permiten espacios o comenzar con un número o guión alto (-).

Ejemplo de Identificadores válidos

hola
camelCase
PascalCase
_under_score
abc123
TODAS_MAYUSCULAS

Ejemplo de Identificadores no válidos

13hola
mi-variable
$miVariable
mi variable
ñandú
👨miMetodo
Mi👩clase

Unicode

No están permitidos caracteres UTF-8 como la Ñ o los emojis en los identificadores. Sin embargo las Strings las soportan en su contenido sin problemas. Hay lenguajes como Swift o Emoji Code que si soportan identificadores con emojis, aunque la utilidad de esta práctica es debatible.

EmojiCode
🏁 🍇
  😀 🔤Hello World!🔤❗️
🍉

Identificadores que inician con guión bajo

Un caso especial es para los identificadores con guión bajo como _color (un guión bajo al principio) y __sabor (dos guiones bajos al principio). Con un guión bajo indica que es una propiedad de instancia, mientras que con dos guiones bajos indican que es una propiedad de clase. Más detalles en la sección de Clases.

Identificadores de clase

Para Wren es importante que las clases comiencen su nombre con mayúsculas. Si bien es posible definir clases con letras minúsculas no es recomendable hacerlo debido a que pueden colisionar con variables dentro del contexto de clase o método.

Ejemplos

// Asociamos la clase `Numero` como un substituto para llamar a la clase `Num`
var Numero = Num
// Dará error. No se puede heredar de las clases primitivas.
class Numero is Num {}
// Es posible nombrar con minúsculas, pero puede dar
// conflictos de contexto al momento de usarlo dentro
// de una clase. (Puede hacer colisión con nombres de variable)
class numero {}

Recomendaciones

  • Los nombres de los identificadores deben ser descriptivos, sin ser muy largos. Ejemplo "ruedasMotocicleta" es mejor que solo "ruedas" y "numero_de_ruedas_en_una_moto".

  • La letra "l" mínuscula y la letra "O" mayúscula puede ser confundida con el número "1" y "0" respectivamente.

Saltos de línea

Wren utiliza los saltos de línea (\n), por lo que no es necesario utilizar el punto y coma (;) para separar instrucciones. Sin embargo omite los saltos de línea si la instrucción espera más información para ser válida.

Ejemplo: Lista de elementos

var animales = [
  "perro",
  "gato",
  "condor",
  "huemul"
]

Ejemplo: Parámetros de un método

MiClase.metodo(
  parametro1,
  parametro2,
  parametro3
)

Ejemplo: Condicionales

Los saltos de línea son considerados en la declaración de bloques de código. Por lo tanto es importante la posición de las llaves ("{}") dentro de una instrucción.

// Correcto
if (condiccion == true) { x = 0 }
// Correcto
if (condiccion == true)   {
  x = 0
}
// Correcto
if (condicion == true) x = 0

Condicionales de una sola línea. Tienen el formato de condición ? retorno si es verdadero : retorno si es falso.

  // Si la condición es verdadera, x será 0. Si es falsa, x será 1
  var x = condicion ? 0 : 1

Utilizando el operador OR (||). Se puede asignar un valor predeterminado a una variable.

  // Si x es nulo se asignará 0. Caso contrario mantiene su valor anterior.
  x = x || 0

Si la llave no está presente en la misma línea, gatillará un error.

// Error
if (condiction == true)
{
  x = 0
}

Ejemplo: Generar un número al azar del 0 al 9

Al considerar los saltos de línea significativos, provoca un comportamiento inusual al momento de llamar métodos.

Los números pseudo aleatorios son generados utilizando la clase `Random`. Para generar un número del 0 al 9 se necesita utilizar 10, ya que el número máximo utilizado no está incluido dentro de la secuencia. Es decir se incluye 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 (total 10 números) dentro de los posibles resultados.

Instrucción en una sola línea.

Random.new().int(10)

Esto no es válido en Wren (Pero si es válido en la mayoría de los lenguajes de programación).

Random
.new()
.int(10)

Para ser válido necesitamos poner un punto al final de la línea.

Random.
new().
int(10)

Este comportamiento inusual espera ser reparado en la versión 0.4.

Ejemplo: Error

La siguiente línea arroja error debido a que no tiene un salto de línea o una operación.

Random.new().int(10) Random.new().int(10)

Retorno implícito

Al tener instrucciones de una sola línea, Wren asume la existencia de una instrucción de retorno ("return"). Si no hay un valor, se asume que el valor de retorno es null.

class Auto {
  // ruedas retornará siempre el valor "4"
  ruedas {4}

  // similar a ruedas, pero usando una instrucción "return" explícita
  puertas {
    return 2
  }
}

Palabras Reservadas

Wren es un lenguaje simple y pequeño. Sus palabras reservadas son las siguientes:

break class construct else false for foreign if import
in is null return static super this true var while

Una palabra reservada tiene un significado especial para Wren, por lo que no se recomienda usarlas para llamar a variables o clases. De esta forma se evita conflictos y confusiones.

Caracteres significativos

  • Caracteres comunes (+ - * / % < > = ! ( ) [ ] | . " { } , & ^ ? : ~ _)

  • Retorno de carro (\n)

Funciones (Fn)

Las funciones en Wren son instancias de la clase Fn y deben ser llamadas utilizando su método call(). Al ser un objeto más, pueden ser pasadas como parámetros a métodos u otras funciones.

var mostrar = Fn.new {|parametro|
  System.print(parametro)
}

// muestra: hola
mostrar.call("hola")

Fibras (Fiber)

Son similares a las funciones, con la diferencia en que se ejecutarán en un hilo (thread) distinto. Además del método call() tienen un método try() usado normalmente para "atajar" errores.

var mostrar = Fn.new {|parametro|
  System.print(parametro)
}

// Si existe un error se almacenará en la variable error
var error = Fiber.new { mostrar.call("hola") }.try()

Clases (class)

Las clases se declaran utilizando la palabra clave class antes del nombre.

class MiClase {}

La herencia se define utilizando la palabra clave is. Solo se heredan los métodos de instancia. Propiedades de clase (_var) y de instancia (_var), constructores y métodos de clase (_static) no son heredados (todos son privados).

class Animal {
  // la propiedad _nombre solo puede ser accesible
  // a clases hijos si se definen como métodos accesadores
  nombre {_nombre}

  // creamos un mutador de la clase
  nombre = (value) {
    _nombre = value
  }

  imprimir() {
    System.print(nombre)
  }
}

class Perro is Animal {

  imprimir() {
    System.print("imprimir en hijo")
  }

  // constructores no son heredables
  construct nuevo(nom) {
    // llamamos al método mutador de la clase padre
    this.nombre = nom

    // Usamos `super` para llamar a un método de la clase padre
    // Muestra "Joe" usando el método accesador del padre
    super.imprimir()

    // Muestra null
    System.print(_nombre)
  }
}

var perrito = Perro.nuevo("Joe")

Para definir un constructor se utiliza la palabra clave construct. Para llamar a la instancia se usa this (opcional).

class Auto {
  construct nuevo() {
    System.print(this)
  }
}

Para definir un método o propiedad de clase se utiliza la palabra clave static.

class Fruta {
  // accesador (getter)
  static cantidad {__cantidad}

  // mutador (setter)
  static cantidad = (value) {
    // doble guión bajo indica propiedad de clase
    __cantidad = value
  }

  // método de clase
  static comer() {
    cantidad = cantidad - 1
  }
}

Para saber el padre de la clase se utiliza la propiedad supertype. Esta propiedad debe ser llamada recursivamente para obtener el árbol de herencia.

  • La clase primitiva base de todas es Object.

  • No se puede heredar de los primitivos como String, Num, Map, entre otros.

class Animal {}

class Perro is Animal {}

System.print(Perro.supertype) // Animal

if (Perro.supertype == Animal) {
  // Perro es animal
}

Si queremos saber el tipo de una instancia se puede usar is.

var perrito = Perro.new()
if (perrito is Perro) {
  // perrito es Perro
}

if (Perro is Animal) {
  // Falso, ya que son clases distintas
}
  • Las propiedades type, supertype y name vienen dentro de cada clase.

  • Object es la única clase que no tiene supertype.

class Animal {}

class Perro is Animal {}

System.print(Perro.name)
System.print(Perro.type)

System.print(Perro.supertype.name)
System.print(Perro.supertype.type)
System.print(Perro.supertype.supertype)

System.print(Object.supertype)

Control de Flujo

Existen las estructuras de control de flujo tradicionales: if, for, while y break.

if (condicion) {
  // codigo
}
while (condicion) {
  // codigo
}
for (elemento in secuencia) {
  // codigo
  break
}

Importar

Para separar el código en diversos archivos esta la instrucción import. El leer los archivos e importar su contenido dependerá del intérprete.

La instrucción import va de la mano con la palabra for.

// El módulo se llama "random" e importamos la clase "Random" que está dentro de este módulo
import "random" for Random

Es la clase padre de todas las demás clases en Wren.

Algunos métodos destacables:

  • toString: Convierte el objeto a un String.

  • type: Retorna la clase a la cual el pertenece el objeto.

// Convertimos los datos a un String serializable
3.toString
["1",2,"tres", true].toString

// similar a "1" == "2", pero sin posibilidad de sobre escribir el operador
Object.same("1", "2")

// verificamos que la instancia pertenezca a la clase
if ("1" is String) {
  System.print("hola")
}

Comentarios

Cuando se comienza a escribir código más elaborado, existe mayor necesidad de pensar como codificar las soluciones a los problemas. Una vez que se soluciona el problema, se dedicará una gran cantidad de tiempo en revisar y perfeccionar el algoritmo.

Los comentarios te permiten escribir en lenguaje humano como Inglés o Español, dentro de los programas.

Los comentarios en Wren utilizan la misma sintaxis que el Lenguaje de Programación C.

Los símbolos son los siguientes: /* */ (multi línea) y // (línea única).

// Comentario de una sola línea

/*
Este comentario
tiene múltiples
líneas
*/

Se pueden anidar los comentarios. útil para comentar código que ya tenga comentarios.

/*
Este comentario
tiene múltiples
líneas.
  /* También puedes incluir comentarios,
  dentro de comentarios multi línea.
  */
*/

Tip: Comentarios Tijera

Puedes combinar los comentarios de una sola línea con los de múltiples líneas para comentar/descomentar rápidamente secciones de código. Se llaman comentarios tijera por que pueden "cortar" un código para no ser ejecutado.

// /*
  codigo()
// */

Al eliminar el comentario de la primera línea, el código será comentado. De esta forma rápidamente puedes activar o desactivar secciones de código.

/*
  codigo()
// */

Puede aún ser más simplificado de esta forma

//*
  codigo()
// */

Si se elimina el primer / el código será comentado. Por lo que se ahorra un par de movimientos al realizar el comentario.

/*
  codigo()
// */

Tip: Comentarios de parámetros

En Wren no es posible llamar a los parámetros por su nombre. Por lo que si utilizas una función con algunos parámetros, puede ser útil comentarlos.

circulo(/* x */ 10, /* y */ 20, /* radio */ 10)

O mejor aún utilizar variables con nombres significativos

var x = 10
var y = 20
var radio = 10
circulo(x, y, radio)

¿Cómo es un buen comentario?

  • Es completo, corto y directo. La mayoría de los comentarios deberían ser escritos en párrafos.

  • Explica tu forma de pensar, para que cuando regreses a leer el código en el futuro puedas comprender cómo se ha resuelto el problema.

  • También explica pensando en otros, para que otras personas puedan trabajar en tu código y entender cómo lo haz estructurado.

  • Explica una sección difícil con mayor detalle.

¿Cuándo comentar?

  • Cuando tienes que pensar cómo funciona el código antes de escribirlo.

  • Cuando probablemente olvides como estabas resolviendo un problema.

  • Cuando exista más de una forma de resolver un problema.

  • Cuando es poco probable que otros comprendan cómo haz resuelto un problema.

Escribir buenos comentarios es un indicador de un buen programador. Úsalos siempre. Verás comentarios a lo largo de los ejemplos en este documento.

Límites

  • Máximo de 16 parámetros en una función o método.

  • Máximo de 255 propiedades en una clase (incluyendo la herencia).