Variables y tipos

Si vienes de Python, JavaScript o Java, estás acostumbrado a que un número sea simplemente un número. En Vesta eliges cuántos bits ocupa, y esa elección tiene consecuencias.

site/snippets/types.vx
i32 main() {
    // Enteros con signo: el numero dice cuantos bits ocupa.
    i8  pequeno = 100;
    i32 normal  = 70000;
    i64 grande  = 9000000000;

    // Sin signo: mismo tamano, pero solo valores positivos.
    u8  byte  = 255;
    u64 ancho = 18000000000000000000;

    // Coma flotante.
    f32 simple = 2.5;
    f64 doble  = 3.14159;

    // Booleano y caracter.
    bool activo = true;
    char letra  = 'A';

    // Cadena.
    string saludo = "hola";

    println("i8=${pequeno} i32=${normal} i64=${grande}");
    println("u8=${byte} u64=${ancho}");
    println("f32=${simple} f64=${doble}");
    println("bool=${activo} char=${letra:char} string=${saludo}");

    // El mismo numero, escrito en cuatro bases.
    i64 dec = 42;
    i64 hex = 0x2A;
    i64 bin = 0b101010;
    i64 oct = 0o52;
    println("42 = ${dec} = ${hex} = ${bin} = ${oct}");

    // El tipo se puede deducir del valor inicial.
    auto contador = 0;
    auto ratio = 1.5;
    println("auto: ${contador} y ${ratio}");

    return 0;
}
i8=100 i32=70000 i64=9000000000
u8=255 u64=18000000000000000000
f32=2.5 f64=3.14159
bool=true char=A string=hola
42 = 42 = 42 = 42 = 42
auto: 0 y 1.5

Por qué el tipo dice su tamaño

i64 significa entero con signo de 64 bits. El número no es decoración: dice exactamente cuánta memoria ocupa la variable y, por tanto, qué valores caben en ella.

Eso importa por dos motivos. El primero es la capacidad: en un i8 caben 256 valores distintos y ni uno más, así que si guardas 300 el resultado no será 300. El segundo es el espacio: un millón de i64 ocupa ocho megabytes y un millón de i8 ocupa uno. Cuando manejas estructuras grandes, o hablas con hardware que espera un formato exacto, esa diferencia es la razón de ser del lenguaje.

Los lenguajes que ocultan el tamaño eligen por ti, normalmente el mayor, y a cambio te ahorran pensar. Vesta te deja elegir porque a veces la elección es el problema que estás resolviendo.

Los tipos primitivos

Enteros con signo:

TipoBitsDesdeHasta
i88-128127
i1616-32 76832 767
i3232-2 147 483 6482 147 483 647
i6464-9 223 372 036 854 775 8089 223 372 036 854 775 807

Enteros sin signo:

TipoBitsDesdeHasta
u880255
u1616065 535
u323204 294 967 295
u6464018 446 744 073 709 551 615

Con signo o sin signo cambia qué valores caben, no cuántos. Un u8 y un i8 ocupan un byte y admiten 256 valores distintos cada uno; lo que cambia es dónde empieza y dónde acaba el rango.

Y el resto:

TipoBitsQué es
f3232Coma flotante de precisión simple
f6464Coma flotante de precisión doble
bool8true o false
char32Un punto de código Unicode
string-Texto, gestionado por el runtime

Cuatro maneras de escribir el mismo número

i64 dec = 42;
i64 hex = 0x2A;
i64 bin = 0b101010;
i64 oct = 0o52;

Son el mismo valor escrito en base diez, dieciséis, dos y ocho. La base que elijas depende de lo que estés expresando: una máscara de bits se lee mucho mejor en binario que en decimal.

Dejar que el tipo se deduzca

Cuando el valor inicial ya dice de qué tipo se trata, auto evita repetirlo:

auto contador = 0;      // i64
auto ratio = 1.5;       // f64

Sirve para variables locales. Es azúcar, no magia: el tipo queda fijado en la compilación igual que si lo hubieras escrito.

Hoy auto falla con las cadenas. auto s = "hola"; no deduce string, y al imprimirlo verás un número en lugar del texto. Escribe string s = "hola"; hasta que se corrija.

char es un número

Un char guarda un punto de código Unicode, y al interpolarlo verás ese número:

char letra = 'A';
println("${letra}");         // 65
println("${letra:char}");    // A

${expr:char} es un especificador de formato: dice cómo quieres que se escriba el valor, no qué valor es. Hay más, como :hex para hexadecimal, y tienen su capítulo en la parte de cadenas.

Convertir entre tipos

Pasar a un tipo más ancho no pierde nada y no hace falta pedirlo:

i32 a = 7;
i64 b = a;      // cabe de sobra

Al revés sí se pierde información, y aquí conviene ir con cuidado:

i64 grande = 300;
i8 pequeno = (i8) grande;   // 44

300 no cabe en un i8, así que se quedan los bits de abajo y el resultado es 44. El (i8) es un cast: le dices al compilador que sabes lo que haces.

El cast no es obligatorio, y esa es la trampa. i8 pequeno = grande; sin cast también compila hoy, y también da 44, sin ningún aviso. Escribe el cast siempre que estreches: no cambia el resultado, pero deja constancia de que era intencionado.

Constantes

const marca un valor que no se puede reasignar:

const i64 MAXIMO = 100;

Intentar cambiarlo es un error de compilación. Recuerda la limitación del capítulo anterior: a nivel superior, las constantes de f32 y f64 todavía no resuelven su nombre al usarlas.

Lo que viene

Ya tienes valores. Lo siguiente es operar con ellos: aritmética, comparaciones, lógica de bits y las reglas de precedencia.