Una sinfonía en C#

Un pequeño aporte a la comunidad de habla hispana.

Predicados y array en Javascript: find, filter, some.

En esta tercera parte vamos a ver varios métodos juntos, find, filter y some porque...bueno, porque sí.
En realidad porque tiene algo en común, todos reciben como parámetro un predicado

¿Y qué es un predicado?

En este contexto es una función que establece una condición contra la cual se evaluarán elementos.
Dicho en palabras un poco menos complicadas, pasamos una función que será la encargada de decirnos si un elemento de un array cumple con una condición.
Veamos un ejemplo:

Array.filter

Empecemos con filter, al final los tres métodos son similares pero hacen cosas distintas.
Filter permite tomar solo aquellos elementos de un array que cumplen con una condición, en este caso, determinada por el predicado.
Entonces, si tenemos el siguiente array:

var a = [1,2,3,4,5,6,7,8,9];

y quisiera quedarme solo con aquellos elementos que son pares podría hacer esto:

var aa = [];
for(var item in a){
     if(item % 2 == 0)
         aa.push(item);
}
console.log(aa);

Con filter la cosa sería así:

aa = a.filter(function(item){
     return item % 2 == 0; });

El resultado es exactamente el mismo.

Y es igual que:

aa = a.filter((item)=> item % 2 == 0);

Aún más elegante.

Algunas características de filter:

  • Solo se invoca el callback (el predicado) para elementos que tiene valores, es decir, los elementos del array sin valores se ignoran.
  • Los elementos borrados durante la ejecución no son visitados.
  • El rango de elementos a visitar se establece antes del inicio de la iteración, es decir, si se agregan elementos los mismo no son visitados.
  • Si un elemento cambia de valor se leerá el nuevo valor.

Además filter recibe dos parámentros, el callback que recibe tres: el elemento actual, el índice actual y el array original.
El segundo parámetro es el contexto de this, vamos, igual que las funciones que vimos en los posts anteriores.

Todo es es igual para el caso de find y some, veamos cómo funcionan.

Find

Simplemente retorna el primer elemento que coincida con el criterio del predicado, en el ejemplo anterior retornaría el número 2.

a.find((item)=> item % 2 == 0);

Evidentemente si hay más elementos que cumplen la condición establecida en el predicado son ignorados, en caso de no haber ninguno retorna undefined.

a.find((item) => item > 10);

Las mismas reglas de comportamiento anteriores se aplican a find.

Some

En este caso devuelve true si al menos un elemento cumple con el criterio de búsqueda y false si no hay ninguno.

a.some((item) => item > 2);

Devolverá true.

a.some((item)=> item > 10);

Devolverá false, sería casi como hacer algo así con find:

a.find((item)=>item > 10) != undefined;

Lo dejamos acá por hoy, nos leemos.

Array map en Javascript, se usa mal?

En el post anterior hablamos sobre Array.forEach y su funcionamiento, ahora vamos con el que hoy en día (creo yo) es el segundo método de Array más usado, map.

Map recorre un array y crea un nuevo array como resultado de la invocación a una función dada.
En palabras simples, map recorre un array y aplica una función (que es parámetro) a cada elemento del mismo, y crea un nuevo array con los elementos resultantes.

Un ejemplo simple (y no muy útil)

var a = [1, 2, 3, 4];
const m = a.map(function(item){
     return item;
});
console.log(m);

O lo que sería lo mismo:

m = array1.map(x => x);

Lo que ocurre es que la función que se pasa como parámetro es quien genera el resultado, en este caso devuelve el mismo elemento que recibe (en item se pasa cada valor del array, uno a la vez) entonces el resultado es igual, pero es un nuevo array, no es el mismo.

Evidentemente este ejemplo no tiene mucha utilidad, en genera uno realiza operaciones dentro de la función, por ejemplo:

var a = [1, 2, 3, 4];
var m = a.map(function(item){
     return item * 2;
});
console.log(m);

En este caso la función recibe en item cada elemento y retorna su valor * 2.
Por supuesto que dentro de esta función podemos hacer cualquier cosa, incluso ignorando los valores del array original.

var a = [1, 2, 3, 4];
var m = a.map(function(item){
     console.log(+new Date());
});

Alguna características de map:

  • La función recibe tres parámetros, el item actual, el índice del elemento y el array orginal, con lo cual podemos operar sobre el array orginal.
  • Se invoca a la función una vez por cada elemento del array que contiene valores.
  • Si no se usa el array resultante o no se retorna un valor en el callback se considera incorrecto el uso de map, en tal caso se puede usar for-of o forEach.
  • Los elementos recorridos por map son determinados antes de iniciar el recorrido.
  • Los elementos que hayan cambiando luego de iniciada la iteración se considerará su valor actual.
  • Los elementos removidos no son recorridos (ya que sus valores serían inválidos).
  • Es posible pasar el contexto como segundo parámetro (que tomaría el valor de this).

Como vemos muchas de estas características son iguales a forEach.

Entonces, cuándo usamos map y cuándo forEach?

Como dice más arriba, si no vamos a utilizar el array resultante se considera un antipatrón usar map y debemos echar manos de forEach o for-of.

El uso tal vez más común al consultar una API sería "reformatear" los objetos obtenidos.

var a = [{"nombre":"Marcelo", "nombre":"Leonardo"}];
var m = a.map(function(item){
     return {"Nombre":item.nombre}
});

console.log(m);

Nos leemos.

Métodos para trabajar con Arrays en Javascript

Esto viene de la curiosidad que me dio ver que varias personas utilizan el método map de Array para iterar aunque no deseen mapear los objetos, al preguntar el porqué de tal decisión me he dado cuenta que hay varios métodos del objeto Array poco conocidos que son muy útiles y, en algunas ocasiones, más adecuados según el caso de uso.

Los arrays en Javascript son cosa de todos los días, cuando manipulamos datos gran parte de las veces se trata de un array de elementos. Entonces conocer algunos métodos relacionados con ellos nos puede ser útil.
En este caso vamos a repasar algunos que me parece más útiles.

A los largo de algunos posts veremos:

  • Array.prototype.forEach
  • Array.prototype.map
  • Array.prototype.some
  • Array.prototype.filter
  • Array.prototype.find
  • Array.prototype.reduce
  • Array.prototype.findIndex

No todos separados, dependiendo un poco de lo largo que vayan quedando los posts.

Array.prototype.forEach

Empezamos con el que creo será el más común que utilizar al consultar un servicio.
forEach permite iterar todos los elementos de un array. Algo así:

var a = ['a', 'b', 'c'];
a.forEach(item => {
   console.log(item); });

Entonces en lugar de iterar con un for clásico (clásico para los que estudiamos programación estructurada) con forEach se recorre todo el array y nos da una referencia en el parámetro item.

Algunas características del forEach:

  • La cantidad de elementos a recorrer es establecida antes de iniciar el bucle, por lo tanto si agregamos un elemento dentro del forEach el mismo no será visitado.
  • Siempre retorna undefined, por lo tanto no es posible encadenarlo
  • No es posible interrumpir su ejecución (excepto con una excepción)
  • Si un elemento cambia y forEach no ha pasado aún por él se leerá el valor actualizado.
  • Si un elemento no visitado es borrado no será visitado.
  • Si un elemento ya visitado es borrado el resto de los elementos no será visitado.

El callback que recibe forEach como parámetro recibe 3 argumentos

  • El elemento actual que se está visitando.
  • El índice del elemento actual.
  • Otro array.

This dentro del forEach.


El valor de this dentro del forEach es el contexto actual (window en el navegador), es posible pasar un segundo parámetro a forEach a modo de contexto.

function Counter() {
   this.sum = 0;
}
Counter.prototype.add = function(array) {
   array.forEach((entry)=>{
     this.sum += entry;
   }, this);
};

Si hacemos:

var c = new Counter();
c.add({1,2,3});

el resultado es la suma, ya que el acumulador de this es el miembro sum del objeto Counter.

Y para qué es el tercer parámetro? un array?

El tercer parámetro que recibe el callback es el array original, ya que en Javascript los parámetros se pasan por valor (es decir, son copias) si hacemos esto:

var a = [1,2,3];
a.forEach(function(item, index, aa){
     item = 0;
});

Si comprobamos el valor del array a vemos que los valores no cambiaron, si quisiéramos cambiarlos deberíamos operar sobre el tercer parámetro que es el orginal.

a.forEach(function(item, index, aa){
     aa[index] = 0;
});

al comprobar el valor del array original vemos que todos sus valores fueron sobre-escritos, mágico.

Bueno, lo dejó acá. Espero les sea útil. Nos leemos.

IoT bases: Introducción a MQTT

En este post vamos a comenzar a hablar sobre uno de los protocolos más utilizados para IoT, MQTT y conocer sus principales características, por qué es interesante para IoT, qué aporta, y cómo funciona.

https://www.penninkhof.com/wp-content/uploads/2015/03/MQTT.png

¿Qué es MQTT?

MQTT son las siglas de Message Queuing Telemetry Transport, es un protocolo pensado para telemetría, algunas cosas para remarcar:

  • Funciona sobre TCP.
  • Existen variantes sobre UDP y Bluetooth (por supuesto, con otras características de transporte).
  • Utiliza el patrón Publish/Suscribe.
  • Hace muy simple la comunicación entre múltiples dispositivos.
  • Diseñado para dispositivos pequeños y de bajo consumo de energía y ancho de banda.
  • Bidireccional.

Pubish/Suscribe

Bien, vamos por lo primero, decimos que MQTT es Publish/Suscriber, esto tiene varias implicaciones:

  • Si queremos recibir un mensaje tenemos que suscribirnos a un “tema”.
  • Si queremos publicar un mensaje lo hacemos a un “tema”.
  • No podemos enviar un mensaje directamente a otro cliente.
  • No podemos saber quién nos ha enviado un mensaje.
  • Si hay muchos dispositivos suscritos a un “tema” recibirán todos el mismo mensaje.
  • Si estamos suscritos a un “tema” recibimos todos los mensajes publicados por cualquier cliente a ese “tema”.

Por ejemplo, podemos suscribirnos al tema “casa” y cada vez que algún cliente publique un mensaje en ese tema lo recibiremos; del mismo modo, siempre que enviemos un mensaje tendremos que indicar el “tema” y este mensaje será recibido por todos los suscriptores (y nosotros no sabremos quiénes son).

Una de las ventajas de este modelo es que mucha responsabilidad no la gestionan los clientes y esto hace que sea simple desde el punto de vista del dispositivo.

El corazón de MQTT, el Broker.

Una cosa importante de señalar es cómo nos conectamos, como nos suscribimos y cómo publicamos; bien, los clientes MQTT nunca se conectan entre sí sino que se conectar a un Broker, que no es más que un intermediario que se encarga de conocer a todos los clientes y repartir los mensajes según las suscripciones. Hace algunas cosas más que iremos viendo.

Entonces, el Broker no es más que una aplicación que tiene que estar instalada y funcionando todo el tiempo, muchas de las ventajas de MQTT relacionadas con el bajo consumo de recursos tienen que ver con que el Broker es responsable de muchas cosas, y es donde reside la mayor parte de la complejidad del protocolo.

El diagrama de funcionamiento seria éste:

 

By Simon A. Eugster - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=70622928

Como vemos en el diagrama, el Client A se conecta al Broker y luego se suscribe al "tema” (Topic) temperature/roof, al lado derecho vemos el Client B que ya se encontraba conectado y publicó un mensaje sobre el mismo Topic, por lo tanto el Broker a ver que Client A se suscribe al Topic le entrega el mensaje. Más adelante Client A publica sobre el mismo Topic la temperatura actual (20º), recibe otro mensaje del Broker (30º), responde lo mismo y se desconecta.

Este diagrama podría perfectamente el funcionamiento de un termostado de una casa que recibe la configuración de temperatura de alguien más.

Nótese que el primer mensaje publicado por Client B dice “retain” esto es un flag especial que hace que ese mensaje quede retenido de modo que todos los nuevos suscriptores lo reciban ni bien se conectan el Topic, esto es especialmente útil cuando los clientes solo se conectan cuando necesitan interactuar con el Broker y de este modo ahorrar energía.

Topics

Los “temas” que nombramos antes se llaman Topics y se organiza en niveles, del siguiente modo:

sport/tennis/player1

De este modo podemos organizar los mensajes, ya que tenemos la posibilidad de suscribirnos a un Topic o a diferentes niveles gracias a los willcards, por ejemplo:

sport/# suscribe a todos los niveles debajo de sport

sport/#/ranking suscribe a todos los ranking de todos los deportes

por otro lado el + permite usar un willcard de un único nivel

sport/tennis/+/ranking suscribe a todos los rankings, es decir el + solo reemplaza un nivel

Hay mucho más detalles al respecto en la especificación.

Calidad de servicio QoS

Existen 3 niveles de calidad en MQTT 0,1 y 2.

Estos niveles determinan con que rigurosidad el Broker debe asegurarse que los mensajes han sido entregados correctamente.

  • 0: Se envían el mensaje y no se espera ninguna verificación (fire en forget).
  • 1: Se espera al menos un ACK de cada clientes que debe recibir el mensaje (si el cliente tarda en responder es posible que se envíe dos veces el mismo mensaje).
  • 2: Se garantiza que cada cliente recibe el mensaje una única vez.

Evidentemente a medida que subimos la calidad los mensajes son más costosos a nivel recursos de energía y tiempo, mayormente se usa el nivel 0 o 1, de hecho muchos Brokers y clientes no implementan el nivel 2.

El nivel de calidad se puede definir al conectarse al Broker (el cliente decide qué nivel de validad quiere) o en cada mensaje enviando (quien envía decide el nivel)

Retención de mensaje (retain message)

Como vimos en el diagrama, esto no es más que un flag que hace que un mensaje en particular (podemos agregarlo en todos, en tal caso siempre se considera el último mensaje por Topic) sea retenido por el Broker de modo de que al suscribirse un nuevo cliente el Topic reciba este mensaje como primer mensaje, esto es muy útil para valores por defecto y cosas o cuando quien publica mensaje lo hace cada cierto tiempo, entonces el mensaje queda ahí y todo el que se conecte al Topic lo recibirá por más que quien generó el mensaje no se encuentre operativo.

Sesiones

Lo último de lo que vamos a hablar es de sesiones, es otra característica avanzada y básicamente hace que el Broker le asigne un número de sesión a cada clente (que se conecte, independientemente de si se suscribe a un Topic) y recuerde este identificador de sesión, de modo que si el cliente se desconecta (otra vez, porque se apaga para ahorrar energía o ocurre algo) pueda informar su sesión y el Broker continue por donde quedó. Otra vez, no todos los Broker y clientes lo implementan.

En la próxima entrada vamos a ver qué software podemos usar para hacer las primeras pruebas con MQTT.

Nos leemos.

Delegate, predicate, Action, Func, métodos anónimos, explicados para mortales.

No es un tema nuevo ni mucho menos,  sin embargo no siempre es del todo bien comprendido y su correcta comprensión es muy importante ya que muchas otras características del framework se apoyan en los delegados, así que vamos a hablar un poco sobre ellos.

Pero, ¿Qué es un delegado?

La respuesta corta es “un delegado es una referencia a un método”, pero no confundir, no es una referencia como un puntero sino que en realidad un delegado nos permite definir una firma para poder luego pasar un método. Vemos un ejemplo.

var testDelegates = new TestDelegates();
testDelegates.DoSomething();

En este simple código tenemos un objeto testDelegates que tiene un método DoSomething y que hace algo, imaginemos que ese método, por ejemplo, hace una llamada a un servicio que ocurre de manera asíncrona y termina después de un tiempo indeterminado. La llamada se realiza pero queremos que de alguna manera este método nos informe que la ejecución ha finalizado. Bien, una forma de hacerlo sería indicarle a DoSomething  que luego de finalizar su ejecución invoque a otro método y nosotros hagamos algo en consecuencia. Más o menos cómo cuando hacemos una llamada AJAX desde Javascript donde tenemos una forma de ser informados de la finalización de la ejecución de la llamada.

Delegado simple

Para hacer esto necesitamos indicar a DoSomething cuál es el método que queremos que sea invocado al final su ejecución (exitosa o no, en este caso eso no nos preocupa) .NET nos permite hacer esto pero nos obliga de definir siempre la firma del método a ser llamado, es decir, tenemos de alguna manera que decir en DoSomething que podemos informar el final de la ejecución a un método pero con cierta firma (que reciba ciertos parámetros y devuelva cierto tipo de datos) acá es donde entran los delegados en acción, justamente nos permiten definir la firma del método.

public class TestDelegates
{
    // declaración del delegador, sin valor de retorno (void) y sin parámetros
    public delegate void DelegadoSimple();
    public void DoSomething(DelegadoSimple delegado)
    {
        // does something
        // llamar al la función
        delegado();
    }
}

Los primero que hacemos es definir el delegado de modo de que sea visible, como dijimos antes esta será la firma que deberá tener el método que pasaremos como parámetro, entonces lo ponemos en la clase que lo utilizará con visibilidad pública.

Luego ponemos como parámetro el delegado que funciona como un tipo y nos permite tener la referencia a la función.

Luego dentro del código podemos invocar la función, en este caso solo agregando los paréntesis porque no recibe parámetros.

private static void Main(string[] args)
{
    var testDelegates = new TestDelegates();
    testDelegates.DoSomething(FuncionSimple);
}

private static void FuncionSimple()
{
    // hacer algo
}

En cuando a la llamada a DoSomething simplemente agregamos el parámetro que es una función igual que el delegado, que no retorna valor (es void) y no recibe parámetros, notemos que no tiene parámetros porque no la invocamos solo pasamos una referencia.

Métodos anónimos

Qué pasaría si no quisiéramos crear una función con nombre y todo para que sea invocada. En este caso podemos crearla inline, de este modo:

private static void Main(string[] args)
{
    var testDelegates = new TestDelegates();
    // en este caso pasamos un método anónimo
    testDelegates.DoSomething(()=>
    {
        //hacer algo
    });
}

Lo que hicimos es declarar nuestro método en el mismo sitio que invocamos a DoSomething, vamos a analizar la sintaxis.

testDelegates.DoSomething(()=>
{
    //hacer algo
});

Primero tenemos que tenemos en cuenta que es necesario cumplir con el delegado, con lo cual el método anónimo no tiene valor de retorno y no recibe parámetros. entonces lo primero que vemos es que hay dos paréntesis vacíos, justamente porque no recibe parámetros y luego la “flecha” que indica que a continuación viene el cuerpo el método ()=>

Después simplemente tenemos las llaves que limitan el cuerpo del método anónimo y si tuviéramos código estaría por ahí, como el método no retorna valor no hay un return.

Es importante destacar que al ser anónimo (el método no tiene nombre) no puede ser invocado desde otra parte.

Imaginemos que lo que queremos hacer es escribir en la consola, el código quedaría así:

testDelegates.DoSomething(() =>
{
    Console.WriteLine("Ejecución finalizada");
});

Y qué ganamos creando un método anónimos? bien, lo principal es que es posible que no usemos ese método para nada más que para ser invocado por DoSomething, por otro lado tenemos visibilidad de las variables dentro del método donde declaramos el método anónimo, por ejemplo podemos hacer esto:

var testDelegates = new TestDelegates();
var variablePrivada = "valor original";
            // en este caso pasamos un método anónimo
testDelegates.DoSomething(() =>
{
    Console.WriteLine("Ejecución finalizada");
    Console.WriteLine($"El valor de la variable 'variablePrivada' es {variablePrivada}");
    variablePrivada = "valor nuevo";
    Console.WriteLine($"El nuevo valor de la variable 'variablePrivada' es {variablePrivada}");
});

No solamente podemos leer una variable privada del método donde declaramos el método anónimo sino que también podemos modificarla, algo similar a un closure.

Métodos anónimos con parámetros

public delegate void DelegadoSimple(int milisegundos);
public void DoSomething(DelegadoSimple delegado)
{
    // does something
    // llamar al la función
    delegado(20);
}

Primero cambiamos la definición del método anónimo para que reciba parámetros, en este caso el tiempo que demoró la ejecución de nuestro método DoSomething, esta vez cuando lo invocamos le pasamos el valor.

private static void Main(string[] args)
{
    var testDelegates = new TestDelegates();
    testDelegates.DoSomething(FuncionSimple);
}

private static void FuncionSimple(int milisegundos)
{
    Console.WriteLine("Ejecución finalizada");
    Console.WriteLine($"La ejecución tomó {milisegundos} milisegundos");
}

Modificamos el método para que reciba el parámetro y al ser ejecutada lo mostramos en pantalla, si lo hiciéramos anónimos sería así:

private static void Main(string[] args)
{
    var testDelegates = new TestDelegates();
    testDelegates.DoSomething((int milisegundos) =>
    {
        Console.WriteLine("Ejecución finalizada");
        Console.WriteLine($"La ejecución tomó {milisegundos} milisegundos");
    });
}

en este caso agregamos en parámetro dentro de los paréntesis.

¿Y qué pasa si tenemos que devolver valores en nuestros delegados?

Por supuesto que podemos tener un delegado que retorne un valor de cualquier tipo, un ejemplo sería el siguiente:

public delegate string DelegadoSimple(int milisegundos);
public void DoSomething(DelegadoSimple delegado)
{
    // does something
    // llamar al la función
    Console.Write(delegado(20));
}

Ahora cambiamos la declaración del delegado para que retorne un string y al invocar el delegado lo imprimimos, en código de la otra parte sería así:

testDelegates.DoSomething((int milisegundos) =>
{
    Console.WriteLine("Ejecución finalizada");
    return $"La ejecución tomó {milisegundos} milisegundos";
});

Muy sencillo.

Delegados predefinidos.

Existen algunos delegados predefinidos que nos permiten evitar declarar todo el tiempo los propios, lo más comunes son:

  • Predicate
  • Action
  • Func

El predicate se usa en muchos métodos de filtrado de colecciones, por ejemplo en la lista genérica:

public T Find(Predicate match)

Y si vemos la definición de predicate podemos comprender bien de qué se trata

public delegate bool Predicate(T obj)

Un predicate sirve para proveer al método Find de una filtro personalizado, es decir, definir nosotros cómo queremos filtrar los datos, vamos a ver el código interno del método Find

public T Find(Predicate match) {
	if( match == null) {
		ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
	}
	Contract.EndContractBlock();

	for(int i = 0 ; i < _size; i++) {
		if(match(_items[i])) {
			return _items[i];
		}
	}
	return default(T);
}

El predicate es la variable match y vemos que lo que hace este método Find es recorrer todos los elementos de la lista y si match es true, retorna el elemento que coincide. Esto nos demuestra la utilidad de los delegados, podemos nosotros definir el criterio de búsqueda.

Existen muchos otros métodos en la clase List<T> que aceptan un predicate y en otras clases también.

Action y Func

Action y Func son más simple, si miramos su definición nos damos cuenta para qué sirven

public delegate void Action();
public delegate void Action(T obj);
public delegate TResult Func();
public delegate TResult Func(T arg);

En el caso de Action es una delegado pre-definido que nos permite definir “acciones” es decir, métodos que no devuelven un valor, el ejemplo del principio lo podríamos haber hecho con Action.

public void DoSomething(Action delegado)
{
    delegado();
}

Lo mismo que si quisiéramos pasar uno o varios parámetros

public void DoSomething(Action delegado)
{
    delegado(20);
}

Existen muchas sobre cargas genéricas para poder pasar hasta 16 parámetros.

En el caso de Func es como un Action pero que devuelve un valor, entonces nuestro código final usando un Func quedaría así:

public void DoSomething(Func delegado)
{
    Console.WriteLine(delegado(20));
}

Simplemente Action y Func no son más que delegados pre-definidos que nos ahorran crear los nuestros en la mayor parte de los casos.

Es importante comprender bien los delegados porque están por todas partes, sobre todo en Linq, todo lo que sea asíncrono como HttpClient o lo relacionado con Threads.

Nos leemos.