sábado, abril 14, 2007

En el radar

Próxima actualización en el radar: nueva entrega de Intuitive C#. Hay un nuevo capítulo sobre P.O.O. (el segundo), que no cuenta nada nuevo, pero lo que cuenta está más o menos bien escrito. O eso creo. Hay más información sobre reflexión, tipos de interfaz, genericidad, inferencia de tipos en llamadas a métodos genéricos, expresiones lambda (¡sí, las de C# 3.0!), qué es una restricción desnuda y cómo puede usarse para simular la covarianza en la asignación polimórfica de tipos genéricos, convirtiendo, por ejemplo, una lista de empleados en una lista de personas (y provocando una excepción cuando encuentre un abogado en ella)...
No, todavía no lo he subido a Internet. Ya avisaré, probablemente el lunes que viene.

Un comentario breve sobre C# 3.0: no me gusta la forma de "activar" los métodos de extensión. Esto ya lo tenía Delphi.NET 8.0: podías fingir que una clase ajena tenía métodos adicionales definiendo esos nuevos métodos como métodos estáticos cuyo primer parámetro tenga el tipo de la clase a extender. Así, Borland intentaba acercar el System.Object de .NET con el TObject délfico de siempre.
En Freya ya hay unas pocas extensiones predefinidas. Por ejemplo, hay dos extensiones que se expanden en línea: los "métodos" Sqr, que actúa sobre tipos numéricos, y Ord, que convierte caracteres en su valor numérico Unicode:
Console.WriteLine(2.Sqr);
El compilador genera código muy eficiente para Sqr: una instrucción de duplicación y la multiplicación. En una aplicación como XSight RT, donde hay que elevar expresiones complejas al cuadrado constantemente, no sólo queda más legible el código fuente, sino que además, se genera mejor código nativo, y el compilador JIT tiene menos carga y termina antes, al serle más sencillo identificar el patrón. Aparte de esto, se considera que todos los métodos estáticos de la clase System.Math se registran automáticamente como métodos de extensión. Así podemos escribir lo siguiente en Freya:
var L := (X.Sqr + Y.Sqr + Z.Sqr).Sqrt;
if (L - L0).Abs < epsilon then
// ...
Lo que no me gusta es la forma en que se "activan" los métodos de extensión en C#: basta con incluir el espacio de nombres en una cláusula using, para que todos los métodos de extensión de ese espacio de nombre entren en danza. Lo malo: un espacio de nombre es una entidad sin "chicha" en .NET. Pueden definirse tipos para un espacio de nombre en más de un ensamblado. De modo que al incluir el using, estamos activando todas extensiones, sin importar en qué ensamblado vengan. Además, la cláusula using ya tiene su propia función. Pueden surgir casos en los que nos interese el uso normal y no el extendido. Por supuesto, con mucho cuidado, no tendrían que surgir problemas... pero no deja de ser chapucero.

Etiquetas: , ,

7 Comments:

Blogger Alfredo Novoa said...

var L := (X.Sqr + Y.Sqr + Z.Sqr).Sqrt;
if (L - L0).Abs < epsilon then

¿Y cuál es el tipo de L?

A mi me gusta más algo así:

var L Real := Sqrt(X**2 + Y**2 + Z**2);

if Abs(L-L0) < epsilon then

O la alternativa:

var L Real := (X^2 + Y^2 + Z^2)^0.5;

martes, abril 17, 2007 12:51:00 p. m.  
Blogger Ian Marteens said...

¡! Es la inferencia de tipos. En este mundillo, el tipo de en el lado izquierdo no influye en la resolución de sobrecargas... aunque sólo en teoría: si miras los operadores de conversión del CLR, verás que pueden diferir sólo por el tipo de retorno. Y hay algunas violaciones al principio mencionado "de toda la vida".

Supongo que tienes algo en contra de este tipo sencillo de inferencia, pero no lo veo claro. A mí lo que no me gusta es la inferencia masiva en plan "Nemerle": es demasiado impredecible. Mira que el algoritmo de inferencia de tipos en llamadas genéricas tampoco es exhaustivo: se detiene donde podrían surgir ambigüedades.

(y sí, ya sé que la inferencia a lo bestia lo ha tenido la FP de toda la vida, desde siempre)

De todos modos, puedes darle un tipo explícito a la declaración:

var L: Real := ...

o si prefieres crear un bloque:

using L: Real := ... do
begin
end;

El using de Freya no exige que la expresión implemente IDisposable, porque eso pocas veces se sabe por adelantado.

No puedo usar ^ para las potencias: lo utilizo como sinónimo de xor. El problema es que el operador compuesto ^= se ve horrible escrito como xor= (y en .NET, no quería perderme la posibilidad de optimizar un poco con estos operadores). Además, aunque lo del xor conviviendo con el ^ no sea muy convincente, piensa entonces en shr y shl: quien no sea hablante nativo o casi nativo, no pilla enseguida si R es derecha o izquierda. Prefiero >> y <<. Y a partir de ahí, tirando del hilo, se llega al xor.

Lo que si puedo es probar a usar los dos asteriscos. La Sqrt como función global cuadra mejor en un híbrido: en realidad, el Sqr es una extrapolación del Ord. Eso (no tener funciones globales) es otra causa por la que hay asignaciones compuestas (que no son expresiones): no quería un Inc y y Dec, o un Include y Exclude.

martes, abril 17, 2007 2:25:00 p. m.  
Blogger Ian Marteens said...

... oye, por cierto, mencionaste el otro día el problema de cómo descargar un ensamblado cargado dinámicamente. ¿Conoces alguna solución? Voy a intentarlo cargando en un AppDomain separado, que creo que sí se puede descargar. El problema, claro, es que si primero compilo con Freya el proyecto A que usa B, y luego quiero hacer cambios en B, ya está cargado y no puedo modificarlo.

¿Conoces alguna técnica mejor?

martes, abril 17, 2007 2:27:00 p. m.  
Anonymous Anónimo said...

Nueva errata en el manual de ejercicios de la serie C, página 67, última linea, donde dice 'SourceID' debe decir 'SupplierID', ( por cierto la columna SourceID no existe )

martes, abril 17, 2007 3:38:00 p. m.  
Blogger Alfredo Novoa said...

Supongo que tienes algo en contra de este tipo sencillo de inferencia, pero no lo veo claro.

En contra tampoco, pero no le veo una utilidad muy clara. Habría que documentar muy bien el algoritmo de inferencia de tipos y aprendérselo de memoria para programar. Me parece mucha complejidad para no se cuál beneficio.

De todos modos, puedes darle un tipo explícito a la declaración:

var L: Real := ...

Si, aunque tengas inferencia de tipos esto sigue siendo necesario, por supuesto.

using L: Real := ... do
begin
end;

Yo uso with para estas cosas.

No puedo usar ^ para las potencias: lo utilizo como sinónimo de xor.

Ya, suele pasar. El ^ se suele usar mucho para el AND. Yo uso los dos asteriscos.

A lo mejor te interesa echarle un vistazo a este artículo sobre la notación:

Eric Hehner "From Boolean Algebra to Unified Algebra"

El problema es que muchos de los símbolos que usa son muy incómodos de escribir con un teclado, pero tiene ideas interesantes de todas formas.

La Sqrt como función global cuadra mejor en un híbrido:

¿A que llamas hibrido?

¿A un lenguaje que no sigue al pie de la letra la "religión" de los objetos? }:)

... oye, por cierto, mencionaste el otro día el problema de cómo descargar un ensamblado cargado dinámicamente. ¿Conoces alguna solución?

No usar ensamblados O:)

Usar métodos dinámicos que no necesitan ensamblados y los recicla el recolector de basura sin tener que hacer nada.

El problema es que no hay tipos dinámicos del estilo de los métodos :(

Voy a intentarlo cargando en un AppDomain separado, que creo que sí se puede descargar.


El problema es que para poder descargarlos estás obligado a hacer las llamadas entre AppDomains separados con lo que el rendimiento es penoso.

martes, abril 17, 2007 3:52:00 p. m.  
Blogger Ian Marteens said...

serie C, página 67, última linea,

Recibido y corregido. Gracias.

¿A que llamas hibrido? ¿A un lenguaje que no sigue al pie de la letra la "religión" de los objetos? }:)

Si sólo incumple el "mandamiento" para Sqrt, no sólo es híbrido: es chapucero. Si tuviese multiple dispatch o algo por el estilo, sería diferente.

He estado mirando, por cierto, un par de artículos sobre el tema, pero todavía veo el problema, no una solución. Y tampoco veo ahora una técnica sencilla para simplificar un "visitor". Tengo que hornearlo un poco más...

Otra cosa que he estado mirando, por inspiración de F#, es la posibilidad de abstraer un poco más la parte estructural de un tipo. La idea está muy verde: un lenguaje funcional utiliza mucho el pattern matching estructural. Pero mientras más sepas sobre la estructura de un tipo, es más posible que termines por cargarte el encapsulamiento. Las propiedades son una abstracción sobre el concepto de campo, ¿no podría seguir elevándose este nivel? ¿Hasta dónde?

Y he visto por ahí algún artículo sobre composición de iteradores anidados...

martes, abril 17, 2007 11:55:00 p. m.  
Blogger Alfredo Novoa said...

Si sólo incumple el "mandamiento" para Sqrt, no sólo es híbrido: es chapucero. Si tuviese multiple dispatch o algo por el estilo, sería diferente.

Híbrido no lo se, chapuza seguro. Pero si con un lenguaje no hay forma de expresar algo tan sencillo como una raiz cuadrada con una sintaxis decente eso dice muy poco a favor del lenguaje. En otras palabras, que al "mandamiento" ese habría que mandarlo a freir churros.

Uno de los muchos problemas (o de las pocas ventajas) de las religiones es que cada uno las puede interpretar como le de la gana.

He estado mirando, por cierto, un par de artículos sobre el tema, pero todavía veo el problema, no una solución. Y tampoco veo ahora una técnica sencilla para simplificar un "visitor".

Ya te decía que es un cambio muy profundo (quizás te valga para tu siguiente lenguaje :)

En la Web de Cecil hay varios artículos que lo explican bien.

Te pongo un ejemplo sencillote.

Imagínate que tienes árbol sintactico. Tienes un tipo unión (abstracto) que se llama Node y dos descendientes: Expression y Statement. Ahora quieres añadir un operador Analyze sin tocar los tipos.

Primero defines un operador abstracto para el tipo Node sin implementación e implementas otros para Statement y Expresion. Para que los operadores puedan acceder a la representación interna de los nodos usas algo como los friends de C++ pero que no tengas que tocar los tipos.

Ahora tienes que hacer esto para usarlos:

var N Node := Parse(myString);

Analyze(N);

Y yatá.

Mamá mamá, herencia sin puntitos :-)

miércoles, abril 18, 2007 1:46:00 p. m.  

Publicar un comentario

<< Home