miércoles, 30 de diciembre de 2020

Libros Gratuitos de Java Code Geeks

 

Download IT Guides!

 

Spring Integration for EAI

Spring Integration extends the Spring programming model to support the well-known Enterprise Integration Patterns. Enables lightweight messaging within Spring-based applications and...

 
 

Jetty Server Cookbook

The web server is used in products such as Apache ActiveMQ, Alfresco, Apache Geronimo, Apache Maven, Apache Spark, Google App Engine, Eclipse, FUSE, iDempiere, Twitter’s Streaming API and...

 
 

JAXB Tutorial

The first specification of JAXB was done in March 2003 and the work process is tracked in the Java Specification Request 31. In this specification request you can find a lot of...

 
 

JavaFX Programming Cookbook

JavaFX 2.0 and later is implemented as a native Java library, and applications using JavaFX are written in native Java code. JavaFX Script has been scrapped by Oracle, but development is...

 

sábado, 26 de diciembre de 2020

Feliz Navidad y buen año para todos!!


Como todos los años les deseo una feliz navidad y un buen 2021. 

Gracias por leerme! 

lunes, 21 de diciembre de 2020

Primeros pasos con Clojure, parte 11

Seguimos con Clojure... 

La wikipedia nos indica que : En matemáticas y en programación de computadoras, una función variadica o Variadic function es una función de aridad indefinida, es decir, una que acepta un número variable de argumentos. El soporte para funciones variadas difiere ampliamente entre los lenguajes de programación. El término variadic es un neologismo, que se remonta a 1936-1937. 

Hablando mal y pronto es como en java que ponemos los 3 puntos en los argumentos de la función, algo así : 

void printArgs(String... strings) {

        for (String string : strings) {

            System.out.println(string);

        }

    }

Entonces podemos pasarle un número n de argumentos : 

        printArgs("hello");                 // short for printArgs( ["hello"] )

        printArgs("hello", "world");        // short for printArgs( ["hello", "world"] )


En clojure, las funciones también pueden definir un número variable de parámetros. Los parámetros de las variables deben aparecer al final de la lista de parámetros. Se recopilarán en una secuencia para que los utilice la función.

El comienzo de los parámetros variables está marcado con &. Por ejemplo : 

(defn hello [greeting & who]

  (println greeting who))

Esta función toma un saludo de parámetro y un número variable de parámetros (0 o más) que se recopilarán en una lista denominada who. Podemos ver esto invocándolo con 3 argumentos:

user=> (hello "Hello" "world" "class")

Hello (world class)

Se puede ver que cuando println imprime who, se imprime como una lista de dos elementos que se recopilaron.


domingo, 20 de diciembre de 2020

Primeros pasos con Clojure, parte 10

 


Seguimos con Clojure... 

Las funciones se pueden definir para tomar diferentes números de parámetros. Funciona como el pattetn matching, veamos un ejemplo : 

(defn messenger

  ([]     (messenger "Hello world!"))

  ([msg]  (println msg)))


Esta función esta declarada 2 veces con 0 parámetros y 1 parámetro. La función de 0 parámetros llama a la función de 1 parámetro con un valor predeterminado para imprimir. Invocamos estas funciones pasando el número apropiado de argumentos:

user=> (messenger)

Hello world!

nil


user=> (messenger "Hello class!")

Hello class!

nil



sábado, 19 de diciembre de 2020

Primeros pasos con Clojure, parte 9

Seguimos con Clojure... 

Clojure es un lenguaje funcional. Las funciones son ciudadanos de primera clase y pueden pasarse por parámetros o devolverse desde otras funciones. La mayoría del código de Clojure consta principalmente de funciones puras (sin efectos secundarios), lo que quiere decir que si invocamos una función con las mismas entradas o parámetros, produce la misma salida.


defn define una función nombrada:

;;    name   params         body

;;    -----  ------  -------------------

(defn greet  [name]  (str "Hello, " name) )


Esta función tiene un solo parámetro, sin embargo, se puede incluir cualquier número de parámetros en el vector params.

Luego podemos llamar la función de esta manera :

user=> (greet "mundo")

"Hello, mundo"


miércoles, 16 de diciembre de 2020

Libros Gratuitos de Java code Geeks

 

Download IT Guides!

 

JDBC Tutorial

JDBC (Java Database Connectivity) is an API provided by Oracle that allows programmers to handle different databases from Java applications: it allows developers to establish connections...

 
 

JSF 2.0 Programming Cookbook

JavaServer Faces (JSF) is a Java specification for building component-based user interfaces for web applications. JSF 2 uses Facelets as its default templating system. Other view...

 
 

Developing Modern Applications with Scala

Scala is a general-purpose programming language. It has full support for functional programming and a very strong static type system. Designed to be concise, many of Scala's design...

 
 

iText Tutorial

Text provides support for most advanced PDF features such as PKI-based signatures, 40-bit and 128-bit encryption, color correction, Tagged PDF, PDF forms (AcroForms), PDF/X, color...

 

martes, 15 de diciembre de 2020

Primeros pasos con Clojure, parte 8


Seguimos con Clojure... 

Una de las cosas más comunes que se hace al aprender un lenguaje es imprimir valores. Clojure proporciona varias funciones para imprimir valores.

println y print traducirán los caracteres impresos especiales (como nuevas líneas y tabulaciones) a su forma impresa y omitirán las comillas en las cadenas. A menudo usamos println para depurar funciones o imprimir un valor en el REPL. println toma cualquier número de argumentos e interpone un espacio entre el valor impreso de cada argumento:

user=> (println "¿Qué es esto?" (+ 1 2))

¿Qué es esto? 3

nil

La función println tiene efectos secundarios (impresión) y devuelve nil como resultado.

Tengamos en cuenta que (println "¿Qué es esto?" (+ 1 2)) no imprimió las comillas circundantes y no es una cadena que el lector pueda volver a leer como datos.

Para ese propósito, podemos usar prn o pr para imprimir como datos:

user=> (prn "one\n\ttwo")

"one\n\ttwo"

nil

Dependiendo del contexto, es posible que prefieramos usar println o print o pr o prn.

lunes, 14 de diciembre de 2020

Primeros pasos con Clojure, parte 7


Seguimos con Clojure... 


Con def podemos guardar un valor en una variable pero ojo al piojo que en los lenguajes funcionales las variables no varían. Son constantes donde guardamos un valor, para utilizarlo más adelante o puede ser un pero eso es otro tema... Lo importante, es que en Clojure estamos lejos del concepto de mutabilidad. 

Para definir una variable podemos hacer: 

user=> (def x 6)

#'user/x

Y luego lo podemos usar : 

user=> (+ x x)
12

def es una forma especial que asocia un símbolo (x) en el espacio de nombres actual con un valor (6). Este enlace se llama var. En la mayoría del código Clojure actual, las vars deben referirse a un valor constante o una función, pero es común definirlas y redefinirlas por conveniencia cuando se trabaja en REPL.

Tengamos en cuenta que el valor de retorno anterior es #'user/x; esa es la representación literal de una var: #' seguida del símbolo de espacio de nombres, user es el espacio de nombres predeterminado.

Recuerde que los símbolos se evalúan buscando a qué se refieren, por lo que podemos recuperar el valor simplemente usando el símbolo, como vimos en el ultimo ejemplo. 




domingo, 13 de diciembre de 2020

Primeros pasos con Clojure, parte 6

 


Seguimos con Clojure... 

Antes de empezar a hablar del Relp de Clojure, tenemos que saber un aspecto importante del Relp es que Clojure siempre compila la expresión antes de ejecutarla; Clojure siempre se compila en bytecode de JVM. No hay intérprete de Clojure.

El Relp de Clojure esta recopado, trae como unos trucos, que nos hacen la vida más fácil. Por ejemplo, algunos símbolos especiales recuerdan los resultados de evaluar las últimas tres expresiones:

  • * 1 (el último resultado)
  • * 2 (el resultado hace dos expresiones)
  • * 3 (el resultado hace tres expresiones)
Veamoslo en acción : 

user=> (+ 3 4)
7
user=> (+ 10 *1)
17
user=> (+ *1 *2)
24

Podemos llamar al espacio de nombres clojure.repl que se incluye en la biblioteca estándar de Clojure que proporciona una serie de funciones útiles. Para cargar esa biblioteca y hacer que sus funciones estén disponibles en nuestro contexto actual, debemos escribir :

user=> (require '[clojure.repl :refer :all])
nil

Ahora tenemos acceso a algunas funciones adicionales que son útiles en REPL: doc, find-doc, apropos, source y dir.

La función doc muestra la documentación de cualquier función. Veamos un ejemplo :

user=> (doc +)
-------------------------
clojure.core/+
([] [x] [x y] [x y & more])
  Returns the sum of nums. (+) returns 0. Does not auto-promote
  longs, will throw on overflow. See also: +'
nil

La función doc imprime la documentación para +, incluidas las firmas válidas.

La función doc imprime la documentación, luego devuelve nil como resultado; verá ambos en la salida de evaluación.

También podemos invocar doc sobre sí mismo:

user=> (doc doc)

-------------------------

clojure.repl/doc

([name])

Macro

  Prints documentation for a var or special form given its name,

   or for a spec if given a keyword

nil

Si no estamos seguros de cómo se llama algo podemos usar el comando apropos para buscar funciones que coincidan con una cadena o expresión regular en particular.

user=> (apropos "+")
(clj-stacktrace.repl/pst+ clojure.core/+ clojure.core/+' clojure.core/read+string clojure.spec.alpha/+ clojure.spec.alpha/rep+impl net.cgrand.parsley.grammar/->Repeat+ net.cgrand.parsley.grammar/map->Repeat+ net.cgrand.regex/+ net.cgrand.regex.charset/+)

También puede ampliar la búsqueda para incluir las cadenas de documentos en sí mismas con find-doc:

user=> (find-doc "trim")
-------------------------
clojure.pprint/ltrim
([s c])
  Trim all instances of c from the beginning of sequence s
-------------------------
clojure.pprint/rtrim
([s c])
  Trim all instances of c from the end of sequence s
-------------------------
clj-stacktrace.core/parse-cause-exception
([causer-e caused-parsed-elems])
  Like parse-exception, but for causing exceptions. The returned map has all
  of the same keys as the map returned by parse-exception, and one added one:
  :trimmed-elems  A subset of :trace-elems representing the portion of the
                  top of the stacktrace not shared with that of the caused
                  exception.
-------------------------
clj-stacktrace.core/trim-redundant
([causer-parsed-elems caused-parsed-elems])
  Returns the portion of the tail of causer-elems that is not duplicated in
  the tail of caused-elems. This corresponds to the "...26 more" that you
  see at the bottom of regular trace dumps.
-------------------------
leiningen.core.utils/git-file-contents
([git-dir ref-path])
  Returns the (trimmed) contents by the given git path, or nil if it is
  inacessible or nonexisting. If it exists and is not readable, a warning is
  printed.
-------------------------
clojure.string/trim
([s])
  Removes whitespace from both ends of string.
-------------------------
clojure.string/trim-newline
([s])
  Removes all trailing newline \n or return \r characters from
  string.  Similar to Perl's chomp.
-------------------------
clojure.string/triml
([s])
  Removes whitespace from the left side of string.
-------------------------
clojure.string/trimr
([s])
  Removes whitespace from the right side of string.
-------------------------
clojure.core/read+string
([] [stream] [stream eof-error? eof-value] [stream eof-error? eof-value recursive?] [opts stream])
  Like read, and taking the same args. stream must be a LineNumberingPushbackReader.
  Returns a vector containing the object read and the (whitespace-trimmed) string read.
-------------------------
clojure.core/subvec
([v start] [v start end])
  Returns a persistent vector of the items in vector from
  start (inclusive) to end (exclusive).  If end is not supplied,
  defaults to (count vector). This operation is O(1) and very fast, as
  the resulting vector shares structure with the original and no
  trimming is done.
nil

Si desea ver lla lista completa de las funciones en un espacio de nombres en particular, puede usar la función dir. Aquí podemos usarlo en el espacio de nombres clojure.repl:

user=> (dir clojure.repl)
apropos
demunge
dir
dir-fn
doc
find-doc
pst
root-cause
set-break-handler!
source
source-fn
stack-element-str
thread-stopper
nil

Y finalmente, podemos ver no solo la documentación sino el código fuente subyacente de cualquier función accesible por el tiempo de ejecución:

user=> (source dir)
(defmacro dir
  "Prints a sorted directory of public vars in a namespace"
  [nsname]
  `(doseq [v# (dir-fn '~nsname)]
     (println v#)))
nil


Primeros pasos con Clojure, parte 5


Seguimos con Clojure... 

A veces es útil suspender la evaluación, en particular para símbolos y listas. A veces, un símbolo debería ser simplemente un símbolo sin buscar a qué se refiere:

user=> 'x

x

Y, a veces, una lista debería ser solo una lista de valores de datos (no un código para evaluar):

user=> '(1 2 3)

(1 2 3)

Un error confuso que puede suceder es el resultado de intentar evaluar accidentalmente una lista de datos como si fuera un código:

user=> (1 2 3)

Execution error (ClassCastException) at user/eval156 (REPL:1).

class java.lang.Long cannot be cast to class clojure.lang.IF

Esto porque nos olvidamos el ' 


Dejo link: https://clojure.org/guides/learn/syntax

Primeros pasos con Clojure, parte 4

Seguimos con cloujure...

Si sabes lisp, clojure es casi natural : 



Este diagrama se puede ver la diferencia entre la sintaxis en verde (la estructura de datos de Clojure producida por el Reader) y la semántica en azul (cómo el tiempo de ejecución de Clojure entiende esos datos).

La mayoría de las formas literales de Clojure se evalúan a sí mismas, excepto los símbolos y las listas. Los símbolos se utilizan para referirse a otra cosa y cuando se evalúan, devuelven a qué se refieren. Las listas (como en el diagrama) se evalúan como invocaciones.

En el diagrama, (+ 3 4) se lee como una lista que contiene el símbolo (+) y dos números (3 y 4). El primer elemento (donde se encuentra +) se puede llamar "posición de función", es decir, un lugar para encontrar la cosa a invocar. Si bien las funciones son algo obvio para invocar, también hay algunos operadores especiales conocidos para el tiempo de ejecución, macros y un puñado de otras cosas invocables.

Considerando la evaluación de la expresión anterior:

  • 3 y 4 se evalúan a sí mismos 
  • + evalúa a una función que implementa +
  • evaluar la lista invocará la función + con 3 y 4 como argumentos

Muchos lenguajes tienen tanto declaraciones como expresiones, donde las declaraciones tienen algún efecto con estado pero no devuelven un valor. En Clojure, todo es una expresión que se evalúa como un valor. Algunas expresiones (pero no la mayoría) también tienen efectos secundarios.

Dejo link: https://clojure.org/guides/learn/syntax

sábado, 12 de diciembre de 2020

Lambdas en Python


Las lambdas son funciones de una línea. También se conocen como funciones anónimas en algunos otros lenguajes. Se utilizan cuando necesitamos utilizar una función una única vez. 

En python tienen esta forma

lambda argument: manipulate(argument)

Veamos un ejemplo: 

add = lambda x, y: x + y

print(add(3, 5))

# Output: 8

Veamos lambda en acción : 

a = [(1, 2), (4, 1), (9, 10), (13, -3)]

a.sort(key=lambda x: x[1])

print(a)

# Output: [(13, -3), (4, 1), (1, 2), (9, 10)]

No solo lo podemos utilizar para ordenar, pero les dejo otra versión, esta vez en paralelo : 

data = zip(list1, list2)

data = sorted(data)

list1, list2 = map(lambda t: list(t), zip(*data))

miércoles, 9 de diciembre de 2020

Primeros pasos con Clojure, parte 3


Seguimos con Clojure...

Como funcióna o lee las expresiones Clojure? 

En Java, el código fuente (archivos .java) se lee como caracteres por el compilador (javac), que produce código de bytes (archivos .class) que la JVM puede cargar. Es decir un proceso tipico de compilación, se lee y compila el archivo fuente y produce bytecode que corre sobre la JVM. Sería algo así : 



En Clojure, se lee el código fuente como caracteres y esto se puede de leer desde un archivo  .clj o recibir una serie de expresiones de forma interactiva. El lector produce datos de Clojure. El compilador de Clojure luego produce el código de bytes para la JVM. Sería algo así : 


Hay dos puntos importantes:

  • La unidad del código fuente es una expresión Clojure, no un archivo fuente Clojure. Los archivos de origen se leen como una serie de expresiones, como si las hubiera escrito de forma interactiva en el REPL.
  • Separar el lector y el compilador es una separación clave que deja espacio para macros. Las macros son funciones especiales que toman código (como datos) y emiten código (como datos). 

martes, 8 de diciembre de 2020

Primeros pasos con Clojure parte 2


Seguimos con Clojure. 

Como la mayoría de los lenguajes Clojure tiene literales que son los valores que normalmente usamos. 

Ojo los ; son comentarios al final de la línea.

Tipos numéricos

42   ; entero

-1,5  ; punto flotante

22/7  ; fracción

Los enteros se leen como enteros de 64 bits de precisión fija cuando están dentro del rango y precisión arbitraria en caso contrario. Se puede usar una N al final para forzar una precisión arbitraria. Clojure también admite la sintaxis de Java para enteros octal (prefijo 0), hexadecimal (prefijo 0x) y radix arbitrario (prefijo con base y luego r).

Los valores de coma flotante se leen como flotantes de 64 bits de doble precisión o precisión arbitraria con un sufijo M. También se admite la notación exponencial. Los valores simbólicos especiales ## Inf, ## - Inf y ## NaN representan valores de infinito positivo, infinito negativo y "no es un número", respectivamente.

Tambien tenemos caracteres : 

"Hola"         ; String

\e                 ; caracter

# "[0-9] +"   ; expresión regular

Las cadenas están contenidas entre comillas dobles y pueden abarcar varias líneas. Los caracteres individuales se representan con una barra invertida al principio. Hay algunos caracteres especiales con nombre: \ newline \ spec \ tab, etc. Los caracteres Unicode se pueden representar con \ uNNNN o en octal con \ oNNN.

Las expresiones regulares literales son cadenas con un # al principio. Estos se compilan en objetos java.util.regex.Pattern.

Tambien tenemos símbolos e identifidores :

map                  ; símbolo

+                       ; símbolo 

clojure.core / + ; símbolo con espacio de nombres

nil                      ; valor nulo

true false           ; booleans

: alpha               ; palabra clave

:release/alpha   ; palabra clave con espacio de nombres

Los símbolos se componen de letras, números y otros signos de puntuación y se utilizan para referirse a otra cosa, como una función, valor, espacio de nombres, etc. Los símbolos pueden tener opcionalmente un espacio de nombres, separados por una barra inclinada del nombre.

Hay tres símbolos especiales que se leen como tipos diferentes: nil es el valor nulo y verdadero y falso son los valores booleanos.

Las palabras clave comienzan con dos puntos iniciales y siempre se evalúan por sí mismas. Se utilizan con frecuencia como valores enumerados o nombres de atributos en Clojure.

Otra cosa son las colecciones Clojure también incluye sintaxis literal para cuatro tipos de colección:

'(1 2 3); lista

[1 2 3]; vector

#{1 2 3}; conjunto

{:a 1,:b 2}; mapa

Hablaremos de colecciones más adelante, por ahora estuvo bien este post.

lunes, 7 de diciembre de 2020

Primeros pasos con Clojure


Cloujure es un lenguaje funcional de tipado dinamico que corre sobre la maquina virtual java y es muy similar a lisp. 

Antes de empezar vamos a instalarlo. Yo tengo instalado sdkman, por lo tanto voy a utilizarlo instalando Leiningen : 

sdk install leiningen

Y listo! Ahora vamos a probar el lenguaje: 

Primero vamos a hacer una prueba, una suma de 2 numeros, para eso en nuestra consola escribimos :

lein repl

Con esta linea corremos el repl de clojure con Leiningen (la primera vez demora un toque). Ahora a programar, escribimos : 

> (+ 5 6)
Y el resultado es 11

Vamos bien, probemos una función como count : 

> (count '(1 2 3 4))
4

Si esto funciona, el primer paso esta hecho. Dejo link: https://clojure.org/guides/getting_started


domingo, 6 de diciembre de 2020

Donde anda Clojure?



Clojure es un lenguaje de programación de propósito general dialecto de Lisp. Hace un énfasis especial en el paradigma funcional, con el objetivo de eliminar la complejidad asociada a la programación concurrente. Clojure puede ser ejecutado sobre la Máquina Virtual de Java. Por si no lo conocían. 

Hace mucho que no escribo sobre Clojure, por lo tanto estuve googleando a ver a donde anda... 

Y me encontré que su ecosistema ha crecido bastante, no muy rápido pero a paso seguro. 

Si no lo sabían, podemos crear nuestras aplicaciones Clojure en Leiningen que sería el maven de Clojure. 

A la vez podemos utilizar Datomic para guardar datos en la base de datos nosql, hecha en Clojure... 

Si les gusta Lisp, les va a encantar Clojure. 

Para empezar podemos utilizar un entorno online. Uno que esta bueno es jdoodle que se encuentra en : https://www.jdoodle.com/execute-clojure-online/

Veamos un pequeño ejemplito : 

(ns clojure.examples.hello

(:gen-class))


(defn sum-of-numbers [x y]

(println (format "x + y = %d" (+ x y))))


(sum-of-numbers 10 25)

Y esto retornará : x + y = 35


Dejo links : https://clojure.org/

https://www.datomic.com/

https://steemit.com/utopian-io/@laxam/programming-in-clojure-part-1-why-clojure

Tipos en Javascript

Javascript es un lenguaje de tipado dinamico, lo que no quiere decir que no tenga tipos. 

Encontre esta imagen en internet que muestra muy bien los tipos : 


Null es raro porque es primitivo y tambien es un objeto, para mi no se decidian. Pero salvo eso esta muy bien la imagen. 


sábado, 5 de diciembre de 2020

The 2020 State of the OCTOVERSE


Github libero su informe anual llamado "State of the OCTOVERSE" 

En este informe se puede encontrar cosas como, lenguajes más usados, de que parte del mundo se commitea más, cantidad de commits, etc... 

Ya hable de los lenguajes más utilizados en este post : https://emanuelpeg.blogspot.com/2020/12/top-10-de-los-lenguajes-de-programacion.html

Dejo link: https://octoverse.github.com/




Top 10 de los lenguajes de programación más populares en GitHub

 


Github liberó el resultado de una métrica que indica cual es el lenguaje más utilizado en su repositorio. Y el ganador por tercer año consecutivo es Javascript. 

El que sorprendió fue typescript, recuperándose de un 2019 no tan bondadoso. 

Y listo, no hay otras novedades...

jueves, 3 de diciembre de 2020

Distros Linux 2020


Mirando internet me encontre con un post de las mejores distros del 2020 y me gusto la lista, así que se las comparto : 

  1. Mint Cinnamon
  2. Ubuntu Budgie
  3. Deepin OS
  4. Ubuntu
  5. Manjaro
  6. Lubuntu
  7. Antergos
  8. Nitrux
  9. Elementary OS
  10. Zorin OS
  11. MX Linux

No sé si el orden es importante, pero personalmente pienso que esta buena, las 3 primeras distros las use y estan muuuyyy buenas. 

Sin más dejo link al post : 

https://computerhoy.com/listas/software/mejores-distribuciones-linux-2018-75139

Libros Gratuitos de Java Code Geeks

 

Download IT Guides!

 

Advanced Java Tutorial

Learning the basics of Java is easy. But really delving into the language and studying its more advanced concepts and nuances is what will make you a great Java developer. The web is...

 
 

Amazon AWS Lambda Tutorial

AWS Lambda is an event-driven, serverless computing platform provided by Amazon as a part of the Amazon Web Services. It is a computing service that runs code in response to events and...

 
 

JPA Tutorial - Ultimate Guide

The Java Persistence API (JPA) is a vendor independent specification for mapping Java objects to the tables of relational databases. Implementations of this specification allow...

 
 

Apache ActiveMQ Cookbook

Apache ActiveMQ is an open source message broker written in Java together with a full Java Message Service (JMS) client. It provides “Enterprise Features” which means fostering the...

 

Functional Programming in Haskell: Supercharge Your Coding


Los que siguen el blog, notaron varios post de haskell medio seguidos, todo esto es gracias a un curso de futurelearn que les quiero recomendar, el nombre es : Functional Programming in Haskell: Supercharge Your Coding. 

Es gratuito y esta realizado por la universidad de Glasgow. 

Entre los capitulos tenemos, teoría, entrevistas, casos prácticos, etc... 

Dejo link: https://www.futurelearn.com/courses/functional-programming-haskell

domingo, 29 de noviembre de 2020

Secuencia en Kotlin parte 2


Seguimos con las secuencias en Kotlin. 

Las operaciones de secuencia se pueden clasificar en los siguientes grupos con respecto a sus requisitos de estados:

  • Operaciones sin estado no requieren ningún estado y procesan cada elemento de forma independiente, por ejemplo, map () o filter (). Las operaciones sin estado también pueden requerir una pequeña cantidad constante de estado para procesar un elemento, por ejemplo, take () o drop ().
  • Operaciones con estado requieren una cantidad significativa de estado, generalmente proporcional al número de elementos en una secuencia.

Si una operación de secuencia devuelve otra secuencia, que se produce de forma perezosa, se llama intermedia. De lo contrario, la operación es terminal. Ejemplos de operaciones de terminal son toList () o sum (). Los elementos de secuencia se pueden recuperar solo con operaciones de terminal.

Las secuencias se pueden iterar varias veces; sin embargo, algunas implementaciones de secuencia pueden limitarse a repetirse una sola vez. Eso se menciona específicamente en su documentación.

Echemos un vistazo a la diferencia entre Iterable y Sequence con un ejemplo.

Suponga que tiene una lista de palabras. El siguiente código filtra las palabras de más de tres caracteres e imprime la longitud de las primeras cuatro palabras.

val words = "The quick brown fox jumps over the lazy dog".split(" ")

val lengthsList = words.filter { println("filter: $it"); it.length > 3 }

    .map { println("length: ${it.length}"); it.length }

    .take(4)

println("Lengths of first 4 words longer than 3 chars:")

println(lengthsList)

Cuando ejecute este código, verá que las funciones filter () y map () se ejecutan en el mismo orden en que aparecen en el código. Primero, verá filter: para todos los elementos, luego length: para los elementos que quedan después de filtrar, y luego la salida de las dos últimas líneas. Así es como va el procesamiento de la lista:

Ahora escribamos lo mismo con las secuencias:

val words = "The quick brown fox jumps over the lazy dog".split(" ")

//convert the List to a Sequence

val wordsSequence = words.asSequence()

val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }

    .map { println("length: ${it.length}"); it.length }

    .take(4)

println("Lengths of first 4 words longer than 3 chars")

// terminal operation: obtaining the result as a List

println(lengthsSequence.toList())

La salida de este código muestra que las funciones filter () y map () se llaman solo cuando se genera la lista de resultados. Entonces, primero verá la línea de texto “Longitudes de ..” y luego se iniciará el procesamiento de la secuencia. Para los elementos que quedan después del filtrado, el mapa se ejecuta antes de filtrar el siguiente elemento. Cuando el tamaño del resultado llega a 4, el procesamiento se detiene porque es el tamaño más grande posible es 4 por ".take(4)"


Función Open de Python


Open abre un archivo. Bastante simple, ¿eh? La mayoría de las veces, vemos que se usa así:

f = open('photo.jpg', 'r+')

jpgdata = f.read()

f.close()

El valor de retorno de open es un identificador de archivo, dado desde el sistema operativo. 

Llamar explícitamente a close cierra el archivo, pero solo si la lectura fue exitosa. Si hay algún error justo después de f = open (...), no se llamará a f.close (). Para asegurarse de que el archivo se cierre ya sea que ocurra una excepción o no, podemos usar with:

with open('photo.jpg', 'r+') as f:

    jpgdata = f.read()

El primer argumento de abrir es el nombre del archivo. El segundo (el modo) determina cómo se abre el archivo.

Si desea leer el archivo, pase r

Si desea leer y escribir el archivo, pase r +

Si desea sobrescribir el archivo, pase w

Si desea agregar al archivo, pase a

El modo es importante no solo porque cambia el comportamiento, sino también porque puede resultar en errores de permisos. Por ejemplo, si abriéramos un archivo jpg en un directorio protegido contra escritura, abrir (.., 'r +') fallaría. El modo puede contener un carácter más; podemos abrir el archivo en binario (obtendrás una cadena de bytes) o en modo texto (una cadena de caracteres).

En general, si el formato está escrito por humanos, suele ser en modo texto. Los archivos de imagen jpg generalmente no están escritos por humanos (y de hecho no son legibles por humanos) y, por lo tanto, debe abrirlos en modo binario agregando ab a la cadena de modo (si está siguiendo el ejemplo de apertura, el modo correcto sería rb). Si abre algo en modo texto (es decir, agrega una t, o nada aparte de r / r + / w / a), también debe saber qué codificación usar. Para una computadora, todos los archivos son solo bytes, no caracteres.

Desafortunadamente, open no permite la especificación de codificación explícita en Python 2.x. Sin embargo, la función io.open está disponible tanto en Python 2.x y 3.x (donde es un alias de open) y hace lo correcto. Puede pasar la codificación con la palabra clave de codificación. Si no pasa ninguna codificación, se elegirá un sistema (y Python) predeterminado específico. Puede tener la tentación de confiar en estos valores predeterminados, pero los valores predeterminados a menudo son incorrectos o la codificación predeterminada no puede expresar todos los caracteres en el archivo (esto sucederá a menudo en Python 2.x y/o Windows). Así que adelante, elija una codificación. La codificación es la forma de instruir a las computadoras sobre cómo se deben almacenar los números como bytes en la memoria. utf-8 es excelente y es compatible con los principales navegadores y lenguajes de programación. Cuando escribe un archivo, puede elegir la codificación a su gusto (o al gusto del programa que eventualmente leerá su archivo).

¿Cómo averigua en qué codificación se escribió un archivo que está leyendo? Bueno, desafortunadamente, no existe una forma infalible de detectar la codificación: los mismos bytes pueden representar caracteres diferentes pero igualmente válidos en diferentes codificaciones. Por lo tanto, debe confiar en los metadatos (por ejemplo, en los encabezados HTTP) para conocer la codificación. Cada vez más, los formatos solo definen la codificación como UTF-8.

Armados con este conocimiento, escribamos un programa que lea un archivo, determine si es JPG (pista: estos archivos comienzan con los bytes FF D8) y escriba un archivo de texto que describa el archivo de entrada.

import io

with open('photo.jpg', 'rb') as inf:

    jpgdata = inf.read()


if jpgdata.startswith(b'\xff\xd8'):

    text = u'This is a JPEG file (%d bytes long)\n'

else:

    text = u'This is a random file (%d bytes long)\n'


with io.open('summary.txt', 'w', encoding='utf-8') as outf:

    outf.write(text % len(jpgdata))


Y listo!

sábado, 28 de noviembre de 2020

Manejo de errores en Go vs Rust parte 3

Seguimos viendo el manejo de errores en Go y Rust.

En Go, Panic es una función incorporada que detiene el flujo ordinario de control y comienza a entrar en pánico. Cuando la función F llama a Panic, la ejecución de F se detiene, cualquier función diferida en F se ejecuta normalmente y luego F vuelve a su llamador. El proceso continúa en la pila hasta que todas las funciones de la goroutine actual han regresado, momento en el que el programa se bloquea. Los pánicos se pueden iniciar invocando el Panic directamente. También pueden deberse a errores en tiempo de ejecución.

Rust tambien tiene panic! pero en este caso en una macro, cuando panic! se ejecuta, el programa imprimirá un mensaje de error y limpiará la pila y luego se cerrará. Esto ocurre más comúnmente cuando se detecta un error de algún tipo y el programa no tiene claro cómo manejar el error.

Veamos un ejemplo para ver cómo es cuando se ejecuta panic!: 

fn main() {

    let v = vec![1, 2, 3];

    v[99];

}

Aquí, estamos intentando acceder al elemento en la posición 100 de nuestro vector (que está en el índice 99 porque la indexación comienza en cero), pero solo tiene 3 elementos. En esta situación, Rust entrará en pánico. Se supone que el uso de [] devuelve un elemento, pero si pasa un índice no válido, no hay ningún elemento que Rust pueda devolver aquí que sea correcto.

En C, intentar leer más allá del final de una estructura de datos es un comportamiento indefinido. Puede obtener lo que esté en la ubicación de la memoria que corresponda a ese elemento en la estructura de datos, aunque la memoria no pertenezca a esa estructura. Esto se denomina sobrelectura del búfer y puede generar vulnerabilidades de seguridad si un atacante es capaz de manipular el índice de tal manera que lea datos que no deberían tener permitido y que se almacenan después de la estructura de datos.

Para proteger el programa de este tipo de vulnerabilidad, si intenta leer un elemento en un índice que no existe, Rust detendrá la ejecución y se negará a continuar. Probémoslo y veamos:

$ cargo run

   Compiling panic v0.1.0 (file:///projects/panic)

    Finished dev [unoptimized + debuginfo] target(s) in 0.27s

     Running `target/debug/panic`

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2806:10

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.


Este error apunta a un archivo que no escribimos, libcore / slice / mod.rs. Esa es la implementación de slice en el código fuente de Rust. El código que se ejecuta cuando usamos [] en nuestro vector v está en libcore / slice / mod.rs, ¡y ahí es donde entra el pánico! 

La siguiente línea de nota nos dice que podemos configurar la variable de entorno RUST_BACKTRACE para obtener un seguimiento de lo que sucedió exactamente. Un backtrace es una lista de todas las funciones que se han llamado para llegar a este punto. Los backtraces en Rust funcionan como lo hacen en otros lenguajes: la clave para leer el backtrace es comenzar desde arriba y leer hasta que veas los archivos que escribiste. Ese es el lugar donde se originó el problema. Veamos un ejemplo : 

$ RUST_BACKTRACE=1 cargo run
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2806:10
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:84
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:61
   4: core::fmt::ArgumentV1::show_usize
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1426
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:65
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:50
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:193
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:210
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:471
  11: rust_begin_unwind
             at src/libstd/panicking.rs:375
  12: core::panicking::panic_fmt
             at src/libcore/panicking.rs:84
  13: core::panicking::panic_bounds_check
             at src/libcore/panicking.rs:62
  14: <usize as core::slice::SliceIndex<[T]>>::index
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2806
  15: core::slice::<impl core::ops::index::Index<I> for [T]>::index
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2657
  16: <alloc::vec::Vec<T> as core::ops::index::Index<I>>::index
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/liballoc/vec.rs:1871
  17: panic::main
             at src/main.rs:4
  18: std::rt::lang_start::{{closure}}
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67
  19: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:52
  20: std::panicking::try::do_call
             at src/libstd/panicking.rs:292
  21: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:78
  22: std::panicking::try
             at src/libstd/panicking.rs:270
  23: std::panic::catch_unwind
             at src/libstd/panic.rs:394
  24: std::rt::lang_start_internal
             at src/libstd/rt.rs:51
  25: std::rt::lang_start
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67
  26: panic::main

En Go, Recover es una función incorporada que recupera el control de una goroutine en pánico. Recuperar solo es útil dentro de funciones diferidas. Durante la ejecución normal, una llamada para recuperar devolverá cero y no tendrá ningún otro efecto. Si la goroutine actual entra en pánico, una llamada para recuperar capturará el valor dado al pánico y reanudará la ejecución normal.

Aquí hay un programa de ejemplo que demuestra la mecánica del panic y el defer:

package main

import "fmt"


func main() {

    f()

    fmt.Println("Returned normally from f.")

}


func f() {

    defer func() {

        if r := recover(); r != nil {

            fmt.Println("Recovered in f", r)

        }

    }()

    fmt.Println("Calling g.")

    g(0)

    fmt.Println("Returned normally from g.")

}


func g(i int) {

    if i > 3 {

        fmt.Println("Panicking!")

        panic(fmt.Sprintf("%v", i))

    }

    defer fmt.Println("Defer in g", i)

    fmt.Println("Printing in g", i)

    g(i + 1)

}

La función g toma el int i, y entra en pánico si i es mayor que 3, o se llama a sí misma con el argumento i + 1. La función f difiere una función que llama a recuperar e imprime el valor recuperado (si no es nulo). Esto da como resultado: 

Calling g.

Printing in g 0

Printing in g 1

Printing in g 2

Printing in g 3

Panicking!

Defer in g 3

Defer in g 2

Defer in g 1

Defer in g 0

Recovered in f 4

Returned normally from f.


Si eliminamos la función diferida de f, el pánico no se recupera y alcanza la parte superior de la pila de llamadas de goroutine, terminando el programa. Este programa modificado generará:


Calling g.

Printing in g 0

Printing in g 1

Printing in g 2

Printing in g 3

Panicking!

Defer in g 3

Defer in g 2

Defer in g 1

Defer in g 0

panic: 4

panic PC=0x2a9cd8

[stack trace omitted]

La convención en las bibliotecas de Go es que incluso cuando un paquete usa panic internamente, su API externa aún presenta valores de retorno de error explícitos.