Mostrando entradas con la etiqueta ballerina. Mostrar todas las entradas
Mostrando entradas con la etiqueta ballerina. Mostrar todas las entradas

sábado, 27 de diciembre de 2025

Ballerina: una comparativa con Rust

Como mencionamos en la entrega anterior, Ballerina es un lenguaje de programación en crecimiento. No posee una comunidad tan grande como otros lenguajes (Java, C#, C/C++, Python, etc.), pero así empiezan todos. Ballerina junto otros lenguajes como Go y Rust han cobrado cierto interés en el mundo de la programación, servicios Cloud, servicios REST y hasta la I.A.

En esta ocasión haremos una comparativa con Rust, un lenguaje de programación que tiene inspiración en lenguajes como C y C++, tomando lo mejor de ellos y descartando lo que no es necesario y Ballerina, un lenguaje que ha cobrado importancia en el desarrollo en la nube. Ambos lenguajes han aprendido de los mejores e incluso han ido superándolos incluso en velocidad y rendimiento.

Ballerina y Rust son lenguajes muy distintos: Ballerina está orientado a integración y microservicios, mientras que Rust se centra en sistemas de alto rendimiento y seguridad de memoria.

Veamos una tabla comparativa:

Comparativa: Ballerina vs Rust
Aspecto Ballerina Rust
Paradigmas Multiparadigma con foco en integración, concurrencia y servicios distribuidos; código con visualización de flujos y llamadas. Multiparadigma (imperativo y funcional) orientado a sistemas, control de bajo nivel y seguridad de memoria.
Casos de uso Integración de APIs, microservicios, orquestación de endpoints, aplicaciones cloud-native y seguridad en comunicaciones. Sistemas operativos, motores de juegos, programación embebida, CLI y servicios de alto rendimiento.
Compilación y ejecución Compila con bal build; ejecuta con bal run archivo.bal. Soporte integrado para Docker/Kubernetes. Compila con rustc archivo.rs; ejecuta con ./archivo. En proyectos se usa Cargo (cargo build, cargo run).
Tipos de variables Tipado estático: int, float, boolean, string; estructurados: record, map, array, table. Tipado estático con inferencia: primitivos (i32, f64, bool, char) y avanzados (struct, enum, tuple).
Estructuras de control if, while, foreach, match; concurrencia con workers y fork/join. if, loop, while, for, match con patrones; concurrencia segura con async/await y ownership.
Estructuras de datos record (tipo estructurado), map, array, table. struct, enum, tuple, array, Vec<T>, HashMap<K,V>.
Concurrencia Modelo de trabajadores, transacciones y flujos de integración; primitivas para servicios distribuidos. Seguridad de datos en concurrencia mediante ownership, borrowing y tipos como Arc/Mutex.
Ecosistema Enfocado en integración (HTTP, gRPC, GraphQL, Kafka) con librerías estándar orientadas a servicios. Amplio ecosistema de crates para sistemas, redes, WebAssembly, embebidos y desarrollo multiplataforma.
Curva de aprendizaje Suave para integraciones y microservicios; diseño opinado para flujos de red. Pronunciada por el ownership y el borrow checker; recompensa con rendimiento y seguridad.

Puntos clave entre Ballerina y Rust

Ambos lenguajes tienen similitudes y diferencias, aquí los puntos claves:

  • Enfoque distinto: Ballerina es un lenguaje de integración; Rust es un lenguaje de sistemas. 
  • Compilación: Rust ofrece control de bajo nivel y optimización; Ballerina simplifica despliegues en entornos distribuidos. 
  • Datos y control: Rust tiene estructuras más ricas y flexibles; Ballerina prioriza simplicidad y seguridad en datos de red. 
  • Concurrencia: Ambos soportan concurrencia, pero Rust lo hace con un modelo de ownership y Ballerina con workers y diagramas visuales.

Ejemplo 1. Crear un sencillo "Hola, mundo" en Ballerina y Rust. Esto nos servirá para ver cómo se compila y ejecuta un programa en cada lenguaje.

Empecemos con Ballerina. Compilaremos y ejecutaremos un archivo llamado holamundo.bal:

import ballerina/io;

public function main(string... args) {
    io:println("\t Hola, mundo en Ballerina");
}

Compilamos y ejecutamos:

$ bal run holamundo.bal

El código se compilará y se ejecutará en la terminal, la salida será:

Compiling source
        holamundo.bal

Running executable

         Hola, mundo en Ballerina

Ahora con Rust, compilaremos y ejecutaremos el archivo holamundo.rs:

fn main() {
    println!("\t Hola mundo en Rust");
}

Compilamos:

$ rustc holamundo.rs

Se creará un ejecutable:

$ holamundo.exe

Salida:

         Hola mundo en Rust

¿Qué podemos notar?

  • Ambos lenguajes son compilados. 
  • Ballerina es más similar Java, es dependiente de la JVM y genera bytecodes
  • Rust es más similar a C/C++, genera ejecutables nativos (*exe). 
  • La extensión de un programa Ballerina es *bal.
  • La extensión de un programa Rust es *rs.

Tipos de datos en Ballerina y Rust

Como mencioanmos, ambos lenguajes son compilados. También comparten la característica de ser de tipado estático. Eso quiere decir que debes especificar el tipo de datos a usar. No como lenguajes como Python o Ruby donde "una variable es una variable".

Tipos de datos en Ballerina vs Rust
Categoría Ballerina Rust
Primitivos numéricos int, float, decimal i8, i16, i32, i64, u8, u16, u32, u64, f32, f64
Booleanos boolean bool
Texto y caracteres string char, String (tipo de colección)
Compuestos record, map, array, table struct, enum, tuple, array, Vec<T>, HashMap<K,V>
Especiales nil (valor nulo), error, any Option<T>, Result<T,E>, unit (())
Concurrencia Workers y canales integrados para paso de mensajes Tipos seguros para concurrencia: Arc, Mutex, RwLock

Ejemplo 2. Crear un programa en ambos lenguajes con el objetivo de ver los tipos de datos en cada lenguaje.

En Ballerina:

tipos.bal

import ballerina/io;

type Persona record {|
    string nombre;
    int edad;
|};

enum Estado {
    ACTIVO,
    INACTIVO
}

public function main() {
    int edad = 30;
    float altura = 1.75;
    boolean activo = true;
    string inicial = "C"; // no existe 'char'
    string nombre = "Thomas Muller.";

    int[] numeros = [1, 2, 3, 4];
    [int, float, string] tupla = [25, 1.80, "Ana"];

    Persona p = { nombre: "Luis", edad: 40 };
    Estado estado = ACTIVO;

    map<string> capitales = { "MX": "Ciudad de México", "US": "Washington" };

    int|error resultado = 10; // Result
    float? opcion = 3.14;     // Option

    
    int contador = 0;
    fork {
        worker w1 {
            int local = contador;
            local += 1;
            io:println("Worker 1 contador: " , local.toString());
        }
        worker w2 {
            int local = contador;
            local += 1;
            io:println("Worker 2 contador: " , local.toString());
        }
    }

	io:println("Nombre: " + nombre + ", Edad: " + edad.toString());
    string capitalMX = capitales["MX"] ?: "Desconocido";
    io:println("Capital de MX: " + capitalMX);
    io:println("Persona: " + p.toString());
    io:println("Contador final (simulado): " + contador.toString());
}

Compilamos y ejecutamos:

$ bal run tipos.bal

Salida:

Nombre: Thomas Muller., Edad: 30
Capital de MX: Ciudad de México
Persona: {"nombre":"Luis","edad":40}
Contador final (simulado): 0
Worker 2 contador: 1
Worker 1 contador: 1

En Rust:

tipos.rs

fn main() {
    
    let edad: i32 = 30;
    let altura: f64 = 1.75;
    let activo: bool = true;
    let inicial: char = 'C';
    let nombre: String = String::from("Thomas Muller.");

    
    let numeros: [i32; 4] = [1, 2, 3, 4];
    let tupla: (i32, f64, &str) = (25, 1.80, "Ana");

    struct Persona {
        nombre: String,
        edad: i32,
    }
    let p = Persona { nombre: String::from("Luis"), edad: 40 };

    enum Estado {
        Activo,
        Inactivo,
    }
    let estado = Estado::Activo;

    use std::collections::HashMap;
    let mut capitales = HashMap::new();
    capitales.insert("MX", "Ciudad de México");
    capitales.insert("US", "Washington");

    let resultado: Result<i32, &str> = Ok(10);
    let opcion: Option<f64> = Some(3.14);

   
    use std::sync::{Arc, Mutex};
    use std::thread;

    let contador = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..2 {
        let contador = Arc::clone(&contador);
        let handle = thread::spawn(move || {
            let mut num = contador.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

    for h in handles {
        h.join().unwrap();
    }

    println!("Nombre: {}, Edad: {}", nombre, edad);
    println!("Capital de MX: {}", capitales["MX"]);
    println!("Persona: {} ({})", p.nombre, p.edad);
    println!("Contador final: {}", *contador.lock().unwrap());
}

Compilamos:

$ rustc tipos.rs

Se creará un ejecutable:

$ tipos.exe

Salida:

Nombre: Thomas Muller., Edad: 30
Capital de MX: Ciudad de México
Persona: Luis (40)
Contador final: 2

Podríamos continuar con las comparaciones con estructuras de datos, acceso a archivos, acceso a base de datos y hasta servicios REST. Sin embargo, lo haremos en otra ocasión.

Conclusiones

Es importante hacer notar que:

  • Rust: curva de aprendizaje más pronunciada por su sistema de ownership y borrow checker
  • Ballerina: menos comunidad y ecosistema que Rust; puede ser limitante fuera del ámbito de integración.

Ambos lenguajes tienen un propósito, resuelven problemas distintos. No son competidores.

Enlaces:

https://rust-lang.org/
https://ballerina.io/
https://www.infoq.com/articles/ballerina-integration-tutorial-part-2/
https://www.infoq.com/articles/ballerina-microservices-language-part-1/



jueves, 25 de diciembre de 2025

Ballerina: un lenguaje en crecimiento

En una entrega anterior vimos un breve vistazo a Ballerina, un lenguaje de programación dependiente de la JVM. Diseñado por WSO2 para programadores de aplicaciones de la era de la nube.

Lanzado en 2017, con versión estable en 2022, Ballerina aún es joven y no tiene la misma comunidad que Java o Go.

Empresas como WSO2, MOSIP y RAAPID.AI usan Ballerina principalmente para integración de sistemas, microservicios y manejo de datos sensibles en entornos distribuidos. Su enfoque está en la orquestación de APIs, seguridad en comunicaciones y procesamiento de datos en la nube.

Empresas que usan Ballerina y casos de uso
Empresa / Proyecto Uso principal de Ballerina Beneficio clave
WSO2 Integración de sistemas empresariales y orquestación de APIs Resuelve el “integration gap” entre microservicios y productos de integración
MOSIP Integración dirigida por eventos con WebSubHub Manejo eficiente de eventos y flujos de datos en sistemas de identidad nacional
RAAPID.AI Integración de datos clínicos Interoperabilidad y unificación de datos médicos dispersos
Localazy Hub Aplicaciones en red y microservicios Seguridad integrada (TLS/SSL) y soporte nativo para Docker/Kubernetes

¿Por qué Ballerina?

  • Diseñado para integración: A diferencia de lenguajes genéricos, Ballerina entiende protocolos, formatos y conectores desde el núcleo. 
  • Microservicios y APIs: Ideal para arquitecturas distribuidas, con soporte nativo para REST, gRPC y mensajería. 
  • Seguridad embebida: TLS/SSL y políticas de seguridad por diseño. 
  • Cloud-native: Integración directa con Docker y Kubernetes, lo que lo hace atractivo para DevOps y despliegues modernos.

Consideraciones y retos

  • Adopción limitada: Aunque potente, Ballerina aún es joven (lanzado en 2017, con versión estable en 2022) y no tiene la misma comunidad que Java o Go. 
  • Nicho de integración: Su mayor valor está en proyectos donde la orquestación de servicios y APIs es crítica; fuera de ese ámbito, otros lenguajes pueden ser más prácticos. 
  • Curva de aprendizaje: Su enfoque visual (diagramas de secuencia y flujos) puede ser novedoso pero requiere adaptación.

Creando un proyecto sencillo con Ballerina

Para esto requerimos instalar Ballerina:

https://ballerina.io/downloads/

1. Una vez instalado comprobamos la versión instalada:

$ bal version

2. Creamos el proyecto:

$ bal new hello_world
$ cd hello_world

3. Editamos el archivo main.bal:

import ballerina/io;

public function main() {
    io:println("Hola, mundo");
}

4. Ejecutamos el código:

$ bal run

Salida:

Hola, mundo

Revisemos la estructura del proyecto:

  • Ballerina.toml: Metadatos del paquete (nombre, versión). 
  •  hello_world/main.bal: Punto de entrada (main) del programa. 
  •  target/ (se crea al compilar): Artefactos y compilados. 
  •  Module.md: Documentación del módulo.

También tenemos la opción de crear un ejecutable (como los JARS):

$ bal build

Y ejecutarlo:

$ bal run target/bin/hello_world.jar

Y si preguntan ¿Por qué se crea un JAR? Es porque Ballerina es un lenguaje dependiente de la JVM.

Ahora veamos algo más interesante: crear un servicio HTTP.

Editemos el archivo main.bal:

import ballerina/http;

service / on new http:Listener(8080) {
    resource function get hello() returns string {
        return "Hola, mundo";
    }
}

Ejecutemos:

$ bal run

Abrimos el navegador en la ruta: http://localhost:8080/hello

Salida:

Hola, mundo

Como se puede observar, Ballerina tiene mucho que ofrecer para los desarrolladores. Desde los que vienen de C, C++, PHP, Python, Java, C#, Go y Rust.

Enlaces:

https://alquimistadecodigo.blogspot.com/2022/09/ballerina-en-un-vistazo.html


sábado, 7 de diciembre de 2024

Un programa en varios lenguajes de programación (2da parte)

En una entrega anterior vimos como resolver un ejercicio de programación (determina si una cadena de caracteres tiene una longitud distinta de 0) usando diversos lenguajes de programación.

Para probar estos ejemplos puedes ir a este sitio:

https://codapi.org/

En está ocasión resolveremos el siguiente problema:

Si enumeramos todos los números naturales menores de 10 que sean múltiplos de 3 o 5, obtenemos 3, 5, 6 y 9. La suma de estos múltiplos es 23. Halla la suma de todos los múltiplos de 3 o 5 menores de 1000.

Un ejercicio propuesto en la página de Project Euler: https://projecteuler.net/

En Dlang:

multipos3o5.d

void main()
{
    import std.stdio : writefln;
    const MAX = 1000;
    int counter = 1;
    int suma = 0;
    while(counter < MAX){
        if(counter%3==0 || counter%5==0){
           suma+=counter;
           writefln("Suma = %d, Counter: %d",suma,counter);
        }
        ++counter;
    }
    writefln("Suma final= %d",suma);
}

En C:

multiplos3o5.c

#include <stdio.h>
const int MAX = 1000;

int main() {
    int counter = 1;
	int suma = 0;
    
	 while(counter < MAX){
        if(counter%3==0 || counter%5==0){
           suma+=counter;
           printf("Suma = %d, Counter: %d\n",suma,counter);
        }
        ++counter;
    }
	printf("Suma final = %d\n",suma);
    return 0;
}

En Python:

multiplos3o5.py

MAX = 1000;
counter = 1
suma = 0
while counter < MAX:
    if counter%3== 0 or counter%5==0:
        print(f"Suma: {suma}, Counter: {counter}")
        suma = suma + counter
    counter = counter + 1   
print(f"Suma final: {suma}")

En Java:

Multiplos3o5.java

package com.test.main;

public class Main {
    public static final int MAX = 1000;
    public static void main(String[] args) {
        int counter = 1;
        int suma = 0;
        while(counter < MAX){
            if(counter%3==0 ||counter%5==0){
                suma+=counter;
                System.out.printf("Suma: %d, Counter: %d\n",counter,suma);
            }
            ++counter;
        }
        System.out.printf("Suma final: %d\n",suma);
    }
}

En Javascript:

multiplos3o5.js

const MAX = 1000;
let counter = 1;
let suma = 0;
    
	while(counter < MAX){
        if(counter%3==0 || counter%5==0){
           suma+=counter;
           console.log(`Suma = ${suma}, Counter: ${counter}`);
        }
        ++counter;
    }
	console.log(`Suma final = ${suma}`);

En Clojure:

multiplos3o5.clj

(def MAX 1000)

(defn calcular-suma []
  (loop [counter 1 suma 0]
    (if (< counter MAX)
      (if (or (zero? (mod counter 3)) (zero? (mod counter 5)))
        (do
          (println "Suma:" suma ", Counter:" counter)
          (recur (inc counter) (+ suma counter)))
        (recur (inc counter) suma))
      (do
        (println "Suma final:" suma)
        suma))))

(calcular-suma)

Clojure es un lenguaje muy distinto a la mayoría. Como emplea la misma sintaxis de LISP, el cual es un lenguaje orientado a expresiones.

En Ada Language Programming:

multiplos3o5.adb

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Suma_Multiplos is
   MAX     : constant Integer := 1000;
   Counter : Integer := 1;
   Suma    : Integer := 0;
begin
   while Counter < MAX loop
      if (Counter mod 3 = 0) or (Counter mod 5 = 0) then
         Put_Line("Suma: " & Integer'Image(Suma) & ", Counter: " & Integer'Image(Counter));
         Suma := Suma + Counter;
      end if;
      Counter := Counter + 1;
   end loop;

   Put_Line("Suma final: " & Integer'Image(Suma));
end Suma_Multiplos;

En Rust:

multiplos3o5.rs

fn main() {
    const MAX: i32 = 1000;
    let mut counter = 1;
    let mut suma = 0;

    while counter < MAX {
        if counter % 3 == 0 || counter % 5 == 0 {
            suma += counter;
            println!("Suma = {}, Counter: {}", suma, counter);
        }
        counter += 1;
    }

    println!("Suma final = {}", suma);
}

En Odin:

multiplos3o5.odin

package main

import "core:fmt"

MAX :: 1000;

main :: proc() {
    counter: int = 1;
    suma: int = 0;

    for counter < MAX {
        if counter % 3 == 0 || counter % 5 == 0 {
            suma += counter;
            fmt.printf("Suma = %d, Counter: %d\n", suma, counter);
        }
        counter += 1;
    }

    fmt.printf("Suma final = %d\n", suma);
}

En Go:

multiplos3o5.go

package main

import "fmt"

func main() {
    const MAX = 1000
    counter := 1
    suma := 0

    for counter < MAX {
        if counter%3 == 0 || counter%5 == 0 {
            suma += counter
            fmt.Printf("Suma = %d, Counter = %d\n", suma, counter)
        }
        counter++
    }

    fmt.Printf("Suma final = %d\n", suma)
}

Continuaremos ampliando la lista de ejemplos.

Enlaces:


https://codemonkeyjunior.blogspot.com/2024/02/un-programa-en-varios-lenguajes.html
https://projecteuler.net/

domingo, 18 de febrero de 2024

Un programa en varios lenguajes

 

Esta ocasión veremos un ejemplo de programa escrito en varios lenguajes de programación como: Java, Erlang, Python, Powershell, Clojure y otros más.

Ejercicio: Un programa que determine si una cadena ("ABC") tiene una longitud distinta de cero. Si la longitud de cadena es distinta de cero, que imprima la cadena en pantalla. Si no cumple la condición deberá mandar el mensaje: "Cadena vacía".

En pseudo código sería algo como esto:

// Pseudo code language
prog longitud:{
     var cadena:String = "ABC";
     var longitud:Int = cadena.size;
     if longitud != 0 then
        disp "${cadena}"
     else
        disp "Cadena vacía"
}


Por temas de espacio algunos bloques de código son omitidos para no hacer más grande el código, usted disculpe.

En Powershell:

longitud.ps1

$cadena="ABC"

if($cadena.Length -ne 0){
   Write-Host $cadena  
}
else{
   Write-Host "Cadena vacia"
}

En Clojure:

longitud.clj

(ns longitud)

(def cadena "ABC")
(def longitud (count cadena))
(if (not= longitud 0)
   (println cadena)
   (println "Cadena vacia")
)

En Erlang:

longitud.erl

-module(longitud).
-author("Codemonkey Junior Blogspot").
-version("1.0.0").
-export([start/0]).

println(Cosa) -> io:format("~p~n", [Cosa]).

start()->
    Cadena="ABC",
    Longitud=string:length(Cadena),
    if 
     Longitud /= 0 ->
       println(Cadena);
    true ->
       println("Cadena vacia")
    end.

En OpenEdge ABL:

longitud.p

define var as char no-undo initial "ABC".

if length(cadena)<>0 then
   disp cadena.
else
   disp "Cadena vacia".

En Rust:

longitud.rs

let cadena:String = String::from("ABC");

if cadena.chars().count()!=0 {
   println!("{}",cadena)
}
else{
   println!("Cadena vacia")
}

En PL/SQL:

longitud.sql

SET SERVEROUTPUT ON
DECLARE
  cadena varchar2(3):='ABC';
  BEGIN
       IF LENGTH(cadena) != 0 THEN
          dbms_output.put_line(cadena);
       ELSE
          dbms_output.put_line('Cadena vacia');
       END IF;
  END;
/

En Elixir:

longitud.exs

cadena = "ABC"

if String.length(cadena) != 0 do
  IO.puts "#{cadena}"
else
  IO.puts "Cadena vacia"
end

En R:

longitud.r

cadena <- "ABC"

if(nchar(cadena) != 0) {
  sprintf("%s",cadena)
}else{
  print("Cadena vacia")
}

En DataStage BASIC:

longitud.dsx

Option Explicit

' Declaración de variables
Dim cadena As String

' Asignación de valor a la variable
cadena = "ABC"

' Verificación de la longitud de la cadena
If Len(cadena) <> 0 Then
    ' Imprimir la cadena si no está vacía
    Print cadena
Else
    ' Imprimir un mensaje si la cadena está vacía
    Print "Cadena vacia"
End If

En Ballerina:

longitud.bal

import ballerina/io;

public function main() {
    string cadena = "ABC";

    if (lengthof cadena != 0) {
        io:println(cadena);
    } else {
        io:println("Cadena vacia");
    }
}

En C:

longitud.c

#include <stdio.h>
#include <string.h>

int main() {
    char cadena[] = "ABC";

    if (strlen(cadena) != 0) {
        printf("%s\n", cadena);
    } else {
        printf("Cadena vacia\n");
    }

    return 0;
}

En C++:

longitud.cpp

#include <iostream>
#include <string>

int main() {
    std::string cadena = "ABC";

    if (!cadena.empty()) {
        std::cout << cadena << std::endl;
    } else {
        std::cout << "Cadena vacia" << std::endl;
    }

    return 0;
}

En Haskell:

longitud.hs

main :: IO ()
main = do
    let cadena = "ABC"
    if length cadena /= 0
        then putStrLn cadena
        else putStrLn "Cadena vacia"

En Prolog:

longitud.pl

cadena_valida('ABC') :- write('ABC').
cadena_valida('') :- write('Cadena vacia').

main :- cadena_valida('ABC').

En Python:

longitud.py

cadena="ABC"
if len(cadena) !=0:
   print(cadena) 
else:
   print("Cadena vacia")

Este post se irá actualizando... see you later !!

Jai un lenguaje de programación inspirado en C++

Hoy hablaremos de un nuevo lenguaje de programación llamado Jai . Se trata de un lenguaje de programación que está desarrolland...

Etiquetas

Archivo del blog