Lingua Franca

may 12 2012

Este mes de mayo, el conocido y muchas veces criticado índice tiobe comenta que, tras 8 años, las posiciones en este índice de los lenguajes de programación no han sufrido demasiado altibajos, con excepciones notables como el “Objective C” empleado por el ecosistema Apple (iPhone/iPad/MacOS). Achaca esta inmovilidad a lo costoso de trasladar todo el código base que hemos acumulado de un lenguaje a otro, optando por mantenerse fiel a lenguaje que está utilizando.

Desde mi punto de vista, ésta no es una razón de peso hoy en día. Los distintos lenguajes de programación pueden compartir librerías sin demasiados problemas. Tecnologías como .Net o JVM facilitan bastante esta tarea, de modo que la mezcla de lenguajes es posible, sin obligar a elegir un único lenguaje al inicio de un desarrollo.

Pienso, por ejemplo, en todos los lenguajes de programación existentes para JVM (groovy, scala, clojure, jython, jruby,…). Todos ellos pueden usar las mismas librerías que usa java, aportando a su vez opciones con las que no cuenta java. Tal vez en esa proliferación de lenguajes alternativos se encuentre la explicación de porqué java ha perdido posiciones con respecto a C++. La evolución de Java se ha quedado algo estancada, tardando demasiado en incorporar características tan demandadas como las “clausuras” o tipos dinámicos que ofrecen los otros lenguajes.1

Porque es la evolución de los lenguajes de programación lo que realmente es interesante. No hace muchos años, creo que en la revista DrDobb’s, existía una sección fija dedicada al “lenguaje exótico del mes” que pretendía mostrar lenguajes más expresivos, muchos de dominio específico orientados a resolver problemas concretos, pero donde a veces se veían pequeñas joyas como el APL. Los lenguajes de uso habitual se consideraban limitados, y muchas veces la evolución en los algoritmos fallaba en el preciso momento de tener que codificarlo en un programa de ordenador. El lenguaje máquina dejó paso a otros modo de entenderse con la máquina.

Con el tiempo, cuando la programación se convirtió en ciencia, aparecieron los “paradigmas” y las “metodologías”. La programación se volvió bastante más abstracta y la ingeniería impuso sus reglas de eficiencia que terminó por relegar los lenguajes de programación a un segundo plano. La “expresividad” se conseguía ahora mediante herramientas CASE e IDEs inteligentes que imponían sus lenguajes de programación.

Estamos en una época que poco va a cambiar en cuanto a lenguajes, tal como afirma Tiobe. La razón de peso son las herramientas que usamos, que no las librerías. Los lenguajes más populares (los que aparecen en el índice tiobe) poseen un proceso evolutivo por el que adaptan los aciertos de los otros y se desprenden de lo obsoleto. No aumenta el número de lenguajes, pero las versiones de los lenguajes aumentan sin parar. Una estrategia evolutiva en el más amplio sentido que hace que los lenguajes se parezcan cada vez más entre sí, con formas muy similares para resolver los mismo problemas que llamamos “patrones de diseño” y concepciones similares.

¿El inicio de una “Lingua Franca”?


  1. En la literatura, se suele mencionar al lenguaje Scala como “lo que debería haber sido la evolución de Java”. 

No responses yet

Problemas con los nombres largos en NTFS

abr 04 2012

Un buen día comenté a un compañero de trabajo que en su carpeta compartida del servidor de ficheros pronto iba a tener problemas al usar nombres de carpetas demasiado largos. El explorador de ficheros ya se negaba a listas algunas carpetas y el problema iba a más con algunas herramientas (backups, antivirus,…).

La respuesta fue una pregunta: ¿Sería posible sacar un listado de todos los ficheros con ruta absoluta demasiado larga?

Después de dudar un rato (y comprobar que el comando dir no era válido para esta labor) , me decidí a averiguar si python sería capaza de realizar dicha tarea. Éste es el resultado de ése estudio.

Problema con los nombres largos

Resulta bastante chocante que la API de windows limite la máxima longitud para una ruta al valor de MAX_PATH, definido como 260 caracteres. Se trata únicamente de una limitación en la API, ya que el kernel de windows está preparado para manejar rutas muchísimo más largas. Como consecuencia, muchas aplicaciones fallan con rutas largas, desde los comandos de terminal hasta las utilidades gráficas del sistema.

Para evitar en parte este problema, podemos usar en nuestras aplicaciones las versiones unicode de las funciones ANSI de la API. Estas versiones unicode admiten como parámetros rutas de hasta 32.767 caracteres, suficientemente largas para un uso normal.

En en caso de la librería estándar de python, el módulo os.path (sinónimo de os.ntpath en windows) tiene buena cuenta de qué API invocar, según sea el caso. De un modo transparente, con sólo codificar las rutas en unicode evitaremos la limitación MAX_PATH en la longitud de las rutas.

Codificación de rutas extendida

Además de codificar las rutas en unicode, tenemos que indicar que se trata de una ruta extendida añadiendo el prefijo '\\?\' a una ruta absoluta. Por ejemplo, "\\?\D:\ruta\muy\muy\larga". Como gran limitación, no se puede usar esta nomenclatura con rutas relativas, por lo que las rutas relativas siempre estarán limitadas a MAX_PATH como máxima longitud.

Es posible, también, indicar una ruta UNC (Universal Naming Convention) como ruta extendida como \\?\server\share, donde server sería el nombre del servidor y share el nombre de la carpeta compartida.

Para más información sobre las rutas extendidas, visitar la página web Naming Files, Paths, and Namespaces de MSDN.

Script para listar ficheros de nombres muy largos

Por último, sólo queda lo más fácil: codificar el script ;-)

Es común que la codificación que lleva por defecto la cónsola de comandos falle con las cadenas unicode. Si pensamos sacar por cónsola los nombres de ficheros, lo recomendable es cambiar la codificación por una más apropiada, como la cp1252, lo más aproximado a utf-8 que podemos encontrar:

    C:\> chcp 1252

Para hacer nuestro script, podríamos haber usado cualquiera de las funciones os.walk de la librería estándar; pero, no sé porqué, fallan a crear la lista de directorios. Ésto nos obliga a crear nuestro propio método para recorrer la jerarquía de directorios.

Por comodidad, voy a lanzar el script en una máquina distinta de la que hace de servidor de ficheros ya que no dispongo de python en los servidores. Usaré la nomenclatura UNC para identificar los recursos compartidos.

#-*- coding: utf-8 -*-

import os

MAX_PATH=260

def longnames(dirpath):
    """Iterador que devuelve las rutas largas (>=MAX_PATH)"""
   
    #Hay que forzar unicode para evitar el límite MAX_PATH
    dirpath=unicode(dirpath)
    if not dirpath.endswith("\\"):
        dirpath+="\\"

    dirs=[]
   
    for f in os.listdir(dirpath):
       
        name = dirpath+f
       
        if len(name)>=MAX_PATH:
            yield name

        #poblar la lista de directorios
        #para recorrer en orden
        if os.path.isdir(name):
            dirs.append(name)

    for d in dirs:
        for f in longnames(d):
            yield f

def listshare(server, share):
    """Crea un UNC para el recurso compartido.
       Devuelve un iterador para las rutas largas (>=MAX_PATH)
    """
   
    dirpath=r"\\?\UNC\%s\%s"%(server, share)
    return longnames(dirpath)

Su uso simple podía ser:

#-*- coding: utf-8 -*-

import codecs

#PARÁMETROS
SERVER="MiServidor"
SHARE=r"Usuario\dir1"

fOut=codecs.open("longnames.txt", "w", encoding="utf-8")

for name in listshare(SERVER,SHARE):
   
    print name
    print >>fOut, name.replace(DIRPATH,".\\")
   
fOut.close()

No responses yet

Programación. ¿Ciencia o Ingeniería?

mar 09 2012

Cuando inicié este blog, además de servir de soporte a algunos artículos técnicos sobre programación que fueran más o menos novedosos, también me movió la idea de aportar reflexiones sobre algunos temas interdisciplinares que constantemente me hacía debido a mi formación científica y que he ido acumulando durante todos estos últimos años. Creo que es momento de empezar con ellos…

En busca de la materia gris

Todavía persiste el mito de considerar que un informático es una especie de chamán que con unos cuantos pases mágicos delante de una pantalla es capaz de hacer que un ordenador tome vida. Muy pocos asumen que un informático pueda tener una formación científica o técnica seria que se encuentre al mismo nivel que un médico o un ingeniero. Y así nos van las cosas.

No tomarse en serio la formación de un informático está llevando a que muchas empresas del sector no valoren suficientemente la destreza de sus empleados. Asumen que siempre podrán encontrar nuevos empleados a los que poder darles una pequeña formación suficiente para encargarse de cualquier proyecto que tengan en marcha. Si supieran un mínimo de ingeniería, sabrían que siempre hay un límite en todo proyecto en el que añadiendo más recursos nunca se consigue acelerar el desarrollo, si no más bien lo contrario. Momentos de dificultad que desemboca en una crisis1, donde prima más la experiencia que la cantidad de manos disponibles.

La actual crisis económica ha venido a agravar más el panorama al minusvalorar aún más a los profesionales de informática. Los buenos profesionales optan por emigrar a otros países donde sean mejor considerados, mientras que aquí las empresas compiten bajando más y más los precios, sin tener en consideración ni la calidad ni la idoneidad del producto que desarrollan.

Estamos inmersos entre sistemas informáticos y de telecomunicaciones que se están colapsando debido a malos diseños y falta de mantenimiento, con usuarios que asumen por normal que un sistema pueda fallar, que los virus puedan entrar hasta las entrañas del ordenador, o que un hacker pueda bloquear cualquier sistema gubernamental y robar identidades,… y lo único que importa a los responsables es que alguna empresa sin escrúpulos asuma la culpa por el menor precio posible.

El fin de la ley de Moore

Es sabido que por la Ley de Moore en estos 50 años pasados, se estaba cumpliendo que cada dos años los ordenadores doblaban su velocidad, mientras se hacían cada vez más y más baratos. Como consecuencia, las aplicaciones mal diseñadas aún se podían sobrellevar gracias a la reducción de costes y mejoras de velocidad que ofrecían los nuevos sistemas.

Lamentablemente, la ley de Moore llega a su final. Se intenta prorrogar su vigencia metiendo más cores en cada cpu, pero si bien se sigue contando con procesadores más baratos y más rápidos, un sistema multicore no es aprovechable por una aplicación mal diseñada. Para aprovechar una cpu multicore, se requiere de nuevas aplicaciones diseñadas específicamente para ellos. Hoy en día, muchos sistemas operativos sólo son capaces de aprovechar un core de todos los disponibles, lo que no deja de ser un engaño para el usuario que piensa que debería ir todo más rápido. Estamos muy cerca de una nueva crisis similar a la crisis del software, pero con hardware esta vez.

Es una burbuja que pronto va a estallar como tantas otras antes.

Poner en valor al programador

Hace tiempo que se perdió el significado de ser un “programador”. Con ese nombre se ha pasado a denominar un puesto técnico de trabajo que está por debajo de analista y un poco por encima de reparador de hardware. Nada que tenga qué ver con un trabajo metodológico y, en cierta medida, creativo.

Y, sin embargo, contar con buenos programadores debería ser parte del activo de una empresa que la ponga en valor. No es entendible que haya empresas que busquen programadores después de haberse comprometido con un proyecto de desarrollo. Debería ser más bien al revés, que para conseguir un proyecto se haya valorado antes qué programadores dispone la empresa en nómina.

Puedo asegurar que hay alguna empresa que cuenta con un núcleo de buenos programadores, normalmente gente joven que montan su propia empresa, que nunca les falta trabajo. Pero son mucho más numerosas las empresas vacías que se dedican a quemar sistemáticamente a toda su plantilla en proyectos difíciles de asumir sin la gente y los medios adecuados.

Contar con programadores experimentados no es tarea fácil. Toda empresa debería asegurar a sus programadores más valiosos, nunca deberían considerarlos inferiores a analistas, ya que asumen roles distintos. Un buen programador puede ser un pésimo analista y viceversa. Un buen programador debería estar bien pagado simplemente como programador, y no verse presionado para ser analista si quiere ascender y cobrar más.

Programación. ¿Ciencia o Ingeniería?

Según donde busques, la programación es parte de la Ciencia de la Computación o es parte de la Ingeniería del Software. Personalmente, me inclino más por que sea una ciencia. Un buen programador siempre intenta comprender el funcionamiento de un programa con el fin de crear nuevos y mejores programas. Usa un ciclo de análisis, desarrollo, prueba y refactorización que tanto se parece al “método científico”, experimentando hipótesis hasta dar con una solución. La ingeniería entraría cuando se requiere que la aplicación se ajuste a determinados requisitos, donde a veces no importa tanto la optimización del programa como el que se ajuste su funcionamiento a los parámetros requeridos.

¿Es posible buscar la belleza entre líneas de código? ¿Evolucionamos hacia mejores lenguajes de programación?

Temas para próximos artículos.

6 responses so far

Estudio función factorial en scala – Revisión funcional

feb 07 2012

Como programador de python que todavía anda algo despistado estudiando scala, ahora empiezo a captar la filosófía que hay detrás de este lenguaje de programación. Mientras que python empienza a erradicar poco a poco la programación funcional, en scala su influencia es cada vez mayor hasta el extremo de considerar precindibles la mayoría de los bucles. Aún asi, ambos lenguajes soportan la “compresión de listas” como técnica a medio camino entre funcional y bucle estándar, aunque esta técnica está más orientada a obtener listas a partir de otras listas, y no para realizar cálculos sobre un conjunto de números.

Voy a completar el anterior artículo que trataba del “Estudio función factorial en scala” con algunas formas más “funcionales” de definir el factorial:

La forma más simple de definir la función factorial:

def fact(n:Int) = (1 to n).product

En realidad, 1 to n no es un elemento sintáctico del lenguaje, si no más bien la forma alternativa de escribir la invocación del método 1.to(n). Este método nos genera una secuencia de números desde el 1 al n (equivalente en python a range(1,n+1)).

Curiosamente, también está definido fact(0) gracias a que product da como resultado el elemento neutro 1 en secuencias vacías 1.

Esta forma concisa de calcular el producto es común a todas las secuencias en scala. Faltaría, tan sólo, que operara con BigInts para que fuera perfecta:

def fact(n:Int) = (BigInt(1) to n).product

No es necesario indicar el tipo devuelto por la función puesto que el compilador es capaz de inferirlo de la expresión.

Otra forma funcional sería usando el método reduce, donde se indica explícitamente la operación binaria a realizar entre pares de elementos:

def fact(n:Int) = (BigInt(1) to n).reduce(_*_)

Como operación se pone una especie de plantilla (pattern) que representa la operación binaria de multiplicación. Por comparar, en python se puede hacer algo así:

from operator import __mul__

def fact(n):
   return reduce(__mul__, xrange(1,n+1))

Lamentablemente, el operador funcional 'reduce' está desapareciendo de python por considerarlo complejo de entender en su funcionamiento 2.

Por último, aún existe otra forma funcional de expresar el factorial en scala. Son los “plegados” (folds), similar en funcionamiento a reduce, pero con control sobre la dirección del recorrido y la posibilidad de dar un valor inicial:

def fact(n:Int) = (1 to n).foldLeft(BigInt(1))(_*_)

Seguro que pronto se me ocurrirán más formas.


  1. En el caso del método sum daría el elemento neutro para la suma, o sea, el 0

  2. Personalmente, considero que la desaparición de la programación funcional se debe más a la corta visión de quién sólo ve un encadenamiento de sentencias, en lugar de ver “actores” interaccionando en libre concurrencia. 

No responses yet

Codificando en binario

ene 26 2012

A raiz de la consulta de un colega, me ha llamado la atención el módulo binascii. Este módulo se encarga de la codificación y decodificación de cadenas binarias para su transmisión en mensajes de texto. Lo habitual es que sea usado por otros módulos como uu, base64 o binhex, por lo que no es nada frecuente ver su uso directo en una aplicación.

Sin embargo, binascii posee algunas funciones que pueden sernos bastante útiles a la hora de simplificar el empaquetado de datos que requieren determinadas APIs, en lugar de usar estructuras más complejas como array o struct. También se revela muy útil a la hora de crear batería de tests donde necesitemos chequear valores binarios.

Estructuras array y struct

Por ejemplo, imaginemos que nuestra API nos pide que empaquetemos un número entero como cuatro bytes. Antes de python3 no existía una forma para controlar el tamaño en bytes de un objeto sin tener que recurrir a alguna estructura especializada. Por ejemplo:

from array import array

def numpack(num):
    a=array('L')
    a.append(num)
    return a.tostring()[::-1]

n=numpack(0xffeeddcc)  # res: \xff\xee\xdd\xcc

En el resultado final ha hecho falta invertir el orden de los bytes debido a que nos estaba usando un orden “little-endian” para su codificación. El orden puede depender del sistema donde estemos trabajando, con lo que no es nada seguro usar este método. Es preferible el uso más especializado de struct donde tendremos algo más de control sobre éste y muchos otros aspectos:

from struct import pack

def numpack(num):
    return pack('!L', num)

n=numpack(0xffeeddcc)  # res: \xff\xee\xdd\xcc

Nota que en la cadena de formato que se pasa a pack() tiene un indicador '!' al principio, con el que indicamos que queremos una ordenación “network (=big-endian)”.

El proceso inverso es tan fácil como usar la función complementaria unpack:

unpack('!L', n)[0]

Codificando mensajes

Lo visto hasta ahora funciona bien cuando tenemos que interaccionar con una API que use tamaños fijos para los datos. Pero, ¿qué pasa cuando los datos son de longitud variable, por ejemplo, un mensaje largo de decenas de bytes? En el mejor de los casos, tendríamos que ir byte a byte, tal vez apoyándonos en array o struct para realizar las conversiones, algo a todas luces resulta bastante tedioso.

Como ya adelanté, el módulo binascii nos va a ayudar en este cometido, en concreto la función b2a_hex y su contraparte a2b_hex.

Por ejemplo, nos envían en un mensaje un entero codificado en multibyte. No sabemos si son 2, 4 u 8 bytes, o incluso podrían ser más bytes de tratarse de un BigInt (entero muy largo). Con binascii podríamos resolverlo así:

from binascii import b2a_hex, a2b_hex

num = int(b2a_hex(msg), 16)

Para el proceso contrario, codificar un entero en una cadena binaria, usaríamos a2b_hex:

h = "%x"%num
if len(h)%2 == 1:
    h = "0" + h

msg = a2b_hex(h)

Hemos tenido cuidado de que la cadena hexadecimal tenga longitud par ya que a2b_hex codifica siempre cada byte a partir de una pareja de dígitos hexadecimales.

Estudio codificaciones unicode

También es posible usar binascii para estudiar las codificaciones de cadenas unicode, lo que hace más sencillo crear tests automáticos para funciones que empleen unicode. Sin muchos adornos, haríamos algo así:

#-*- coding: utf-8 -*-

from binascii import b2a_hex, a2b_hex

cadena = u"Peón \N{BLACK CHESS PAWN}"

print b2a_hex(cadena.encode('utf-8'))

#res: 5065c3b36e20e2999f

Comparando el resultado obtenido con la cadena unicode, vemos que la ó acentuada se codifica en ‘utf-8′ como 0xc3b3, o que la figura de peón negro se codifica como 0xe2999f.

Si cambiamos la codificación por ‘utf-16′ obtenermos como resultado fffe50006500f3006e0020005f26. Además de ser más larga, vemos que se añade al principio fffe, que es lo que se denomina BOM, y que nos indica qué ordenación de bytes se ha usado en la codificación ('FEFF' para Big Endian / 'FFFE' para Little Endian). Con fffe nos indica concretamente que se ha usado la codificación ‘UTF-16 Little Endian’, con lo que tenemos los bytes invertidos para cada caracter codificado (ver más info en el artículo sobre BOM de la wikipedia).

De no desear que se nos añada la marca BOM, podríamos haber forzado la codificación mediante 'utf-16be' ó 'utf-16le' para Big Endian y Little Endian, respectivamente.

No responses yet

web2py, con pilas incluidas

dic 01 2011

He estado últimamente trabajando en varios proyectos que me han hecho descuidar un poco el blog. En próximos días espero publicar algunos artículos relacionados que creo serán de interés.

Lo último que estoy haciendo es un desarrollo de aplicación de escritorio con web2py, a pesar de tratarse de un framework para crear aplicaciones web. Corre desde un navegador cualquiera, interaccionando con [jQuery] para la presentación, y con python corriendo por debajo para dar soporte a la capas de datos y lógica de negocio.

¿Por qué web2py?

Como indico en el título, web2py lleva las “pilas incluidas”, que tratándose de python significa que incluye todo lo puedas necesitar. ¡Y no exagero! La selección de librerías que incluye es extensa, permitiendo desarrollar casi cualquier aplicación web que necesites, con herramientas administrativas tanto para el modelo de datos como para editar los ficheros vistas y controladores. Vamos, que con descomprimir el fichero con web2py y un navegador ya tienes todo lo necesario para desarrollar la aplicación, desde una simple aplicación estática, hasta una completa aplicación que funcione en el Google AppEngine. Además posee un sistema de plugins que permite cambiar fácilmente el diseño de la web o añadir funcionalidades.

Hasta ahora, había probado algunos GUIs graficos como pyqt o wxpython que incluyeran algún widget html para renderizar páginas webs y poder controlarlas desde el programa python, algo bastante costoso de programar y con serias incompatibilidades a la hora de presentar la página web. Con web2py, la aplicación de escritorio se orienta a una aplicación web con el servidor web corriendo directamente en el cliente. Web2py permite abstraer algunas facilidades ajax y jquery habituales, aunque no resulta difícil usar el resto de funcionalidades de jquery en las aplicaciones sin tener que ser un experto en programación javascript.

Uno de los problemas que también había tenido hasta ahora era en la distribución de aplicaciones python para windows. Habitualmente, hace falta instalar varias herramientas en el sistema, desde el intérprete python hasta todas las librerías necesarias, algunas complicadas de hacerlas funcionar. Bien es cierto que existen formas de empaquetar una aplicación usando py2exe (py2app en MacOS), pero casi siempre hay alguna cosa que no funciona bien del todo. Web2py viene con todo empaquetado para su uso en windows y macOS, incluyendo el intérprete python y resto de librerías necesarias. Basta descomprimir el fichero y, sin intalación, ejecutar el servidor web y abrir un navegador. Las aplicaciones web son carpetas que podemos copiar de una instalación a otra o, aún más sencillo, usar el interface administrativo para empaquetar e instalar aplicaciones (al estilo tomcat).

Échale un vistazo, y no te dejes las “pilas”.

One response so far

Estudio función factorial en scala

oct 17 2011

Como continuación al artículo que dediqué al estudio del factorial, voy a explicar cómo se haría este famoso algoritmo usando scala. Tengo que añadir que tan sólo llevo una semana con el lenguaje scala, por lo que es muy probable que haya algún aspecto de este lenguaje que me haya dejado por el camino.

Versión recursiva (y one-line)

La forma básica de la función sería:

def fact(n:Int):BigInt =
    if (n==0) 1
    else n*fact(n-1)

Si se compara con la función recursiva en python, no parece que haya mucha diferencia, con excepción de que en scala existe el tipado de datos.

Esta función es en realidad una sóla línea, por lo que podíamos haberla escrito de esta manera:

def fact(n:Int):BigInt = if (n==0) 1 else n*fact(n-1)

Es una clara señal de la orientación funcional que tiene scala.

Al igual que python, esta función recursiva se corta cuando se sobrepasa un cierto límite de llamadas recursivas para proteger la memoria del sistema.

El compilador de Scala posee una optimización especial denominda de “LLamada Terminal” (Tail Call)1 (optimización que no existe en JVM). Este tipo de optimizaciones son posibles cuando la última línea a ejecutar de la función es únicamente la llamada recursiva a sí misma, con lo cuál hace innecesario guardar el stack de ejecución puesto que no quedarían más líneas para ejecutar.

Para que sea posible aplicar esta optimización de “llamada terminal”, tenemos que reescribir nuestra función de modo que la última línea sea una llamada a sí misma. Para ello usaremos una función acumuladora que se encargue de realizar la multiplicación previamente a la llamada. Casi mejor si vemos el código:

def fact(n:Int):BigInt = {
    def factAcc(n:Int, acc:BigInt):BigInt =
        if (n<=1) acc else factAcc(n-1, n*acc)

    factAcc(n,1)
}

En las últimas versiones de scala existe una “anotación” especial para indicar al compilador de scala que intente aplicar la optimización de “LLamada Terminal”, o que nos dé un aviso de no poder hacerlo. Finalmente, así quedaría el código de nuestra función recursiva:

import scala.annotation.tailrec

def fact(n:Int):BigInt = {
    @tailrec
    def factAcc(n:Int, acc:BigInt):BigInt=
        if (n<=1) acc else factAcc(n-1, n*acc)

    factAcc(n,1)
}

Versión iterativa

Es la versión más sencilla:

def fact(n:Int):BigInt = {
    var res=BigInt(1)
    for (i <- 1 to n)
        res*=i
    res
}

Fórmula de Stirling

Para completar el estudio, podemos ver cómo sería la función de Stiling en Scala, bastante similar, como puede verse, a su versión en python:

import math._

def fact(n:Int):Double =
    sqrt(2*Pi*n)*pow(n/E,n)

  1. Existe algún intento para implementar esta optimización de “Tail Call” en python, con algunos decoradores más o menos funcionales. Si quieres ver motivos en contra, visita el artículo que escribió Guido sobre el tema: http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html 

One response so far

Rentrée (nueva temporada)

oct 08 2011

Desconectado de mis tareas habituales depués de algunas semanas viajando por Francia, veo que me quedaron varios proyectos y artículos en dique seco que pretendo recuperar. Con la “reentrada” (o, como dirían los franceses, “rentrée”) me he propuesto algunas metas para esta nueva temporada (por llamarla de algún modo) que ahora empiezo.

Junto a los artículos que tengo previstos, intentaré incorporar al blog más comentarios sobre temas técnicos que me vayan surgiendo en el día a día, preferiblemente relacionados con la programación. Sin llegar a la extensión de un artículo, espero que sirvan como gérmen de desarrollos posteriores más extensos.

Como primeras ideas para esta rentrée, he tomados dos decisiones: centrar mis desarrollos en la máquina virtual java (plataforma JVM) y aprender a programar con scala.

Máquina Virtual Java (JVM)

Hoy en día, la JVM está omnipresente para casi cualquier dispositivo y sistema operativo. Su uso empresarial es muy extendido, tanto para desarrollo en el lado servidor como para clientes móviles. Librerías y paquetes suficientemente robustos y probados completan una gran plataforma donde desarrollar cualquier tipo de aplicativo que podamos pensar.

Al evaluar la robustez de las librerías java, hay que tener en cuenta que java y su JVM están en constante evolución. El paso de Java5 a Java6 sido muy lento debido a las pocas ventajas que ofrecía el cambio frente al coste de tener que adaptar el código; pero con Java7 se incorpora a la máquina virtual el poder trabajar con tipos dinámicos de datos, lo que mejorará bastante el rendimiento de los lenguajes de scripting como jython, jruby ó groovy, por poner algunos ejemplos. Este cambio parece independizar el desarrollo de la JVM del lenguaje java para pasar a ser una plataforma común para la ejecución de aplicaciones, sea cual sea el lenguaje que se haya usado (objetivo similar a lo que tenía que haber sido .Net).

En lo personal, desde hace mucho tiempo que estoy programando en jython, tal como comenté en otro artículo. La llegada de los dispositivos android hace aún más interesante la programación para JVM, así como que las numerosas herramientas de software libre que estoy usando estén para esta plataforma. No quiero decir con ésto que renuncie a utilizar la CPython, la máquina virtual “nativa” que lleva python, siempre que sea necesario. Tan sólo priorizo la plataforma, JVM, frente a las últimas implementaciones del lenguaje python. Espero que el proyecto PyPy facilite un único camino para el desarrollo del lenguaje, independiente de la máquina virtual empleada.

Lenguaje Scala

Poco conozco de este lenguaje, la verdad. En el índice [tiobe] de septiembre de 2011 figura en la posición 50, la última posición que entra en valoración. Pero los comentarios que he leído sobre este lenguaje me han picado tanto la curiosidad que he decidido darle un vistazo. Si quieres un consejo: no te limites a un sólo lenguaje de programación. Sólo comparando con otros lenguajes descubrirás las virtudes y limitaciones de los lenguajes que uses. Sobre todo, intenta aprender algún lenguaje “exótico”, si por exótico se entiende aquél que no se ve en los estudios oficiales de informática. Siempre que te pidan mostrar tus conocimientos de programador, saber programar en un lenguaje “exótico” será visto como que te entusiasma la programación y que tienes capacidad para aprender cosas nuevas por tu cuenta (Python sigue siendo un excelente ejemplo de lenguaje para estas demostraciones).

Algunas características interesantes de Scala:

  • Lenguaje funcional orientado a objeto similar a java, pero superando a éste en simplicidad. Incorpora clausuras y tipado perezoso de datos.
  • Escalable (como indica su nombre: scalable language)
  • Emplea la JVM, aunque también hay versión para .Net. Puede usarse en cualquier sitio que se use java como, por ejemplo, para programación en android.
  • Preparado para la programación concurrente. Sigue el modelo “Actor”, o lo que es lo mismo, todos los objetos son “actores” con su propio entorno de ejecución.

Asociacionismo en torno a python

Tangencialmente, he empezado a meterme en la organización de un evento relacionado con python. Creo importante que todos retomemos los contactos personales e intentar hacer reflotar las ilusiones perdidas por esta crisis que estamos viviendo. Si todo va bien, espero vernos en el Día Python 2011 en Zaragoza dentro de la LSWC’11.

2 responses so far

Bitbucket soporta también git

oct 04 2011

Relacionado con el anterior artículo en el que contaba cómo usar mercurial para acceder a repositorios git, la noticia de hoy es que bitbucket soporta también git (además de mercurial). Unido a las herramientas para importar cualquier proyecto de github, SourceForge, Google Code y Codeplex convierten a bitbucket en el lugar ideal para alojar nuestros proyectos, usando cualquier DCVS que elijamos.

Noticia en el blog de bitbucket: http://blog.bitbucket.org/2011/10/03/bitbucket-now-rocks-git/

No responses yet

Mercurial como cliente DCVS universal

ago 30 2011

Introducción

Con la llegada de los DCVS (Distributed Concurrent Versions System), se ha convertido en habitual el uso de un sistema de control de versiones en todo desarrollo. La popularización de sitios webs basados en estos sistemas como github, gitorious, bitbucket o googlecode como foros públicos donde compartir código entre programadores hasta el punto de convertirse en auténticas redes sociales, ha hecho de estos sistemas una necesidad para todo desarrollador que se precio, con el consabido dilema de cuál de los sistemas elegir.

Gracias a las extensiones que podemos añadir, cada día es menos transcendente la elección de un DCVS, pudiendo usar cualquier cliente con cualquier otro servidor.

Comparando git y mercurial

Sin entrar en mucho detalle, podemos comparar estos dos sistemas DCVS populares para hacernos una idea:

git

  • Desarrollado en Depende de perl y está pensado para linux (mal soporte en windows)
  • Velocidad: muy rápido
  • Comandos: algo complejo
  • Interface gráfico: no tiene
  • Popularidad muy alta
  • Repositorio público estrella: github

mercurial (hg)

  • Desarrollado en python, con versiones para linux, windows y mac
  • Velocidad: rápido
  • Comandos: sencillo (similar a subversion)
  • Interface gráfico: tortoiseHG para gnome y windows
  • Popularidad alta
  • Repositorio público estrella: bitbucket

Éstos son algunos apuntes rápidos. Evidentemente, hay algunos interfaces gráficos para git y es posible emplear git en windows, pero en mi opinión tiene algunos problemas que necesitan pulirse. Por otro lado, existen varios IDEs como netbeans o eclipse que pueden usar cualquiera de estos DCVS, abstrayendo su uso interno a través de un interface común.

Para un programador de python, la elección debería ser clara: mercurial. Realizado en python y con numerosas extensiones, también desarrolladas en python, parece sin duda la mejor elección. Además, es el sistema de control de versiones más utilizado en proyectos python, incluyendo el desarrollo del lenguaje en si, por lo que se uso es casi obligado si queremos colaborar con otros desarrolladores python.

Pero no hace falta renunciar a nada: desde mercurial también se puede usar repositorios git o subversion. Basta con añadir la extensión adecuada.

En el resto del articulo, me centreré sólo en la extensión hg-git, con la que se posibilita el uso de repositorios git desde mercurial, sin necesidad de instalar ningún cliente de git adicional (no existen dependecias con ningún ejecutable git).

hg-git

Instalación

La última versión de mercurial a la hora de escribir este artículo es la 1.9. Como la versión “estable” de hg-git tiene problemas con esta versión en concreto de mercurial, voy a explicar aquí lo que sería el método manual de instalación, bastante más seguro.

Suponemos que tenemos ya instalado mercurial por lo medios habituales (autoinstalador en windows/instalador de paquetes en linux). Nos será de gran ayuda tener instalado tortoiseHG como interface gráfico para manejar los repositorios. Para windows, la instalación de tortoiseHG incluye todo lo necesario al empotrar un intérprete de python, mercurial y varias extensiones, algunas de ellas necesarias para transformar rutas y nombres de ficheros codificados en MBCS. Los siguientes pasos a ejecutar con mercurial serán más fáciles de aplicar desde la interface de tortoiseHG.

En el emplazamiento que queramos, empezamos por clonar un repositorio con hg-git desde mercurial:

$ hg clone http://bitbucket.org/durin42/hg-git hg-git

Normalmente, yo suelo usar un mismo directorio para agrupas todos los repositorios clonados. Ése podría ser el lugar adecuado para guardar este repositorio.

Añadimos esta extensión a la configuración de mercurial. Normalmente, se hace en el fichero mercurial.ini (windows) o en ~/.hgrc (linux). Si usamos tortoiseHG, desde las "opciones globales" podemos editar directamente este fichero.

Para añadir la extensión:

[extensions]
hggit = <ruta-al-repositorio>\hg-git\hggit

Como anotación, en alguna documentación se recomienda añadir también la extensión opcional bookmarks a la configuración; pero a partir de la versión 1.8 de mercurial, el comando bookmark es parte propia de los comandos de mercurial, por lo tanto este paso ya no es necesario.

Como dependencia, hace falta instalar el módulo de python dulwich para manejo de repositorios git con python. En windows ya viene incluído en tortoiseHG, por lo que no hay que hacer nada más. En linux, viene como paquete instalable (python-dulwich en ubuntu), pero también se podría haber instalado mediante easy_install sin mayor problema. Lo que sí hay que tener cuidado es en asegurarnos que no tenemos instalado el paquete python-git para que no interfiera con el módulo hg-git que estamos configurando.

Como lista final, estas serían las versiones probadas:

  • mercurial (hg) 1.9
  • hg-git 0.2.4
  • dulwich 0.6.1

Utilización

Con hg-git instalado ya podemos acceder, por ejemplo, a los repositorios de github directamente desde mercurial. Basta con especificar que se trata de un repositorio git:

$ hg clone git://github.com/django/django.git django.git

Para realizar un push a github con conexión codificada con SSH:

$ hg push git+ssh://user@github.com/user/myrep.git

Así mismo, si partimos de un repositorio mercurial también podemos “convertirlo” para su uso en git con el siguiente proceso:

$ cd myrep # (dentro del repositorio mercurial)
$ hg bookmark -r default master # marcamos 'default' como 'master'
$ hg push git+ssh://user@github.com/user/myrep.git
$ hg push

Al marcar con el nombre master a default facilitamos la conversión de los datos de mercurial a objetos git. Este proceso sólo es necesario hacerlo la primera vez.

github o bitbucket

En cuanto a elegir entre github o bitbucket, es más una cuestión de gustos. github se ha posicionado como el sistema predilecto para darse a conocer, sobre todo como referencia en los curriculo a la hora de solicitar empleo. En cambio, bitbucket permite el uso de repositorios privados, muy útil para pequeños grupos de trabajo y para colaboraciones en la “nube” (dispositivos móviles).

Ambos son gratuitos, por lo que no debes dejar de probarlos tan sólo por lo que haya podido decir aquí. Es una nueva forma de conocer y darse a conocer entre programadores, algo que sin duda hace de nuestro pequeño mundo algo mucho más grande.

8 responses so far

Older posts »