Taller de Elixir #4 – Operadores Básicos

Hemos vistos que los operadores aritméticos +, -, *, / como, además de las funciones div/2 y rem/2 para la división entera y el resto.

También vimos ++ y — para manipular listas:

iex> [1, 2, 3] ++ [4, 5, 6]
[1, 2, 3, 4, 5, 6]
iex> [1, 2, 3] -- [2]
[1, 3]

La concatenación de cadenas se realiza con <>:

iex> "foo" <> "bar"
"foobar"

Aun que también es muy común el uso de:

iex> [foo, bar] = ["foo", "bar"]
["foo", "bar"]
iex> "#{foo}#{bar}"
"foobar"

Hay tres operadores booleanos: or, and y not. Estos operadores son estrictos en el sentido de que esperan algo que se evalúe como booleano (verdadero o falso) como primer argumento:

iex> true and true
true
iex> false or is_atom(:example)
true

Proporcionar un valor no booleano generará una excepción:

iex> 1 and true
** (BadBooleanError) expected a boolean on left-side of "and", got: 1

Or y and son operadores de cortocircuito. Solo ejecutan el lado derecho si el lado izquierdo no es suficiente para determinar el resultado:

iex> false and raise("This error will never be raised")
false
iex> true or raise("This error will never be raised")
true

Además de estos operadores booleanos, Elixir también proporciona ||, && y! que aceptan argumentos de cualquier tipo. Para estos operadores, todos los valores, excepto falso y nulo, se evaluarán como verdaderos:

# or
iex> 1 || true
1
iex> false || 11
11

# and
iex> nil && 13
nil
iex> true && 17
17

# !
iex> !true
false
iex> !1
false
iex> !nil
true

Como regla general, use y, o no y cuando esté esperando booleanos. Si alguno de los argumentos no es booleano, use &&, || y!

También podemos usar ==,! =, ===,! ==, <=,> =, como operadores de comparación:

iex> 1 == 1
true
iex> 1 != 2
true
iex> 1 < 2
true

La diferencia entre == y === es que este último es más estricto:

iex> 1 == 1.0
true
iex> 1 === 1.0
false

También podemos comparar dos tipos de datos diferentes:

iex> 1 < :atom
true

La razón por la que podemos comparar diferentes tipos de datos es el pragmatismo. Los algoritmos de clasificación no necesitan preocuparse por los diferentes tipos de datos para ordenar. El orden de clasificación general se define a continuación:

number < atom < reference < function < port < pid < tuple < map < list < bitstring

En realidad no necesita memorizar este pedido; es suficiente saber que existe este orden.

Taller de Elixir #3 – Tipos de datos

Los tipos básicos en elixir son enteros, flotantes, booleanos, átomos, cadenas, listas y tuplas.

iex> 1          # integer
iex> 0x1F       # integer
iex> 1.0        # float
iex> true       # boolean
iex> :atom      # atom / symbol
iex> "elixir"   # string
iex> [1, 2, 3]  # list
iex> {1, 2, 3}  # tuple

Aritmética básica

Las operaciones básicas son comunes:

iex> 1 + 2
3
iex> 2 - 1
1
iex> 5 * 5
25
iex> 10 / 2
5.0

Para que al dividir devuelva un entero en vez de un flotante se usa la función div/1 y para el modulo usamos rem/1.

iex> div(10, 2)
5
iex> div 10, 2
5
iex> rem 10, 3
1

Elixir le permite quitar los paréntesis al invocar funciones con nombre. Esta característica proporciona una sintaxis más limpia.

También admite anotaciones de acceso directo para ingresar números binarios, octales y hexadecimales:

iex> 0b1010
10
iex> 0o777
511
iex> 0x1F
31

Los números flotantes requieren un punto seguido de al menos un dígito y también admiten e para notación científica:

iex> 1.0
1.0
iex> 1.0e-10
1.0e-10

Las flotantes son de doble precisión de 64 bits.

La función “round” devuelve el número entero más cercano a un flotante y la función “trunc” para obtener la parte entera de un flotante.

iex> round(3.58)
4
iex> trunc(3.58)
3

Booleanos

Tenemos las palas claves true y false:

iex> true
true
iex> true == false
false

También tenemos la función “is_boolean”:

iex> is_boolean(true)
true
iex> is_boolean(1)
false

Atoms

Un átomo es una constante cuyo valor es su propio nombre. Algunos lenguajes llaman a estas símbolos. A menudo son útiles para enumerar valores distintos, como:

iex> :apple
:apple
iex> :orange
:orange
iex> :watermelon
:watermelon

Los átomos son iguales si sus nombres son iguales:

iex> :apple == :apple
true
iex> :apple == :orange
false

A menudo se utilizan para expresar el estado de una operación, mediante el uso de valores como :ok y :error.

Los booleanos verdadero y falso también son átomos:

iex> true == :true
true
iex> is_atom(false)
true
iex> is_boolean(:false)
true

Elixir te permite omitir el líder: para los átomos falso, verdadero y nulo.

Finalmente, Elixir tiene una construcción llamada alias que exploraremos más adelante. Los alias comienzan en mayúsculas y también son átomos:

iex> is_atom(Hello)
true

Strings

Las cadenas están delimitadas por comillas dobles, y están codificadas en UTF-8:

iex> "hellö #{:world}"
"hellö world"

Las cadenas pueden tener saltos de línea en ellas. Puedes presentarlos usando secuencias de escape:

ex> "hello
...> world"
"hello\nworld"
iex> "hello\nworld"
"hello\nworld"

Se puede imprimir una cadena usando la función IO.puts/1 desde el módulo IO:

iex> IO.puts "hello\nworld"
hello
world
:ok

Podemos ver que la función IO.puts/1 devuelve el átomo :ok después de imprimir.

Las cadenas están representadas internamente por secuencias contiguas de bytes conocidas como binarios:

iex> is_binary("hellö")
true

Para saber el número de bytes en una cadena:

iex> byte_size("hellö")
6

Observamos que el número de bytes en esa cadena es 6, a pesar de que tiene 5 caracteres. Esto se debe a que el carácter “ö” toma 2 bytes para ser representado en UTF-8. Podemos obtener la longitud real de la cadena, en función del número de caracteres, utilizando la función String.length/1:

iex> String.length("hellö")
5

El String module  contiene un montón de funciones para operar:

iex> String.upcase("hellö")
"HELLÖ"

Funciones anónimas

Estas funciones nos permiten almacenar y pasar código ejecutable como si fuera un entero o una cadena. Están delimitados por las palabras clave fn y end:

iex> add = fn a, b -> a + b end
#Function<12.71889879/2 in :erl_eval.expr/5>
iex> add.(1, 2)
3
iex> is_function(add)
true

Las funciones anónimas también se identifican por la cantidad de argumentos que reciben. Podemos verificar si una función usando is_function / 2:

iex> is_function(add, 2)
true

iex> is_function(add, 1)
false

Definamos una nueva función anónima que usa la función agregar anónimo que hemos definido previamente:

iex> double = fn a -> add.(a, a) end
#Function<6.71889879/1 in :erl_eval.expr/5>
iex> double.(2)
4

Una variable asignada dentro de una función no afecta a su entorno:

iex> x = 42
42
iex> (fn -> x = 0 end).()
0
iex> x
42

Listas

Se usan corchetes para especificar una lista de valores. Los valores pueden ser de cualquier tipo:

iex> [1, 2, true, 3]
[1, 2, true, 3]
iex> length [1, 2, 3]
3

Se pueden concatenar o restar dos listas utilizando los operadores ++ / 2 y – / 2 respectivamente:

iex> [1, 2, 3] ++ [4, 5, 6]
[1, 2, 3, 4, 5, 6]
iex> [1, true, 2, false, 3, true] -- [true, false]
[1, 2, 3, true]

Los operadores de listas nunca modifican la lista existente. Concatenar o eliminar elementos de una lista devuelve una nueva lista. Decimos que las estructuras de datos de Elixir son inmutables. Una ventaja de la inmutabilidad es que conduce a un código más claro. Puede pasar libremente los datos con la garantía de que nadie los mutará en la memoria, solo los transformará.

La cabeza es el primer elemento de una lista y la cola es el resto de la lista. Se pueden recuperar con las funciones hd/1 y tl/1. Asignemos una lista a una variable y recuperemos su cabeza y cola:

iex> list = [1, 2, 3]
iex> hd(list)
1
iex> tl(list)
[2, 3]

Obtener la cabeza o la cola de una lista vacía arroja un error:

iex> hd []
** (ArgumentError) argument error

A veces creará una lista y devolverá un valor entre comillas simples. Por ejemplo:

iex> [11, 12, 13]
'\v\f\r'
iex> [104, 101, 108, 108, 111]
'hello'

Cuando Elixir ve una lista de números ASCII imprimibles, Elixir lo imprimirá como una lista de caracteres (literalmente, una lista de caracteres). Las listas de caracteres son bastante comunes al interactuar con el código Erlang existente. Siempre que vea un valor en IEx y no esté seguro de cuál es, puede usar el i/1 para recuperar información al respecto:

iex> i 'hello'
Term
  'hello'
Data type
  List
Description
  ...
Raw representation
  [104, 101, 108, 108, 111]
Reference modules
  List
Implemented protocols
  ...

Las representaciones con comillas simples y dobles no son equivalentes en Elixir, ya que están representadas por diferentes tipos:

iex> 'hello' == "hello"
false

Las comillas simples son charlists, las comillas dobles son cadenas.

Tuplas

Elixir usa llaves para definir tuplas. Al igual que las listas, las tuplas pueden contener cualquier valor:

iex> {:ok, "hello"}
{:ok, "hello"}
iex> tuple_size {:ok, "hello"}
2

Las tuplas almacenan elementos contiguos en la memoria. Esto significa que acceder a un elemento de tupla por índice u obtener el tamaño de la tupla es una operación rápida. Los índices comienzan desde cero:

iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> elem(tuple, 1)
"hello"
iex> tuple_size(tuple)
2

También es posible poner un elemento en un índice particular en una tupla con put_elem/3:

iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> put_elem(tuple, 1, "world")
{:ok, "world"}
iex> tuple
{:ok, "hello"}

Observamos que put_elem/3 devolve una nueva tupla. La tupla original almacenada en la variable tupla no se modificó. Al igual que las listas, las tuplas también son inmutables. Cada operación en una tupla devuelve una nueva tupla, nunca cambia la dada.

¿Listas o tuplas?

Las listas se almacenan en la memoria como listas vinculadas, lo que significa que cada elemento de una lista mantiene su valor y apunta al siguiente elemento hasta llegar al final de la lista. Esto significa que acceder a la longitud de una lista es una operación lineal: debemos recorrer toda la lista para determinar su tamaño.

Del mismo modo, el rendimiento de la concatenación de listas depende de la longitud de la lista de la izquierda:

iex> list = [1, 2, 3]

iex> [0] ++ list
[0, 1, 2, 3]

iex> list ++ [4]
[1, 2, 3, 4]

Las tuplas, por otro lado, se almacenan contiguamente en la memoria. Esto significa que obtener el tamaño de tupla o acceder a un elemento por índice es rápido. Sin embargo, actualizar o agregar elementos a las tuplas es costoso porque requiere crear una nueva tupla en la memoria:

iex> tuple = {:a, :b, :c, :d}
iex> put_elem(tuple, 2, :e)
{:a, :b, :e, :d}

Hay que tener en cuenta que esto solo se aplica a la tupla en sí, no a su contenido. Por ejemplo, cuando actualiza una tupla, todas las entradas se comparten entre la tupla antigua y la nueva, excepto la entrada que ha sido reemplazada. En otras palabras, las tuplas y las listas en Elixir son capaces de compartir sus contenidos. Esto reduce la cantidad de asignación de memoria que necesita realizar el idioma y solo es posible gracias a la semántica inmutable del idioma.

Esas características de rendimiento dictan el uso de esas estructuras de datos. Un caso de uso muy común para las tuplas es usarlas para devolver información adicional de una función. Por ejemplo, File.read/1 es una función que se puede usar para leer el contenido del archivo. Devuelve una tupla:

iex> File.read("path/to/existing/file")
{:ok, "... contents ..."}
iex> File.read("path/to/unknown/file")
{:error, :enoent}

Si la ruta dada a File.read/1 existe, devuelve una tupla con el átomo :ok como el primer elemento y el contenido del archivo como el segundo. De lo contrario, devuelve una tupla con :error y la descripción del error.

La mayoría de las veces, Elixir te guiará para hacer lo correcto. Por ejemplo, hay una función elem/2 para acceder a un elemento de tupla, pero no hay un equivalente incorporado para las listas:

iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> elem(tuple, 1)
"hello"

Hasta ahora hemos utilizado 4 funciones de conteo: byte_size/1 (para el número de bytes en una cadena), tuple_size/1 (para el tamaño de la tupla), length/1 (para la longitud de la lista) y String.length/1 ( para el número de grafemas en una cadena). Usamos byte_size para obtener el número de bytes en una cadena, una operación barata. Recuperar el número de caracteres Unicode, por otro lado, usa String.length, y puede ser costoso ya que depende de un recorrido de toda la cadena.

Elixir también proporciona puertos, referencias y PID como tipos de datos (generalmente utilizados en la comunicación de procesos).

Taller de Elixir #2 – Primeros pasos

Documentación

Modo Interactivo

Cuando tenemos instalado Elixir. Tendremos 3 ejecutables: iex, elixir, mix.

El primero que vamos a ver es iex o iex.bat en windows. Que significa Interactive Elixir. En este shell, podremos escribir cualquier expresión de Elixir y obtener su resultado.

Un ejemplo sencillo sería.

Erlang/OTP 21.0 [64-bit] [smp:2:2] [...]

Interactive Elixir (1.10.2) - press Ctrl+C to exit
iex(1)> 40 + 2
42
iex(2)> "hello" <> " world"
"hello world"

Para salir de iex, presione Ctrl + C dos veces.

Ejecutar scripts

Creamos un fichero llamado “simple.exs” y le añadimos la siguiente linea.

IO.puts "Hello world from Elixir"

Salvamos el fichero y ejecutamos en la consola.

$ elixir simple.exs
Hello world from Elixir

Crear un proyecto

Creemos nuestro primer proyecto con “mix new” desde la línea de comandos. Pasaremos el nombre del proyecto como argumento (kv, en este caso), y le diremos a Mix que nuestro módulo principal debería ser el KV en mayúsculas, en lugar del predeterminado, que habría sido Kv:

$ mix new kv --module KV

Lo que nos devolverá algo parecido a esto:

* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/kv.ex
* creating test
* creating test/test_helper.exs
* creating test/kv_test.exs

El fichero responsable de la compilación del proyecto (Opciones, dependencias.. etc) es mix.exs y se genera automáticamente.

defmodule KV.MixProject do
  use Mix.Project

  def project do
    [
      app: :kv,
      version: "0.1.0",
      elixir: "~> 1.9",
      start_permanent: Mix.env == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications
  def application do
    [
      extra_applications: [:logger]
    ]
  end

  # Run "mix help deps" to learn about dependencies
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
    ]
  end
end

Ahora ya tenemos un proyecto. Se podría crea módulos y funciones. Para usarlo como librería de otra app. Pero queremos que se ejecute. Para ello modificamos el archivo mix.exs el apartado application. Tiene que ser algo parecido a esto.

  def application do
    [
      mod: {KV, []},
      extra_applications: [:logger]
    ]
  end

Eso hará que cuando ejecutemos la app nos llame a la función “start” del método “KV”. Nos vamos a fichero “lib/kv.ex” y cambiamos su contenido que es de ejemplo por:

defmodule KV do
  @moduledoc """
  Documentation for `KV`.
  """

  @doc """
    Run to start app.
  """
  def start(_type, _args) do
    IO.puts "starting"
    :timer.sleep(1000)
    Task.start(fn -> :timer.sleep(1000); IO.puts("done sleeping") end)
  end
end

Una vez realizado esto. Ejecutamos en consola:

$ mix run

Lo que nos devolverá el siguiente texto con un pequeño delay.

Compiling 1 file (.ex)
starting

Taller de Elixir #1 – Conceptos e instalación

Este taller estará basado en Elixir guides. Es básicamente una traducción del mismo con algunos cambios y apuntes.

¿Qué es?

Elixir es un lenguaje de programación funcionalconcurrente, de propósito general que se ejecuta sobre la máquina virtual de Erlang (BEAM). Elixir está escrito sobre Erlang y comparte las mismas abstracciones para desarrollar aplicaciones distribuidas y tolerantes a fallos. Elixir también proporciona un diseño extensible con herramientas productivas. Incluye soporte para metaprogramación en tiempo de compilación con macros y polimorfismo mediante protocolos.

Características

Instalación en Linux (Ubuntu)

wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb 
sudo dpkg -i erlang-solutions_1.0_all.deb
sudo apt-get update
sudo apt-get install esl-erlang
sudo apt-get install elixir

Instalación en Mac

brew install elixir (utilizando Homebrew)

Instalación en Windows

Descarga el instalador y sigue los pasos

Java con un poco de SpringBoot2

En esta entrada vamos a presentar un poco el framework SpringBoot2 para Java, es un software que como objetivo tiende a sustituir y eliminar los tediosos archivos XML del framework de Spring por las anotaciones, que básicamente son clases programadas que modifican el comportamiento de las clases, métodos y parámetros sobre los que están puestos, y se distinguen en el código por tener una @ delante del nombre de la anotación.

Tenemos decenas de anotaciones en el framework que nos van a ayudar a la hora de implementar un proyecto de forma muy rápida sin tener que reescribir el código necesario para que todo funcione, parece magia ya que todo es transparente para el programador, aunque nos obliga a formarnos, tiene una curva de aprendizaje muy rápida y sus funcionalidades pueden ayudarnos a la hora de integrar la lógica de la aplicación.

@anotaciones

@Autowired // Instancia una variable y sus @Beans
@Bean // Crea una instancia singleton
@SpringBootApplication // Instancia una aplicación SpringBoot2
@Controller // Clase controlador
@Service // Clase servicio
@Repository // Clase repositorio
@SpringBootTest // Instancia una bateria de pruebas
@RequesMapping // Prepara un método para un endpoint
@GetMapping // Mismo que el anterior HTTP GET
@PostMapping // Mismo que el anterior HTTP POST
@Async // Clase asíncrona
@EnableAsync // Instancia una aplicación asíncrona

Las anotaciones son muy potentes, nos permiten añadir funcionalidad al código sin tener que implementarla, podemos pasar parámetros de entrada en la anotación entre paréntesis () o varios entre llaves ({}) eso dependerá según para lo que esté programada la anotación.

@GetMapping({ "/", "/index" }) // dos parámetros
@PostMapping("/new") // un parámetro
@GetMapping("/{id}/edit") // podemos especificar parámetros enlazados con variables de entrada

Como vemos con estas herramientas fácilmente podríamos implementar una aplicación con el patrón MVC y añadir las funcionalidades necesarias como un simple CRUD

Spring Initializr para SpringBoot2

Para iniciar una aplicación en SpringBoot2 vamos a la web start.spring.io y seleccionamos el tipo de proyecto que vamos a desplegar y las librerías que vamos a utilizar

Una vez terminamos nos descargamos el proyecto y lo descomprimimos en el workspace para empezar a trabajar con el IDE que más os guste

Espero haber animado a usar este framework que cada día se utiliza más en aplicaciones, y ofrece características como la asincronía o la programación reactiva que no deja indiferente a la hora de poner aplicaciones en producción con altas cargas de peticiones.

Aquí os dejo un pom.xml de prueba

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.8.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Saludos

Modificadores de acceso en Java

Este post es un resumen de los modificadores de Java. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

Los modificadores de acceso permiten el encapsulamiento. El cual busca la forma controlar el acceso a los datos de un objeto o instancia.

Los modificadores dan seguridad a las aplicaciones limitando el acceso a diferentes atributos, métodos, constructores asegurando una “ruta” especificada acceder a la información.

Si nuestra aplicación es usada por programadores. Con modificadores de acceso aseguramos que un valor no será modificado incorrectamente. Para eso usaremos el acceso a los atributos con los métodos get y set.

  • Private

Este modificador solo nos permitirá acceder desde la misma clase. En caso de un método solo se podrá llamar internamente. Para los atributos, se crearan métodos públicos GETTERS y SETTERS.

package app.ejemplo;
public class Ejemplo1
{
	// Atributo y sus metodos
	private int atributo;

	public int getatributo()
	{
	  return atributo;
	}

	public void setAtributo(int atributo)
	{
	  this.atributo = atributo;
	}

	// Metodo
	private int metodo(){
	  //code;
	}
}
  • Default

Este acceso por defecto que permite que tanto la propia clase como las clases del mismo paquete.

package app.ejemplo;
public class Ejemplo2
{
    static int atributo = 0;
}
package app.ejemplo2;
public class Ejemplo2_1
{
    public static int getAtributo()
    {
            return Ejemplo2.atributo;
    }
}
  • Protected

Nos permite acceder a las propiedades de la clase padre, cuando estemos haciendo herencias. Fuera de las clases hijas es equivalente a private.

package app.ejemplo;
public class Ejemplo3
{
    protected static int atributo = 0;    
}
package app.ejemplo3_1;
import app.ejemplo3.Ejemplo3;
public class Ejemplo3_1 extends Ejemplo3
{
    public static void main(String[] args)
    {
        System.out.println(atributo)
    }
}
  • Public

Es el mas permisivo. Cualquier clase tendra acceso a el sin importar paquete o procedencia.

package app.ejemplo4;
public class Ejemplo4
{
    public static int atributo = 0;

    public static void metodo()
    {
        System.out.println("Metodo Publico");
    }
}
package otro.paquete;
import app.ejemplo4.Ejemplo4;

public class OtraExterna
{
    public static void main(String[] args)
    {
        System.out.println(Ejemplo4.atributo);
        Ejemplo4.metodo(); 
    }
}
  • La directiva Static

Static es una directiva no un modificador de acceso, pero por utilidad vamos desarrollarla un poco.

Una clase, método o campo declarado como estático puede ser accedido o invocado sin la necesidad de tener que instanciar un objeto de la clase. Uno de los ejemplos típicos de uso de métodos y variables estáticas es la clase java.lang.Math.

public class MathTest {
     public static void main(String[] args) {
        double floorOfPi = Math.floor(Math.PI);
        System.out.println(floorOfPi);
    }
}

Map, filter y reduce (JavaScript)

javascript

Hola, en esta entrada vamos a explicar un poco los métodos nativos map, filter y reduce, que encontramos en los objetos Arrays de JavaScript y como pueden ayudar a hacer más eficiente la implementación, ya que son más rápidos que los bucles tradicionales.

  • map([🌽, 🐮, 🐔], cook) => [🍿, 🍔, 🍳]
  • filter([🍿, 🍔, 🍳], isVegetarian) => [🍿, 🍳]
  • reduce([🍿, 🍳], eat) => 💩

Map

El método map() devuelve un nuevo Array como resultado de la función que se está aplicando a cada elemento del Array. Esto significa que cada elemento del Array va a ser devuelto en la misma posición del Array resultante pasando por la función del método map(), como lo haría un iterador.

// Declaramos un Array
> var a = new Array(1, 2, 3) || [1, 2, 3]
// Mapeamos el Array con una función para elevar al cuadrado el contenido
> var resultado = a.map(elemento => Math.pow(elemento, 2))
// Se imprime el resultado
> console.log(resultado)
> [1, 4, 9]

Finalmente el método map() devuelve un nuevo Array de la misma dimensión que el original pero modificando cada elemento por el de la salida de la función que estemos aplicando, por lo que no se modifica el Array original.

Filter

El método filter() del objeto Array, como su nombre indica se utiliza para filtrar los elementos del Array con las condiciones lógicas que se tenga en la función que implementa, si la condición no pasa el filtro este elemento no es devuelto en el Array resultante, quedando una dimensión menor que el original.

// Declaramos un Array
> var a = new Array(1, 2, 3) || [1, 2, 3]
// Filtramos el Array con una función para obviar el número 2
> var resultado = a.filter(elemento => elemento !== 2)
// Se imprime el resultado
> console.log(resultado)
> [1, 3]

Vemos como el filtro ignora el número 2 ya que la condición es que sea distinto del número 2, por lo que este número si se encuentra en el Array no es devuelto en el resultante y su posición se obvia, tampoco se modifica el Array original.

Reduce

El método reduce() del objeto Array, este método reduce el Array a un único elemento, ejecuta la función que tiene el método en cada uno de los elementos del Array y el resultado de cada elemento se almacena en un acumulador que será el resultado total.

// Declaramos un Array
> var a = new Array(1, 2, 3) || [1, 2, 3]
// Reducimos el Array a un solo elemento sumando los cuadrados de los elementos del Array
> var resultado = a.reduce((acumulador, elemento) => acumulador + Math.pow(elemento,2))
// Se imprime el resultado
> console.log(resultado)
> 14

Como vemos el resultado en este caso no es un nuevo Array sino el acumulador de la función que apliquemos, tampoco se modifica el Array original.

Conclusiones

Para terminar añadir que ninguno de estos tres métodos utiliza un elemento que no esté definido, en caso de que sea undefined o null se obvia la función aplicada.

Es una buena práctica utilizar los métodos nativos de los Arrays en vez de los bucles tradicionales, ya que son mucho más rápidos a la hora de iterar y si estamos aplicando funciones se hace todo con una sola instrucción y es más limpio.

Los mapas de Elixir tienen una sintaxis incorporada para actualizar

Esto es una traducción de un post de Marin Abernethy  en el blog dockyard.com. En modo de homenaje y agradecimiento. Con la intención de que la comunidad hispana pueda disfrutarlo en su idioma nativo.

En Elixir a menudo, encontramos que hay muchas formas de implementar una sola tarea. Por ejemplo, cuando queremos actualizar un valor clave en un mapa, tenemos varias opciones por delante…

Dado,    expenses = %{groceries: 200, rent: 1000, commute: 70}  podría emplear:

  • Si deseamos actualizar varios pares de valores clave y / o varios nuevos.
# Sintaxis
Map.merge(map1, map2)
# Ejemplo
Map.merge(expenses, %{ rent: 1200, comcast: 100 }) 
  • Si actualizamos o agregamos un solo valor de clave.
# Sintaxis
Map.put(map, key, val)
# Ejemplo
Map.put(expenses, :booze, 100) 
  •  Si queremos incrementar un valor en cierto grado.
# Sintaxis
Map.update(map, key, initial, fun)
# Ejemplo
Map.update(expenses, :misc, 300, &(&1 * 2)) 
  • Si queremos actualizar un valor en una estructura anidada.
# Sintaxis
Kernel.put_in(data, keys, value) 
# Ejemplo
expenses = %{groceries: %{milk: 5}, apartment: %{rent: 1000, comcast: 100}}
put_in(expenses, [:rent, :comcast], "too much")
  • Sin embargo, los mapas vienen con una sintaxis integrada para actualizar uno o más valores clave.
%{expenses | groceries: 150, commute: 75}