Translate

martes, 10 de junio de 2025

new vs override en C#: ¿cuál es la diferencia y cuándo usar cada uno?



Cuando trabajamos con herencia en C#, dos palabras clave aparecen para definir comportamiento en clases derivadas: new y override. A primera vista pueden parecer similares, pero representan intenciones diferentes. Entenderlas bien puede evitarte muchos errores.

En C# una clase puede heredar miembros (métodos, propiedades, etc.) de otra. ¿Pero qué pasa si queremos cambiar el comportamiento de un método heredado?

Ahí entran en juego override y new.

Cuando queremos modificar el comportamiento de un método heredado, usámos override.


class Animal

{

    public virtual void Hablar()

    {

        Console.WriteLine("Hace un sonido");

    }

}


class Perro : Animal

{

    public override void Hablar()

    {

        Console.WriteLine("Guau");

    }

}


Y ahora mirá esto:


Animal a = new Perro();

a.Hablar(); // Imprime "Guau"


Con override, el comportamiento depende del tipo real del objeto, no del tipo de la variable. Esto se llama polimorfismo.


En cambio, new oculta el método de la clase base. No lo reemplaza a nivel del sistema de tipos.


class Animal

{

    public void Hablar()

    {

        Console.WriteLine("Hace un sonido");

    }

}


class Gato : Animal

{

    public new void Hablar()

    {

        Console.WriteLine("Miau");

    }

}


Probá esto:

Animal a = new Gato();

a.Hablar(); // Imprime "Hace un sonido"


Porque a es del tipo Animal, y el método Hablar() de Gato no lo reemplazó: solo lo ocultó. Pero:


Gato g = new Gato();

g.Hablar(); // Imprime "Miau"


¿cuándo uso new?

  • Cuando querés ocultar intencionalmente un método de la clase base, pero sin reemplazarlo para el sistema de tipos.
  • Generalmente se evita, porque puede causar confusión. Se usa cuando no podés cambiar la clase base (por ejemplo, una librería externa) pero necesitás un método con el mismo nombre y diferente comportamiento.


¿Qué pasa si no usás ni new ni override? El compilador mostrará una advertencia si detecta que estás ocultando un miembro sin decirlo explícitamente.


// Esto compila, pero da warning:

public void Hablar() { ... } // Oculta un método de la base


Siempre que ocultes un miembro heredado, C# quiere que lo declares con new o override, para que tu intención sea clara.

domingo, 8 de junio de 2025

La Arquitectura Elm

La Arquitectura Elm es un patrón para diseñar programas interactivos, como aplicaciones web y juegos.

Esta arquitectura parece surgir de forma natural en Elm. En lugar de que alguien la inventara, los primeros programadores de Elm seguían descubriendo los mismos patrones básicos en su código. ¡Era un poco inquietante ver a gente terminar con código bien diseñado sin planificación previa!

Así que la Arquitectura Elm es sencilla en Elm, pero útil en cualquier proyecto front-end. De hecho, proyectos como Redux se han inspirado en la Arquitectura Elm, así que quizás ya hayas visto derivados de este patrón. La cuestión es que, incluso si aún no puedes usar Elm en el trabajo, obtendrás mucho de su uso e internalización.

Los programas Elm siempre se ven así:


El programa Elm produce HTML para mostrar en pantalla y luego el ordenador envía mensajes de respuesta sobre lo que está sucediendo. "¡Han pulsado un botón!"

Pero ¿qué sucede dentro del programa Elm? Siempre se divide en tres partes:

  • Modelo: el estado de la aplicación
  • Vista: una forma de convertir el estado a HTML
  • Actualización: una forma de actualizar el estado según los mensajes

Estos tres conceptos son la base de la arquitectura Elm.


jueves, 5 de junio de 2025

Proxy en javascript


En JavaScript moderno hay varias formas de observar cambios en objetos, pero la más directa y nativa es usando Proxy, que te permite interceptar y reaccionar a operaciones sobre un objeto, como modificar una propiedad.


Veamos un ejemplo:


function observeObject(obj, callback) {

  return new Proxy(obj, {

    set(target, prop, value) {

      const oldValue = target[prop];

      target[prop] = value;


      // Ejecutamos el callback cuando se modifica algo

      callback(prop, value, oldValue);


      return true;

    }

  });

}


// Ejemplo de uso

const original = { nombre: 'Juan', edad: 30 };


const observado = observeObject(original, (prop, newVal, oldVal) => {

  console.log(`Propiedad '${prop}' cambió de ${oldVal} a ${newVal}`);

});


observado.nombre = 'Ana';   // Se dispara el callback

observado.edad = 31;        // También se dispara


Me gusto mucho, es simple y puede venir al pelo para ciertas ocaciones, pero debemos de tener en cuenta que : 

  • Solo observa propiedades directas, no anidadas. Si querés observar objetos dentro del objeto, hay que aplicar recursivamente el Proxy.
  • No detecta borrados (como delete obj.prop) a menos que también implementes el deleteProperty trap.
  • No funciona con arrays de forma intuitiva si hacés push, pop, etc., salvo que interceptes esos métodos.


martes, 3 de junio de 2025

Tuplas en Elm


Las tuplas son otra estructura de datos útil. Una tupla puede contener dos o tres valores, y cada valor puede ser de cualquier tipo. Un uso común es cuando se necesita devolver más de un valor de una función. La siguiente función recibe un nombre y envía un mensaje al usuario:

> isGoodName name =

|   if String.length name <= 20 then

|     (True, "name accepted!")

|   else

|     (False, "name was too long; please limit it to 20 characters")

<function>


> isGoodName "Tom"

(True, "name accepted!")



>  

domingo, 1 de junio de 2025

Listas en Elm


Las listas son una de las estructuras de datos más comunes en Elm. Contienen una secuencia de elementos relacionados, de forma similar a los arrays en JavaScript.

Las listas pueden contener muchos valores. Todos estos valores deben ser del mismo tipo. A continuación, se muestran algunos ejemplos que utilizan funciones del módulo Lista:


> names =

|   [ "Alice", "Bob", "Chuck" ]

["Alice","Bob","Chuck"]


> List.isEmpty names

False

> List.length names

3

> List.reverse names

["Chuck","Bob","Alice"]

> numbers =

|   [4,3,2,1]

[4,3,2,1]

> List.sort numbers

[1,2,3,4]

> increment n =

|   n + 1

<function>

> List.map increment numbers

[5,4,3,2]


¡todos los elementos de la lista deben tener el mismo tipo!

  

If en ELM


Para lograr un comportamiento condicional en Elm, se usa una expresión if.

Creemos una nueva función de saludo que sea apropiadamente respetuosa con el presidente Abraham Lincoln:


> greet name =

|   if name == "Abraham Lincoln" then

|     "Greetings Mr. President!"

|   else

|     "Hey!"

<function>

> greet "Tom"

"Hey!"

> greet "Abraham Lincoln"

"Greetings Mr. President!"

  

jueves, 29 de mayo de 2025

Funciones en Elm


Una función transforma valores. Toma un valor y genera otro.

Por ejemplo, aquí hay una función de saludo que toma un nombre y dice hola:


> greet name =

|   "Hello " ++ name ++ "!"

<function>

> greet "Alice"

"Hello Alice!"

> greet "Bob"

"Hello Bob!"


Los valores pasados ​​a la función se llaman comúnmente argumentos, así que podrías decir "saludar es una función que toma un argumento".

Bien, ahora que ya hablamos de saludos, ¿qué tal una función de madlib que toma dos argumentos?


> madlib animal adjective =

|   "The ostentatious " ++ animal ++ " wears " ++ adjective ++ " shorts."

<function>


> madlib "cat" "ergonomic"

"The ostentatious cat wears ergonomic shorts."

> madlib ("butter" ++ "fly") "metallic"

"The ostentatious butterfly wears metallic shorts."


Se debe usar paréntesis para agrupar "butter" ++ "fly". Cada argumento debe ser un valor primitivo como "cat" o debe estar entre paréntesis.

Quienes usan lenguajes como JavaScript podrían sorprenderse de que las funciones se vean diferentes aquí:


madlib "cat" "ergonomic"                  -- Elm

madlib("cat", "ergonomic")                // JavaScript


madlib ("butter" ++ "fly") "metallic"      -- Elm

madlib("butter" + "fly", "metallic")       // JavaScript


Esto puede resultar sorprendente al principio, pero este estilo termina usando menos paréntesis y comas. ¡Hace que el lenguaje se sienta realmente limpio y minimalista una vez que te acostumbras!

lunes, 26 de mayo de 2025

¡Comencemos por familiarizarnos con el código Elm!


El componente más pequeño de Elm se llama valor. Esto incluye valores como 42, Verdadero y "¡Hola!".

Comencemos analizando los números:


> 1 + 1

2

Hacer cálculos matemáticos está bien, pero es sorprendentemente poco común en la mayoría de los programas. Es mucho más común trabajar con cadenas como esta:


> "hola"

"hola"


> "butter" ++ "fly"

"butterfly"

>


¡Estos valores primitivos se vuelven más interesantes cuando empezamos a escribir funciones para transformarlos! Por lo tanto en proximos post veremos funciones. 


domingo, 25 de mayo de 2025

Cómo instalar Elm en Ubuntu


Si te interesa la programación funcional y te atrae la idea de crear interfaces web robustas y sin errores, Elm puede ser una excelente elección. 

Elm es un lenguaje de programación funcional y fuertemente tipado que compila a JavaScript. Se usa principalmente para construir interfaces web confiables, sin errores en tiempo de ejecución.

Vamos a instalarlo!! 

Antes de instalar Elm, asegurate de tener instalado:


Node.js y npm (el gestor de paquetes de Node)


Podés instalarlos con:


sudo apt update

sudo apt install nodejs npm


Verificá la instalación:

node -v

npm -v


Podés instalar Elm de varias formas, pero la más sencilla y recomendada para Ubuntu es a través de npm:


sudo npm install -g elm


Esto instalará los siguientes comandos:

  • elm (CLI principal)
  • elm-repl (intérprete interactivo)
  • elm-reactor (servidor de desarrollo)
  • elm-make (compilador, alias de elm desde Elm 0.19)


Verificá que esté instalado correctamente:


elm --version

Deberías ver algo como: 0.19.1


Podés crear un proyecto de prueba:


mkdir hola-elm

cd hola-elm

elm init


Esto generará un archivo elm.json. Luego, podés crear un archivo src/Main.elm y escribir tu primer módulo Elm. Por ejemplo : 


module Main exposing (main)


import Browser

import Html exposing (text)


main =

    Browser.sandbox

        { init = ()

        , update = \_ model -> model

        , view = \_ -> text "¡Hola Mundo desde Elm!"

        }


Para ver tus archivos Elm directamente en el navegador, ejecutá:


elm reactor


Y abrí http://localhost:8000 para explorar tu proyecto visualmente.


Elm es un lenguaje potente con un ecosistema pequeño pero muy enfocado. Si venís de JavaScript o TypeScript, o simplemente te interesa la programación funcional, Elm te va a sorprender.


jueves, 22 de mayo de 2025

1 Billon de iteraciones de bucles anidados

Me encanto esta comparativa por lo que quería compartirla, básicamente es un benchmark en diferentes lenguajes :


Dejo link

https://benjdd.com/languages/

martes, 20 de mayo de 2025

Conversiones implicit y explicit en C#


En C#, los operadores implicit y explicit nos permiten definir conversiones personalizadas entre tipos. Esto es útil cuando trabajamos con estructuras o clases que representan conceptos que pueden transformarse naturalmente en otros valores, como metros a kilómetros, grados a radianes, o monedas.

Cuando diseñamos tipos personalizados, muchas veces necesitamos que se comporten como si fueran valores comunes. Por ejemplo, si tenemos un struct Metros, queremos poder escribir:


Metros distancia = 100.0;


En lugar de tener que usar un constructor o un método auxiliar. O, si ya tenemos un objeto de tipo Metros, queremos poder convertirlo a double sin esfuerzo.

Sin conversiones definidas, tendríamos que hacer algo como:


var distancia = new Metros(100.0);

double d = distancia.Valor;


Definiendo operadores de conversión, podemos hacer que esta interacción sea más fluida.


El modificador implicit permite definir una conversión automática cuando no hay pérdida de información. El compilador permitirá esta conversión sin necesidad de cast.

Por ejemplo:


public struct Metros

{

    public double Valor { get; }


    public Metros(double valor) => Valor = valor;


    public static implicit operator Metros(double valor) => new Metros(valor);

}


Uso:

Metros distancia = 100.0; // conversión implícita desde double


Cuando una conversión puede perder información, o puede fallar, se recomienda marcarla como explicit. Esto obliga al programador a escribir el cast, dejando claro que está realizando una operación que podría tener consecuencias.

Por ejemplo:


public static explicit operator double(Metros metros) => metros.Valor;


Uso:


double d = (double)distancia; // cast explícito requerido


Las conversiones implicit y explicit en C# permiten diseñar APIs más amigables, legibles y seguras. Usá implicit cuando estés seguro de que la conversión no va a fallar ni perder datos, y explicit cuando quieras que el programador sea consciente del riesgo de la conversión.


domingo, 18 de mayo de 2025

Tipos Abstractos y Polimorfismo en Programación Funcional


Cuando pensamos en abstracción y polimorfismo, solemos imaginar clases, interfaces y herencia. Pero ¿sabías que la programación funcional también tiene sus propios superpoderes para modelar el comportamiento genérico y abstraer detalles? 

En POO, usamos clases abstractas o interfaces para definir estructuras que deben ser implementadas. En programación funcional, el enfoque es distinto, pero el objetivo es similar: ocultar detalles de implementación y exponer un comportamiento general.

Un ADT define un tipo por sus operaciones, no por cómo están implementadas. Por ejemplo:


data Pila a = Vacía | Empujar a (Pila a)


Este tipo Pila podría representar una pila genérica, y podríamos tener funciones que operen sobre ella sin importar cómo esté construida internamente.

En la programación funcional se identifican varios tipos de polimorfismo:

Polimorfismo Paramétrico: Permite escribir funciones genéricas sobre cualquier tipo. Es como los genéricos de Java, pero más poderoso:


identidad :: a -> a

identidad x = x


La función identidad funciona para cualquier tipo a.


Polimorfismo ad-hoc (Typeclasses / Traits / Protocolos) : En Haskell, Rust, Scala o Elixir podemos definir interfaces de comportamiento según el tipo. Esto recuerda al "método virtual" de POO.


class Metrico a where

    distancia :: a -> a -> Double


instance Metrico (Double, Double) where

    distancia (x1, y1) (x2, y2) =

        sqrt ((x2 - x1)^2 + (y2 - y1)^2)


Veamos un ejemplo en Scala:


trait Metrico[T] {

  def distancia(a: T, b: T): Double

}


implicit object Punto2D extends Metrico[(Double, Double)] {

  def distancia(a: (Double, Double), b: (Double, Double)) =

    math.sqrt(math.pow(a._1 - b._1, 2) + math.pow(a._2 - b._2, 2))

}


def calcularDistancia[T](a: T, b: T)(implicit m: Metrico[T]) =

  m.distancia(a, b)


Pattern Matching como Polimorfismo Estructural: Otro recurso poderoso es el pattern matching, que permite seleccionar comportamiento según la "forma" del dato.


sealed trait Forma

case class Circulo(r: Double) extends Forma

case class Rectangulo(ancho: Double, alto: Double) extends Forma


def area(f: Forma): Double = f match {

  case Circulo(r)       => math.Pi * r * r

  case Rectangulo(a, h) => a * h

}


¿Y qué ganamos con esto?

  • Abstracción sin herencia: no hay jerarquías rígidas.
  • Mayor seguridad de tipos: muchos errores se detectan en tiempo de compilación.
  • Separación de datos y comportamiento: las funciones no "viven" dentro de las estructuras de datos, lo cual facilita la composición y el testing.


La programación funcional ofrece mecanismos muy sólidos y expresivos para manejar abstracción y polimorfismo. Aunque no se usa herencia, se logra el mismo efecto (o incluso uno más flexible) usando funciones genéricas, pattern matching y typeclasses.


miércoles, 14 de mayo de 2025

¿Por qué un lenguaje funcional como Elm?



Puedes obtener algunas ventajas de programar con un estilo funcional, pero hay cosas que solo se pueden conseguir con un lenguaje funcional como Elm:

  • Sin errores de ejecución en la práctica.
  • Mensajes de error intuitivos.
  • Refactorización fiable.
  • Control de versiones semántico automático para todos los paquetes de Elm.

Ninguna combinación de bibliotecas JS puede ofrecerte todas estas garantías. ¡Provienen del diseño del propio lenguaje! Y gracias a estas garantías, es bastante común que los programadores de Elm digan que nunca se sintieron tan seguros programando. Seguros para añadir funciones rápidamente. Seguros para refactorizar miles de líneas. ¡Pero sin la ansiedad de pensar que se te ha pasado algo importante!


El Archivo de Anna


Les quiero recomendar el sitio el Archivo de Anna (del inglés Anna's Archive) que es un metabuscador en línea gratuito y sin ánimo de lucro de bibliotecas fantasma que proporciona acceso a una colección de libros, creado por un equipo de archivistas anónimos (conocidos como Anna o el equipo Pirate Library Mirror, abreviado como PiLiMi), ​ y publicado en respuesta directa a los esfuerzos de las fuerzas de seguridad, con la ayuda formal de The Publishers Association y Authors Guild, para cerrar el sitio web de Z-Library en noviembre de 2022.

En este sentido, el equipo del Archivo de Anna afirma proporcionar acceso a los metadatos de los materiales de Open Library, ser una copia de seguridad de las bibliotecas fantasma Library Genesis y Z-Library, presentar información sobre ISBN, no almacenar materiales protegidos por derechos de autor en su sitio web y solo indexar metadatos que ya están disponibles públicamente. Anna's Archive señala que su sitio web, un proyecto sin ánimo de lucro, acepta donaciones para cubrir gastos (alojamiento, nombres de dominio, desarrollo y relacionados).

Dejo link:

https://es.annas-archive.org

sábado, 10 de mayo de 2025

Clases padres, clases hijas… ¿y las madres qué?


La programación orientada a objetos (POO) nos trajo muchas cosas lindas: encapsulación, herencia, polimorfismo, y sobre todo, la posibilidad de inventarnos familias disfuncionales de clases sin necesidad de pasar por terapia.

Pero hay algo que siempre nos hizo ruido:

  • ¿Por qué hablamos de clases padre y clases hijas? 
  • ¿Dónde quedaron las madres, los tíos, las primas, o la abuela que todo lo sabe?

Lo más raro es que una clase padre puede ser hija de otra clase. Rarisisimo...

Todo empieza con el inglés. En POO se habla de parent class para referirse a la clase de la cual heredan otras. Y parent, significa “padre o madre”.

Pero claro, en español, por alguna razón misteriosa que seguro involucra a la Real Academia, siempre traducimos parent class como “clase padre”, y no “clase madre” o “clase progenitor/a” (aunque esa última suena a trámites en ANSES).

Entonces… ¿por qué decimos “clase hija”? Acá la gramática mete la cuchara. Como la palabra “clase” es femenina, cuando hablamos de su descendencia lógica usamos “hija” para que concuerde: La clase padre tiene muchas clases hijas.

¿Y si dijéramos “clase madre”?

¡Podemos! No hay ninguna ley que lo impida. De hecho, si queremos romper esquemas y escribir:


class Mamífero // clase madre

class Perro extends Mamífero // clase hija


...nadie de Scala te va a venir a buscar. Al contrario, tal vez sumes puntos con tus profes de literatura.

Eso sí, el término "clase madre" no es tan común, así que si lo usás, preparate para explicar o educar. (O poner una nota al pie tipo “uso madre porque soy inclusivo/a y rebelde”).

La POO no distingue género, pero el lenguaje humano sí. Y en nuestra necesidad de ponerle nombre a todo, terminamos replicando convenciones culturales sin cuestionarlas.

¿Querés decir clase madre? ¡Decilo!

¿Preferís clase base? ¡También está bien!

Lo importante es que tus clases compilen… y que no traumen a sus hijas.