Encontré un articulo por demás interesante que nos muestra las novedades de swift con ejemplos.
Dejo link:
http://www.appcoda.com/swift4-changes/?utm_content=bufferbefa9&utm_medium=social&utm_source=plus.google.com&utm_campaign=buffer
Translate
jueves, 29 de junio de 2017
miércoles, 28 de junio de 2017
Parámetro implícito en Scala
"Este es el primer paso para implementar la abstracción contextual en Scala". ¿Qué quiero decir con esto?
Abstracción: La capacidad de nombrar un concepto y usar sólo el nombre después.
Contextual: Un fragmento de un programa produce resultados o resultados en algún contexto. Nuestros lenguajes de programación son muy buenos para describir y abstraer lo que se producen. Pero casi no hay nada disponible para abstraer sobre las entradas que los programas obtienen de su contexto. Un ejemplo para resolver esto es la inyección de dependencias.
Los tipos de funciones implícitas son una forma sorprendentemente sencilla y general de hacer abstractables los patrones de codificación que resuelven estas tareas, reduciendo el código clásico y aumentando la aplicabilidad. Para entender esto debemos entender los parámetro implícito
En un lenguaje funcional, las entradas a un cálculo se expresan más naturalmente como parámetros. Uno podría simplemente aumentar las funciones para tomar parámetros adicionales que representan configuraciones, capacidades, diccionarios, o cualquier otro dato contextual que las funciones necesiten. El único inconveniente de esto es que a menudo hay una gran distancia en el gráfico de llamadas entre la definición de un elemento contextual y el sitio donde se utiliza. En consecuencia, se hace tedioso definir todos esos parámetros intermedios y pasarlos a lo largo de donde finalmente se consumen.
Los parámetros implícitos solucionan la mitad del problema. Ellos no tienen que ser propagados usando código de repetitivo; el compilador se encarga de eso. Esto los hace prácticos en muchos escenarios donde los parámetros simples serían demasiado engorrosos. Los parámetros implícitos también son muy útiles como un mecanismo general de paso del contexto.
Digamos que queremos escribir algún código que está diseñado para ejecutarse en una transacción. En aras de la ilustración, aquí hay una clase de transacción simple:
class Transaction {
private val log = new ListBuffer[String]
def println(s: String): Unit = log += s
private var aborted = false
private var committed = false
def abort(): Unit = { aborted = true }
def isAborted = aborted
def commit(): Unit =
if (!aborted && !committed) {
Console.println("******* log ********")
log.foreach(Console.println)
committed = true
}
}
La transacción encapsula un registro, al que se pueden imprimir mensajes. Puede estar en uno de los tres estados: run, commit o abort. Si la transacción se confirma, imprime el registro almacenado en la consola.
El método de transacción permite ejecutar un determinado código dentro de una transacción recién creada:
Abstracción: La capacidad de nombrar un concepto y usar sólo el nombre después.
Contextual: Un fragmento de un programa produce resultados o resultados en algún contexto. Nuestros lenguajes de programación son muy buenos para describir y abstraer lo que se producen. Pero casi no hay nada disponible para abstraer sobre las entradas que los programas obtienen de su contexto. Un ejemplo para resolver esto es la inyección de dependencias.
Los tipos de funciones implícitas son una forma sorprendentemente sencilla y general de hacer abstractables los patrones de codificación que resuelven estas tareas, reduciendo el código clásico y aumentando la aplicabilidad. Para entender esto debemos entender los parámetro implícito
En un lenguaje funcional, las entradas a un cálculo se expresan más naturalmente como parámetros. Uno podría simplemente aumentar las funciones para tomar parámetros adicionales que representan configuraciones, capacidades, diccionarios, o cualquier otro dato contextual que las funciones necesiten. El único inconveniente de esto es que a menudo hay una gran distancia en el gráfico de llamadas entre la definición de un elemento contextual y el sitio donde se utiliza. En consecuencia, se hace tedioso definir todos esos parámetros intermedios y pasarlos a lo largo de donde finalmente se consumen.
Los parámetros implícitos solucionan la mitad del problema. Ellos no tienen que ser propagados usando código de repetitivo; el compilador se encarga de eso. Esto los hace prácticos en muchos escenarios donde los parámetros simples serían demasiado engorrosos. Los parámetros implícitos también son muy útiles como un mecanismo general de paso del contexto.
Digamos que queremos escribir algún código que está diseñado para ejecutarse en una transacción. En aras de la ilustración, aquí hay una clase de transacción simple:
class Transaction {
private val log = new ListBuffer[String]
def println(s: String): Unit = log += s
private var aborted = false
private var committed = false
def abort(): Unit = { aborted = true }
def isAborted = aborted
def commit(): Unit =
if (!aborted && !committed) {
Console.println("******* log ********")
log.foreach(Console.println)
committed = true
}
}
La transacción encapsula un registro, al que se pueden imprimir mensajes. Puede estar en uno de los tres estados: run, commit o abort. Si la transacción se confirma, imprime el registro almacenado en la consola.
El método de transacción permite ejecutar un determinado código dentro de una transacción recién creada:
def transaction[T](op: Transaction => T) = {
val trans: Transaction = new Transaction
op(trans)
trans.commit()
}
La transacción actual se debe pasar a lo largo de una cadena de llamadas a todos los lugares que necesitan para acceder a ella. Para ilustrar esto, aquí están tres funciones f1, f2 y f3 que se llaman entre sí, y también acceder a la transacción actual. La manera más conveniente de lograr esto es pasar la transacción actual como un parámetro implícito.
def f1(x: Int)(implicit thisTransaction: Transaction): Int = {
thisTransaction.println(s"first step: $x")
f2(x + 1)
}
def f2(x: Int)(implicit thisTransaction: Transaction): Int = {
thisTransaction.println(s"second step: $x")
f3(x * x)
}
def f3(x: Int)(implicit thisTransaction: Transaction): Int = {
thisTransaction.println(s"third step: $x")
if (x % 2 != 0) thisTransaction.abort()
x
}
El programa principal llama a f1 en un nuevo contexto de transacción e imprime su resultado:
def main(args: Array[String]) = {
transaction {
implicit thisTransaction =>
val res = f1(args.length)
println(if (thisTransaction.isAborted) "aborted" else s"result: $res")
}
}
lunes, 26 de junio de 2017
Un Ejemplo de Polimorfismo en C++
La idea es que una empresa tiene un conjunto de bienes los cuales tienen un valor y a la vez algunos bienes pueden ser amortizados (La amortización es un término económico y contable, referido al proceso de distribución de gasto en el tiempo de un valor duradero. Adicionalmente se utiliza como sinónimo de depreciación en cualquiera de sus métodos.)
Los bienes se clasifican en inmuebles, muebles y rodados. A la vez los inmuebles no pierden el valor en el tiempo (es decir no son amortizables) . El software debe proveer una forma de saber el valor de todos los bienes y calcular su amortización.
Para resolver este problema vamos a definir 1 clase abstracta bien que describa la característica que tienen los bienes de saber su valor y la característica de calcular la amortización. A la vez vamos a crear un gestor contable que imprima las amortizaciones.
Veamos la clase abstracta bien:
bien.h :
#ifndef BIEN_H
#define BIEN_H
#include <iostream>
class Bien
{
protected:
double valor = 0.0;
public:
Bien();
double virtual amortizar() = 0;
void setValor(double valor);
friend std::ostream& operator<<(std::ostream& os, const Bien& obj);
};
#endif // BIEN_H
#include "bien.h"
Bien::Bien()
{
this->valor = 0;
}
void Bien::setValor(double valor){
this->valor = valor;
}
std::ostream& operator<<(std::ostream& os, const Bien& obj){
return os << "Bien : " << obj.valor;
}
rodado.h :
#ifndef RODADO_H
#define RODADO_H
#include <iostream>
#include "bien.h"
class Rodado : public Bien
{
protected:
int km = 0;
public:
Rodado();
double amortizar();
void setKm(int km);
};
#endif // RODADO_H
rodado.cpp :
#include "rodado.h"
Rodado::Rodado()
{
}
double Rodado::amortizar(){
int por = this->km /1000;
return this->valor * ((0.1) * por);
}
void Rodado::setKm(int km){
this->km = km;
}
Veamos mueble.h:
#ifndef MUEBLE_H
#define MUEBLE_H
#include <iostream>
#include "bien.h"
class Mueble : public Bien
{
protected:
int anioCreacion = 1900;
public:
Mueble(int anioCreacion);
double amortizar();
void setAnioCreacion(int anioCreacion);
};
#endif // MUEBLE_H
mueble.cpp :
#include "mueble.h"
Mueble::Mueble(int anioCreacion)
{
this->anioCreacion = anioCreacion;
}
double Mueble::amortizar(){
int dif = 2017 - this->anioCreacion;
return this->valor * (dif * 0.05);
}
void Mueble::setAnioCreacion(int anioCreacion){
this->anioCreacion = anioCreacion;
}
Veamos el inmueble que le puse "Terreno" por lo tanto veremos a terreno.h :
#ifndef TERRENO_H
#define TERRENO_H
#include <iostream>
#include "bien.h"
class Terreno : public Bien
{
public:
Terreno();
double amortizar();
};
#endif // TERRENO_H
terreno.cpp :
#include "terreno.h"
Terreno::Terreno()
{
}
double Terreno::amortizar(){
return 0.0; //no amortiza por eso retorna 0
}
Ahora veremos el gestor contable que no hace mucho en el ejemplo, pero usen la imaginación y piensen que debería guardar los registros, calcular asientos, etc.
gestorcontable.h :
#ifndef GESTORCONTABLE_H
#define GESTORCONTABLE_H
#include <iostream>
#include "bien.h"
using namespace std;
class GestorContable
{
public:
GestorContable();
void imprimir(Bien * unBien);
};
#endif // GESTORCONTABLE_H
gestorcontable.cpp :
#include "gestorcontable.h"
GestorContable::GestorContable()
{
}
void GestorContable::imprimir(Bien * unBien){
cout << *unBien << " amortizacion : "<< unBien->amortizar() << endl;
}
Como pueden ver el Bien es abstracto y sus especializaciones polimorficas y el gestor contable usa esas características y utiliza el polimorfismo de esta manera no importa que bien deba imprimir, como el calculo de la amortización lo sabe hacer cada bien, cada bien calculara su amortización por lo tanto lo hará correctamente.
Recuerden que el polimorfismo se refiere a la propiedad por la que es posible enviar mensajes sintácticamente iguales a objetos de tipos distintos. El único requisito que deben cumplir los objetos que se utilizan de manera polimórfica es saber responder al mensaje que se les envía.
Espero que les sirva!!
Antes de despedirme les muestro el main:
#include <iostream>
#include "bien.h"
#include "mueble.h"
#include "rodado.h"
#include "terreno.h"
#include "gestorcontable.h"
using namespace std;
int main()
{
GestorContable gestorContable = GestorContable();
Bien * unTerreno = new Terreno();
unTerreno->setValor(12000.0);
gestorContable.imprimir(unTerreno);
Bien * unRodado = new Rodado();
Rodado * o = 0;
// Esto lo hago solo para mostrar un cambio de tipos.
if (o = reinterpret_cast<Rodado*> (unRodado)) {
o->setKm(2450);
}
unRodado->setValor(400000.00);
gestorContable.imprimir(unRodado);
Bien * unMueble = new Mueble(2000);
unMueble->setValor(47000.00);
gestorContable.imprimir(unMueble);
return 0;
}
domingo, 25 de junio de 2017
Un Ejemplo de Polimorfismo en Java
La idea es mostrar un ejemplo de polimorfismo para los que comienzan a programar en el paradigma orientado a objetos.
La idea es que una empresa tiene un conjunto de bienes los cuales tienen un valor y a la vez algunos bienes pueden ser amortizados (La amortización es un término económico y contable, referido al proceso de distribución de gasto en el tiempo de un valor duradero. Adicionalmente se utiliza como sinónimo de depreciación en cualquiera de sus métodos.)
Los bienes se clasifican en inmuebles, muebles y rodados. A la vez los inmuebles no pierden el valor en el tiempo (es decir no son amortizables) . El software debe proveer una forma de saber el valor de todos los bienes y calcular su amortización.
Para resolver este problema vamos a definir 2 interfaces una que describa la característica que tienen los bienes de saber su valor y otra que describa la característica de calcular la amortización.
public interface Valorizable {
public Double getValor();
}
public interface Amortizable {
public Double calcularAmortizacion();
}
Programemos los bienes, empesamos con el mueble que para el ejemplo le puse Edificio:
import java.util.Calendar;
import java.util.Date;
public class Edificio implements Valorizable, Amortizable {
private Double valor;
private Date fechaDeCreacion;
public Edificio(Double valorInicial, Date fechaDeCreacion) {
this.valor = valorInicial;
this.fechaDeCreacion = fechaDeCreacion;
}
@Override
public Double calcularAmortizacion() {
Calendar cal = Calendar.getInstance();
int actualYear =cal.get(Calendar.YEAR);
cal.setTime(fechaDeCreacion);
int year =cal.get(Calendar.YEAR);
int diferencia = actualYear - year;
Double amortizacion = (diferencia * valor) / 300;
this.valor = this.valor - amortizacion;
return amortizacion;
}
@Override
public Double getValor() {
return this.valor;
}
@Override
public String toString() {
return "mueble " + this.valor;
}
}
Seguimos con el rodado:
public class Rodado implements Amortizable, Valorizable{
private static final Double VALOR_AMORTIZACION = 0.2;
private Double valor;
private Integer kms;
public Rodado(Double valorInicial, Integer kms) {
this.valor = valorInicial;
this.kms = kms;
}
public Double getValor() {
return valor;
}
public Double calcularAmortizacion() {
Double amotizacion = 0.0;
if (valor > 0.0) {
amotizacion = (VALOR_AMORTIZACION * kms.doubleValue())/100;
valor = valor - amotizacion;
}
return amotizacion;
}
@Override
public String toString() {
return "rodado " + this.valor;
}
}
Y por ultimo programemos el terreno:
public class Terreno implements Valorizable {
private Double valor= 0.0;
private String direccion = "";
public Terreno(Double valor, String direccion) {
this.valor = valor;
this.direccion = direccion;
}
@Override
public Double getValor() {
return valor;
}
@Override
public String toString() {
return this.direccion;
}
}
De esta manera podemos tratar a todos los objetos amortizables como si fueran del mismo tipo y a todos los valorables como si fueran del mismo tipo, sin importarnos como calculan el valor o la amortización.
Veamos el main:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
public class Main {
public static void main(String[] args) {
// Construyo los Objetos
Calendar cal = Calendar.getInstance();
cal.set(1990, 02, 02);
Edificio unEdificio = new Edificio(150000.00, cal.getTime());
Rodado unRodado = new Rodado(12000.00, 1000);
Terreno unTerreno = new Terreno(600000.00, "Los colibies 234");
List<Amortizable> list = new ArrayList<>();
list.add(unEdificio);
list.add(unRodado);
//list.add(unTerreno); No es posible agregar un terreno porque no es Amortizable
System.out.println();
System.out.println("Calcular Amortizacion");
for (Amortizable amortizar : list) {
System.out.println(amortizar.calcularAmortizacion());
}
List<Valorizable> list2 = new ArrayList<>();
list2.add(unEdificio);
list2.add(unRodado);
list2.add(unTerreno);
System.out.println();
System.out.println("Imprimir el valor");
for (Valorizable valorizar : list2) {
System.out.println(valorizar.getValor());
}
// En Java es común el uso de polimorfismo, veamos un ejemplo:
List<Object> list3 = new ArrayList<>();
list3.add(unEdificio);
list3.add(unRodado);
list3.add(unTerreno);
list3.add("Hola!");
System.out.println();
System.out.println("Hacer to String");
for (Object object : list3) {
System.out.println(object.toString()); //toString es llamado de forma polimorfica.
}
}
}
Recuerden que el polimorfismo se refiere a la propiedad por la que es posible enviar mensajes sintácticamente iguales a objetos de tipos distintos. El único requisito que deben cumplir los objetos que se utilizan de manera polimórfica es saber responder al mensaje que se les envía.
Espero que les sirva!!
Un resumen de Scala for the Impatient, parte 23
Sobrescribir campos
Se puede sobrescribir val (o un método sin parámetros) con una declaración val con el mismo nombre. La clase tiene privados los atributos y públicos los getters y setters por lo tanto se sobrescribirán estos métodos.
Por ejemplo:
class Person(val name: String) {
override def toString = getClass.getName + "[name=" + name + "]"
}
class SecretAgent(codename: String) extends Person(codename) {
override val name = "secret" // Don’t want to reveal name . . .
override val toString = "secret" // . . . or class name
}
Este ejemplo muestra el mecanismo, pero es bastante artificial. Un caso más común es sobrescribir un def de una clase abstracta, veamos un ejemplo :
abstract class Person { // See Section 8.8 for abstract classes
def id: Int // Each person has an ID that is computed in some way
...
}
class Student(override val id: Int) extends Person
// A student ID is simply provided in the constructor
Note las siguientes restricciones:
- Un def solo puede ser sobrescrito por un def
- Un val solo puede ser sobrescrito por otro val o un def sin parámetros
- Un var solo puede ser sobrescrito por un var abstracto
Veamos un cuadro que describe la sobrecarga:
|
Con val |
Con def |
Con var |
Sobrescribir val |
La subclase tiene un campo privado (con el mismo nombre que el campo de la superclase: está bien). Getter reemplaza al getter de superclase. |
Error |
Error |
Sobrescribir def |
La subclase tiene un campo privado. Getter anula el método de superclase. |
Como java. |
Una var puede anular un par getter / setter. Anular solo el getter produce un error. |
Sobrescribir var |
Error |
Error |
Sólo si la superclase var es abstracta |
Subclases anónimas.
Como en java, se pueden implementar interfaces o extender clases abstractas implementando los métodos a continuación del llamado de dicha clase o interfaz, es más fácil explicar esto con un ejemplo:
val alien = new Person("Fred") {
def greeting = "Greetings, Earthling! My name is Fred."
}
Técnicamente esto creo una persona con el método “greeting” implementado con el texto: "Greetings, Earthling! My name is Fred." El tipo es Person{def greeting: String}. Se puede utilizar este tipo como parámetro de la siguiente forma:
def meet(p: Person{def greeting: String}) {
println(p.name + " says: " + p.greeting)
}
Clases Abstractas.
Como en java, podemos definir una clase abstracta con la palabra “abstract” y esta clase no se podrá instanciar. Normalmente esto es usado de la siguiente manera porque hay uno o más métodos que no podemos definir, es decir que son abstractos.
abstract class Person(val name: String) {
def id: Int // No method body—this is an abstract method
}
Una subclase de Person va a estar obligada a implementar el método id o ser abstracta. A diferencia de java no es necesario utilizar la palabra abstract para los métodos, simplemente debemos omitir el cuerpo de la función.
Una subclase concreta esta obligada a sobre escribir este método:
class Employee(name: String) extends Person(name) {
def id = name.hashCode // override keyword not required
}
jueves, 22 de junio de 2017
Empezando con Elixir 5
Estructuras de control
if y unless
Si hemos programado estamos familiarizados con el if y en menor medida con el unless. Estas estructuras son construidas en elixir por medio de macros y no forma parte del lenguaje.
Por otra parte es necesario aclarar que en elixir solo es falso el nil y el false (por supuesto)
iex> if String.valid?("Hello") do
...> "Valid string!"
...> else
...> "Invalid string."
...> end
"Valid string!"
iex> if "a string value" do
...> "Truthy"
...> end
"Truthy"
Se utiliza unless para analizar los casos falsos:
iex> unless is_integer("hello") do
...> "Not an Int"
...> end
"Not an Int"
case
Esta estructura nos permite utilizar el pattern matching:
iex> case {:ok, "Hello World"} do
...> {:ok, result} -> result
...> {:error} -> "Uh oh!"
...> _ -> "Catch all"
...> end
"Hello World"
El valor _ es similar al default de c o java. Y esto puede servir para prevenir errores:
iex> case :even do
...> :odd -> "Odd"
...> end
** (CaseClauseError) no case clause matching: :even
iex> case :even do
...> :odd -> "Odd"
...> _ -> "Not Odd"
...> end
"Not Odd"
Dado que case se basa en pattern matching, se aplican todas las mismas reglas y restricciones. Si se quiere que coincida con variables existentes debe usar el operador pin ^ :
iex> pie = 3.14
3.14
iex> case "cherry pie" do
...> ^pie -> "Not so tasty"
...> pie -> "I bet #{pie} is tasty"
...> end
"I bet cherry pie is tasty"
Permite tambien utilizar clausulas de protección:
iex> case {1, 2, 3} do
...> {1, x, 3} when x > 0 ->
...> "Will match"
...> _ ->
...> "Won't match"
...> end
"Will match"
cond
Cuando necesitamos hacer coincidir condiciones en vez de valores, podemos recurrir a cond. Esto es similar a else if o elsif de otros lenguajes:
iex> cond do
...> 2 + 2 == 5 ->
...> "This will not be true"
...> 2 * 2 == 3 ->
...> "Nor this"
...> 1 + 1 == 2 ->
...> "But this will"
...> end
"But this will"
Igual que case podemos tener un default que en este caso va ser el valor true :
iex> cond do
...> 7 + 1 == 0 -> "Incorrect"
...> true -> "Catch all"
...> end
"Catch all"
with
with es útil cuando se puede usar una sentencia case anidada o situaciones que no se pueden canalizar de forma limpia. La expresión with se compone de las palabras clave, los generadores y, finalmente, una expresión.
Veamos un ejemplo simple y luego veremos algo más:
iex> user = %{first: "Sean", last: "Callan"}
%{first: "Sean", last: "Callan"}
iex> with {:ok, first} <- Map.fetch(user, :first),
...> {:ok, last} <- Map.fetch(user, :last),
...> do: last <> ", " <> first
"Callan, Sean"
En el caso de que una expresión no coincida, se devolverá un error:
iex> user = %{first: "doomspork"}
%{first: "doomspork"}
iex> with {:ok, first} <- Map.fetch(user, :first),
...> {:ok, last} <- Map.fetch(user, :last),
...> do: last <> ", " <> first
:error
Ahora veamos un ejemplo más grande sin with y luego veamos cómo podemos refactorizarlo:
case Repo.insert(changeset) do
{:ok, user} ->
case Guardian.encode_and_sign(resource, :token, claims) do
{:ok, token, full_claims} ->
important_stuff(token, full_claims)
error -> error
end
error -> error
end
Ahora usaremos with:
with {:ok, user} <- Repo.insert(changeset),
{:ok, token, full_claims} <- Guardian.encode_and_sign(user, :token) do
important_stuff(token, full_claims)
end
En Elixir 1.3 el with soporta el else:
import Integer
m = %{a: 1, c: 3}
a =
with {:ok, number} <- Map.fetch(m, :a),
true <- Integer.is_even(number) do
IO.puts "#{number} divided by 2 is #{div(number, 2)}"
:even
else
:error ->
IO.puts "We don't have this item in map"
:error
_ ->
IO.puts "It is odd"
:odd
end
Dejo link: https://elixirschool.com/lessons/basics/control-structures/
martes, 20 de junio de 2017
Un resumen de Scala for the Impatient, parte 22
Extender una Clase.
Se puede extender una clase con la palabra extends :
class Employee extends Person {
var salary = 0.0
…
}
Como en Java, en la subclase se pueden agregar atributos y métodos y sobre escribir métodos existentes de la super clases.
Igual que Java, se pueden marcar las clases como final y no van a poder ser extendidas pero en scala se agrega que un método o atributo pueden ser final.
Sobre escribir métodos.
En scala se debe utilizar el modificador override cuando se sobre escribe un método y este no es abstracto. Por ejemplo:
public class Person {
…
override def toString = getClass.getName + "[name=" + name + "]"
}
El modificador override es muy útil para encontrar errores muy comunes como los siguientes:
- Cuando se escribe mal el método que quiero sobre escribir
- Cuando se agrega un parámetro de más o de menos, y no tiene la misma firma.
- Cuando se modifica el método padre en la super clase.
Si se desea llamar a un método del padre se hace igual que java se llama por medio de la palabra clave super.
public class Employee extends Person {
…
override def toString = super.toString + "[salary=" + salary + "]"
}
Al llamar a super.toString se esta llamando a el método toString de la clase Person.
Chequeo de tipos y casteos.
El desarrollador puede saber si un objeto es de una clase determinada con el método isInstanceOf. Si esta clase es de un método determinado se puede castear utilizando asInstanceOf, veamos un ejemplo:
if (p.isInstanceOf[Employee]) {
val s = p.asInstanceOf[Employee] // s has type Employee
…
}
isInstanceOf retorna si un objeto es de una clase y asInstanceOf hace el casteo.
Si p es null, isInstanceOf retorna false y asInstanceOf retorna null.
Si p no es un objeto Employee, asInstanceOf lanza una excepción.
Si es necesario saber que p es un empleado pero no una subclase de empleado lo hacemos de este modo:
if (p.getClass == classOf[Employee])
La función classOf esta definido en scala.Predef que siempre es importado.
A continuación se muestra una comparación con formas de chequeo de java:
Scala | Java |
---|---|
obj.isInstanceOf[Cl]
|
obj instanceof Cl
|
obj.asInstanceOf[Cl]
|
(Cl) obj
|
classOf[Cl]
|
Cl.class
|
A la vez el pattern matching es útil para saber los tipos:
p match {
case s: Employee => ... // Hacer cosas con el empleado
case _ => ... // p no es un empleado
}
Atributos y métodos protegidos
Como en java o c++ en scala existe los atributos o métodos protegidos, que son los que puede ver la clase y sus descendientes y no por otras clases.
Pero al contrario de java estos atributos no son visibles para los objetos de su paquete.
Constructor de la super clase.
Como recordaran existe un constructor principal de la clase y pueden existir n constructores auxiliares y que todos los constructores auxiliares llaman al constructor principal.
Como consecuencia de esto un constructor auxiliar no puede invocar a un constructor auxiliar de la super clase directamente.
El constructor auxiliares de la subclase deben llamar al constructor principal de la subclase y solo el constructor principal puede llamar al constructor principal de la super clase.
El constructor principal está relacionado con la definición de clase. La llamada al constructor de la superclase está igualmente relacionado. Veamos un ejemplo:
class Employee(name: String, age: Int, val salary : Double) extends
Person(name, age)
y el primer constructor llama al constructor de la super clase.
Note que el código es sumamente conciso y podemos pensar a nuestro constructor principal con la mayoría de los datos y los auxiliares al llamarlo pondrán valores por defecto.
Una clase Scala puede extender de una clase java. Por ejemplo:
class Square(x: Int, y: Int, width: Int) extends
java.awt.Rectangle(x, y, width, width)
Un resumen de Scala for the Impatient, parte 21
Los imports pueden estar en cualquier lado.
En scala los import pueden estar en cualquier lugar. No solo en el
principio del archivo. Por ejemplo:
class Manager {
import scala.collection.mutable._
val subordinates = new ArrayBuffer[Employee]
…
}
Esto es muy útil, dado que reduce las posibilidades de conflicto.
Renombrar y ocultar miembros.
En scala se pueden importar algunos miembros de un paquete usando el
selector:
import java.awt.{Color, Font}
La sintaxis del selector permite renombrar las clases :
import java.util.{HashMap => JavaHashMap}
import scala.collection.mutable._
Ahora JavaHashMap es java.util.HashMap y HashMap es
scala.collection.mutable.HashMap
El selector => _ es útil para ocultar una implementación. Esto es
útil en el caso particular de que se quiera dejar de usar una clase
para utilizar otro por ejemplo dentro de una clase:
import java.util.{HashMap => _, _}
import scala.collection.mutable._
Ahora HashMap es scala.collection.mutable.HashMap dado que
java.util.HashMap se oculto.
Imports implícito.
Cada programa de scala se importan de forma implícita los siguientes
paquetes:
import java.lang._
import scala._
import Predef._
Como es un programa Java se importa todas las clases de java.lang y
luego se importan las clases de scala que en cierto caso pisan alas de
java. Por ejemplo scala.StringBuilder pisa a java.lang.StringBuilder.
Y por ultimo se importa el objeto Predef. Que es un objeto que
contiene funciones útiles.
Como el paquete scala es importado por defecto no es necesario
importarlo luego, por ejemplo:
collection.mutable.HashMap es scala.collection.mutable.HashMap pero
no es necesario escribir el comienzo del paquete.
sábado, 17 de junio de 2017
Demuestra todo lo que sabes sobre la nube en el Azure Skills Challenge
miércoles, 14 de junio de 2017
Programación Funcional en Erlang
Me acabo de anotar en un curso de programación funcional en erlang que se dicta de forma gratuita, por la pagina futurelearn y la universidad de Kent (superman?)
Comienza el 19 de este mes.
Dejo link : https://www.futurelearn.com/courses/functional-programming-erlang/
https://www.cs.kent.ac.uk/
martes, 13 de junio de 2017
EdX en español !!!
El sitio de cursos Edx me envío el siguiente correo:
|
domingo, 11 de junio de 2017
Empezar con programación funcional en la plataforma Java
Como ustedes sabrán Java no es un lenguaje funcional y por más que le agreguemos clausuras, no deja de ser un lenguaje orientado objetos con clausuras. Y la plataforma java sigue esta premisa, por lo tanto podemos afirmar que es imposible la programación funcional pura en java, y esto es cierto. Pero tambien es cierto que se puede programar de modo funcional con un lenguaje funcional no puro.
Vamos desde el principio, que es la programación funcional? Si vemos la wikipedia :
"En ciencias de la computación, la programación funcional es un paradigma de programación declarativa basado en el uso de funciones matemáticas, en contraste con la programación imperativa, que enfatiza los cambios de estado mediante la mutación de variables. La programación funcional tiene sus raíces en el cálculo lambda, un sistema formal desarrollado en los años 1930 para investigar la definición de función, la aplicación de las funciones y la recursión. Muchos lenguajes de programación funcionales pueden ser vistos como elaboraciones del cálculo lambda.
En la práctica, la diferencia entre una función matemática y la noción de una "función" utilizada en la programación imperativa, es que las funciones imperativas pueden tener efectos secundarios, como cambiar el valor de cálculos realizados previamente. Por esta razón carecen de transparencia referencial, es decir, la misma expresión sintáctica puede resultar en valores diferentes en varios momentos de la ejecución del programa. Con código funcional, en contraste, el valor generado por una función depende exclusivamente de los argumentos alimentados a la función. Al eliminar los efectos secundarios se puede entender y predecir el comportamiento de un programa mucho más fácilmente. Ésta es una de las principales motivaciones para utilizar la programación funcional.
Los lenguajes de programación funcional, especialmente los puramente funcionales, han sido enfatizados en el ambiente académico y no tanto en el desarrollo comercial o industrial. Sin embargo, lenguajes de programación funcional como Scheme, Erlang, Rust, Objective Caml , Scala, F# y Haskell, han sido utilizados en aplicaciones comerciales e industriales por muchas organizaciones. La programación funcional también es utilizada en la industria a través de lenguajes de dominio específico como R (estadística), Mathematica (matemáticas simbólicas), J y K (análisis financiero)." https://es.wikipedia.org/wiki/Programaci%C3%B3n_funcional
Pero que mide la pureza de un lenguaje funcional? Un lenguaje funcional es puro respecto de la integridad referencial. No permite ningún efecto colateral. Probablemente, sea su característica más importante. Y volviendo a la plataforma java no podemos asegurar esto, porque esta plataforma nacio basada en un paradigma que mantiene estados. De igual manera existen lenguajes en la plataforma que nos permiten ser bastante puros como es el caso de los lenguajes basados en Haskell como Frege
y Jaskell.
Con respecto a los lenguajes la plataforma Java cuenta con varios lenguajes funcionales y con Java, si Java es un lenguaje de la plataforma Java y este como ya lo saben no es funcional. Es decir a partir de java 8 se pueden utilizar lambda, pero eso es solo una característica de la programación funcional, no hace a java funcional. De igual manera existen framework que suman azúcar sintáctico para programar en java de modo funcional :
Vamos desde el principio, que es la programación funcional? Si vemos la wikipedia :
"En ciencias de la computación, la programación funcional es un paradigma de programación declarativa basado en el uso de funciones matemáticas, en contraste con la programación imperativa, que enfatiza los cambios de estado mediante la mutación de variables. La programación funcional tiene sus raíces en el cálculo lambda, un sistema formal desarrollado en los años 1930 para investigar la definición de función, la aplicación de las funciones y la recursión. Muchos lenguajes de programación funcionales pueden ser vistos como elaboraciones del cálculo lambda.
En la práctica, la diferencia entre una función matemática y la noción de una "función" utilizada en la programación imperativa, es que las funciones imperativas pueden tener efectos secundarios, como cambiar el valor de cálculos realizados previamente. Por esta razón carecen de transparencia referencial, es decir, la misma expresión sintáctica puede resultar en valores diferentes en varios momentos de la ejecución del programa. Con código funcional, en contraste, el valor generado por una función depende exclusivamente de los argumentos alimentados a la función. Al eliminar los efectos secundarios se puede entender y predecir el comportamiento de un programa mucho más fácilmente. Ésta es una de las principales motivaciones para utilizar la programación funcional.
Los lenguajes de programación funcional, especialmente los puramente funcionales, han sido enfatizados en el ambiente académico y no tanto en el desarrollo comercial o industrial. Sin embargo, lenguajes de programación funcional como Scheme, Erlang, Rust, Objective Caml , Scala, F# y Haskell, han sido utilizados en aplicaciones comerciales e industriales por muchas organizaciones. La programación funcional también es utilizada en la industria a través de lenguajes de dominio específico como R (estadística), Mathematica (matemáticas simbólicas), J y K (análisis financiero)." https://es.wikipedia.org/wiki/Programaci%C3%B3n_funcional
Pero que mide la pureza de un lenguaje funcional? Un lenguaje funcional es puro respecto de la integridad referencial. No permite ningún efecto colateral. Probablemente, sea su característica más importante. Y volviendo a la plataforma java no podemos asegurar esto, porque esta plataforma nacio basada en un paradigma que mantiene estados. De igual manera existen lenguajes en la plataforma que nos permiten ser bastante puros como es el caso de los lenguajes basados en Haskell como Frege
y Jaskell.
Con respecto a los lenguajes la plataforma Java cuenta con varios lenguajes funcionales y con Java, si Java es un lenguaje de la plataforma Java y este como ya lo saben no es funcional. Es decir a partir de java 8 se pueden utilizar lambda, pero eso es solo una característica de la programación funcional, no hace a java funcional. De igual manera existen framework que suman azúcar sintáctico para programar en java de modo funcional :
- Functional Java
- Google guava
- LambdaJ
- Fun4J
- JCurry
- OCaml-Java
- Jambda
- Bolts
- Functional Java (swensen.functional)
Con respecto a los lenguajes, la plataforma java tiene varios lenguajes funcionales es su plataforma:
Y esto es simplemente para nombrar algunos porque varios lenguajes tienen características funcionales y corren en la plataforma de java, como por ejemplo Kotlin o Ceylon.
En conclusión java es una buena plataforma para programación funcional, si bien no se puede implementar la programación funcional pura a nivel de plataforma provee lenguajes muy puros como Frege o Jaskell. Lo que pasa es que tampoco es fácil hacer una plataforma multiparadigma en serio. Conocen una plataforma la cual pueda ejecutar lenguajes funcionales puros y orientados a objetos?
Suscribirse a:
Entradas (Atom)