Archivo: Categoría 'Vicente - Jad Engine Blog'


Developing a flexible RPG Library in .NET 4.0 – The Expression Parser

[ Blog: Vicente - Jad Engine Blog ]
2010:04:23 17:00:00

(disclaimer: this post has some repeated content from a spanish post from last year)

One of my “playtest” projects is developing a small library to implement RPG games, based on the Dungeons and Dragons toolset, most specifically in the d20 System. I’ve been working on it on my free time for the last year, but I have been swamped with lots of things and I haven’t advanced as much as I would like. But nevertheless, I have the core more or less complete from my point of view and the library it’s capable of doing some pretty cool things right now, so my idea is to explain it in detail on the next several posts.

I wanted this library to be data-driven, so I could define most information (weapons, spells, armors,…) in text/xml files and the library would read them at startup to get all the information it would need. That’s great for the future, but in short term it gave me some pretty big headaches, and probably the first one was the parsing of mathematical expressions.

When I was designing how the system would work, I decided that objects would have a list of “modifiers”: expressions that change the value of another object variables. An easy example: a Chain Mail is an item that modifiers the Armor Class of the player that has it equipped. I could claim this idea is mine, but I got it from a spectacular piece of software called PCGen (a character generator for the d20 System).

Let’s imagine an example XML representation for the Chain Mail:

<Armor Name="Chain Mail">
  <Modifiers>
    <Modifier Attribute="Armor Class" Value="+5"/>
  </Modifiers>
</Armor>

The first problem I need to solve was: how I transform that “+5” into a number? In this case, it’s simple, I could just do:

public int Parse(string value)
{
    int result;
    if (int.TryParse(value, out result))
    {
        return result;
    }
 
    throw new ArgumentException(string.Format("value \"{0}\" is not a valid number", value));
}

That works, but this is a very simple case. Let’s imagine now the spell “Energy Drain”, which gives a creature 2d4 negative levels. The XML could be:

<Spell Name="Energy Drain">
  <Modifiers>
    <Modifier Attribute="Level" Value="-2d4"/>
  </Modifiers>
</Spell>

Now, things have got much harder for two reasons:

  • First: I need to be able to parse the expression in several parts, the minus symbol, the 2, the “d” and the 4.
  • Second: parsing this expression shouldn’t produce a number, but a method!

There are even harder examples. Let’s think again about another spell, “Cure Light Wounds”, which heals a creature 1d8 hit points plus 1 hit point per caster level. The XML:

<Spell Name="Cure Light Wounds">
  <Modifiers>
    <Modifier Attribute="Hit Points" Value="1d8 + CasterLevel"/>
  </Modifiers>
</Spell>

Nearly no other example gets harder than this in the d20 System: I have to combine (+) two mathematical expressions (1d8, CasterLevel), one which is a weird thing (1d8) and the other one is the value of an object (CasterLevel).

To solve this, I approached the problem in small steps. First, I transformed the expression into a list of tokens. My first simple approach was to rely on string.Split using spaces as separator, but honestly “1 d 8” looks horrible. So I implemented the following grammar (I think it’s in right BNF, but could be it’s not) and wrote a small parser for it.

Grammar

 

If you read the grammar and write some examples, you will realize it doesn’t handle parenthesis right, but I do not care about it much as the next step will control that case. The next step is to transform the list of tokens into something I can evaluate. For example, I may have the tokens: Number (5.0), Operator (+), Number (3.3), and I want some way to evaluate that to 8.8. This involves two steps.

First, “5.0 + 3.3” is a mathematical expression in infix notation, which is great for humans to read but a pain to evaluate. It’s far easier for a computer to evaluate mathematical expressions in postfix notation “5.0 3.3 +” (if you have used old HP calculators, you may have seen it there). There are several nice things about this step:

  • There is a very simple algorithm that transform infix to postfix expressions: Shunting-Yard (invented by Dijkstra).
  • Postfix expressions do not need parenthesis, so if the parenthesis are right the expression will transform using Shunting-Yard and if they aren’t the tranformation will detect it and throw an error.

Now that the expression is in postfix notation, the second step is to evaluate it to produce the expected result: 8.8. The postfix evaluation algorithm is pretty easy too. But while we can evaluate “5.0 3.3 +”, we can’t evaluate “5.0 Character.CasterLevel +”. That’s why our evaluator has to produce a method instead of a number. This may seem hard, but if you read the Shunting-Yard explanation it says:

It can be used to produce output in Reverse Polish notation (RPN) or as an abstract syntax tree (AST).

.NET 3.5 added support to create ASTs! That’s what the Expression Trees feature is all about (it was designed for Linq To SQL, but it helps us here). So, instead of evaluating the expression, what I do is to modify the evaluation algorithm to generate a tree that represents the expression, like this:

private static Expression<Func<CalculationHelper, double>> ToExpressionTree(IEnumerable<Token> tokens)
{
    Stack<Expression> operands = new Stack<Expression>();
    ParameterExpression parameter = Expression.Parameter(typeof(CalculationHelper), "calculator");
 
    Expression op1, op2;
    foreach (Token token in tokens)
    {
        switch (token.TokenType)
        {
            case TokenType.Number:
                {
                    operands.Push(Expression.Constant(((NumberToken)token).Value, typeof(double)));
                    break;
                }
 
            case TokenType.Variable:
                {
                    VariableToken variable = (VariableToken)token;
                    operands.Push(Expression.Call(parameter, "SolveDependency", null, Expression.Constant((variable.Category), typeof(string)), Expression.Constant((variable.Attribute), typeof(string))));
                    break;
                }
 
            case TokenType.Dice:
                {
                    DiceToken dice = (DiceToken)token;
                    operands.Push(Expression.Call(typeof(Dice), "Roll", null, Expression.Constant(dice.Number, typeof(int)), Expression.Constant(dice.Size, typeof(int))));
                    break;
                }
 
            case TokenType.Operator:
                {
                    OperatorToken operatorToken = token as OperatorToken;
 
                    op2 = operands.Pop();
                    op1 = operands.Pop();
 
                    switch (operatorToken.OperatorType)
                    {
                        case OperatorType.Add:
                            {
                                operands.Push(Expression.Add(op1, op2));
                                break;
                            }
 
                        case OperatorType.Subtract:
                            {
                                operands.Push(Expression.Subtract(op1, op2));
                                break;
                            }
 
                        case OperatorType.Multiply:
                            {
                                operands.Push(Expression.Multiply(op1, op2));
                                break;
                            }
 
                        case OperatorType.Divide:
                            {
                                operands.Push(Expression.Divide(op1, op2));
                                break;
                            }
 
                        case OperatorType.Power:
                            {
                                operands.Push(Expression.Power(op1, op2));
                                break;
                            }
                    }
 
                    break;
                }
 
            default:
                {
                    throw new ArgumentException(string.Format("An undefined token ({0}) appeared while calculating an expression.", token.Text));
                }
        }
    }
 
    if (operands.Count == 1)
    {
        return Expression.Lambda<Func<CalculationHelper, double>>(operands.Pop(), parameter);
    }
    else
    {
        throw new ArgumentException("Invalid expression");
    }
}

If you read the code, you will see it may insert two method calls inside the expression tree, one to Dice.Roll, which simulates a dice roll (1d8), and another to CalculationHelper.SolveDependency, which solves the value of variables from other objects. The tree returned for this method can be later compiled to a delegate Func<CalculationHelper, double> which will be used to calculate the real value of the modifier. For example, the Cure Lights Woulds expression (“1d8 + Character.CasterLevel”) would be transformed and compiled into the following delegate:

Func<CalculationHelper, double> func = (c) => Dice.Roll(1, 8) + c.SolveDependency("Character", "CasterLevel");

(I will explain in another post why CalculationHelper is a parameter of the delegate)

Future improvements (now on hold while I work on other parts of the library) will be:

  • Handle parenthesis right in the grammar. Low priority, easy.
  • Improve the grammar and the expressions tree generator to handle expressions like xd4 where x is the value of another object. For example, the damage of the spell “Fireball” is 1d6 per caster level, so the expression should be something like “Character.Level d6” or something like that (not sure yet, suggestions accepted). High priority, so-so.
  • Improve the grammar and the expression tree generator to support calls to methods from the Math class (Round, Truncate,…). Medium priority, pretty hard.

This post has been published at Kartones.Net.

Microsfot MVP Summit and MVP Open Day (english)

[ Blog: Vicente - Jad Engine Blog ]
2010:03:29 12:49:34

I’m going to try to retake blogging in english as I have some people who follow me in twitter and that are subscribed to the blog that are english speakers, and there’s so much Google Translate can do :p

When you are nominated Microsoft Most Valued Profesional (MVP), one of the multiple beneficts you get is to be invited to two events: the MVP Summit that is celebrated in Microsoft Corp, Redmond (Washington) and the MVP Open Day, which depends of each country.

The MVP Summit lasts for four days, this year instead of having our hotels in Seattle, we were in Bellevue, much closer to the Microsoft Campus.

DSC_0004 The Hyatt Regency Bellevue hall where I had my room, great hotel!

DSC_0022

Bellevue bus station

  • First day: the talks today are mostly about the event and welcoming us. Last year the talk was given by Ballmer, but this year he was in Barcelona presenting Windows Phone 7 Series, so he recorded a video they put to us and then Nestor Portillo welcomed us. Appart from that the spanish MVPs had a dinner organized by our MVP Lead with some spanish people that work in Corp.DSC_0056 Ballmer videoDSC_0068 Pike Market fishermen, from Seattle, it’s a very typical attraction so see them throwing fish :p

DSC_0079 Spanish dinner in Bellevue, the seafood was served directly on the table, pretty weird (but the place was really good)

  • Second day: talks with our product group, the people from XNA and DirectX. I have no idea how other groups work as all talks are under NDA, but we talked about the present and future of XNA, things that were going to appear soon (XNA 4.0, WP7,…) and things we think would be important in the future. On the evening we had a private event with our group in the same bar/mini cinema we had the event last year. It is a very nice place and they serve really good mojitos :)

DSC_0095 Myself doing the idiot inside the Microsoft building (you can see a Big Daddy on the background)

DSC_0124

Lego Rock Band in the mini cinema

DSC_0136

Taking some drinks, from left to right: a Korean MVP whose name I don’t remember (sorry :S),

Benjamin Nitschke (Germany), myself, Phil Bourke (Ireland), Petri Wilhelmsen (Norway) y Charlas Humphrey (UK)

  • Third day: talks and meetings with our product group again, pretty similar to the second day (there are so many things to talk about that one day is not enough). At night there is a big party with all the MVPs (1400 people). Last year it was in Seattle EMP (Experience Music Project), and this year we went to The Garage, a really huge place with bowling lanes, billiards, and a lot of place to sit, talk, drink and dance. No pictures from this as I didn’t want to carry the camera (as I was pretty sure how the night was going to end :p).
  • Forth day: general talks for all the MVPs. Last year I saw them, but this year I preferred to stay outside talking with other MVPs and doing a little networking.

DSC_0145 

Last day lunch, with our MVP jackets :D

DSC_0150

Bye bye picture, more next year :)

Compared to last year, I really enjoyed more this Summit, I was more prepared for it, the team told us a ton of things and secret stuff about XNA and DirectX, and although my last year room mate (an Excel MVP) was very nice, this year I had a great time with Charles Humphrey, also a XNA/DirectX MVP.

On the other hand, the MVP Open Day is a local event (Spain and Portugal celebrate it together) and with a much smaller scope: one day. The most funny thing of the MVP Open Day is that new MVPs are “armed/knighted” MVPs, something I think only Spain does. This year we had the new boss of the MVP Leads (the Microsoft people who handle the MVP program on each country) visiting us and we knighted her too (thanks she had a lot of sense of humor and she liked the ceremony :p). No pictures of this, I totally forgot my camera :(

Microsoft MVP Summit y MVP Open Day

[ Blog: Vicente - Jad Engine Blog ]
2010:03:29 12:20:43

Cuando te nombran Microsoft Most Valued Profesional (MVP), uno de los beneficios del programa es ser invitado a dos conferencias: el MVP Summit que se celebra en Microsoft Corp, en Redmond (Washington), y el MVP Open Day, que es dependiente de cada país.

El MVP Summit es un evento de cuatro días de duración, este año en vez de alojarnos en Seattle, nos alojaron en Bellevue (mucho más cerca del campus de Microsoft).

DSC_0004

Foto del hall del Hyatt Regency Bellevue, el hotel donde nos alojaron (pedazo hotel :)).

DSC_0022Estación de autobuses de Bellevue

  • Primer día: charlas de bienvenida al evento, el año pasado nos la dio Ballmer, pero este año estaba en Barcelona anunciando Windows Phone 7 Series, así que nos grabó un video y la charla de bienvenida la dio Nestor Portillo. Además los MVPs españoles tuvimos una cena junto con algunas personas de Microsoft Corp de nuestro país.

DSC_0056Video de Ballmer

DSC_0068 Vendedores de pescado del Pike Market, Seattle (es toda una atracción local en Seattle ver como se lanzan el pescado ;))

DSC_0079 Cena de españoles por Bellevue, te servían el marisco encima de la mesa directamente (mu raro :p)

  • Segundo día: conferencias con tu equipo de producto, en mi caso con la gente de XNA/DirectX. No sé como son las charlas de otros equipos (ya que son todas bajo NDA – Non Disclosure Agreement), pero en la nuestra hablamos del presente y futuro de XNA, que cosas iban a aparecer en breve (XNA 4.0, WP7,…) y que cosas creíamos que serían importantes para el futuro. Por la tarde noche cada grupo tenía un “evento privado”/fiesta con el equipo, nosotros fuimos al mismo sitio que el año pasado, un bar con una sala de cine y unos mojitos que no veas :)

DSC_0095 Un servidor haciendo el canelo con las estatuas que había por el edificio de Microsoft (al fondo se ve a un Big Daddy)

DSC_0124 Lego Rock Band en un mini cine

DSC_0136

Tomando mojitos, de izquierda a derecha: un MVP de Korea cuyo nombre no recuerdo :S,

Benjamin Nitschke (Alemania), un servidor, Phil Bourke (Irlanda), Petri Wilhelmsen (Noruega) y Charlas Humphrey (UK)

  • Tercer día: de nuevo charlas con tu equipo de producto, parecido al día anterior (hay tantísimas cosas de que hablar que solo un día se hace corto). Por la noche hay otro evento/fiesta pero esta vez con todos los MVPs (1400 personas). El año pasado estuvimos en el EMP (Experience Music Project) de Seattle, y este año fuimos a The Garage, un mega bar con dos boleras, muuuuuchas mesas de billar y muchísimo sitio para sentarse, charlar, bailar,… De esto no hay fotos, ya sabía yo como iba a terminar y decidí no llevarme la cámara :p
  • Cuarto día: charlas generales para todos los MVPs de despedida. El año pasado sí que las vi, pero este me quedé fuera charlando con otros MVPs y haciendo un poco de networking.

DSC_0145 Comida el último día

DSC_0150 Foto de despedida, el año que viene más :)

Comparado con el año pasado, disfruté mucho más de este Summit, llevaba las cosas mucho más preparadas, el equipo nos contó muchísimas cosas y nos dio mucha información sobre XNA y DirectX, y además aunque el año pasado mi compañero de habitación, un MVP de Excel cuyo nombre no recuerdo fue muy majo, este año me reí mucho con Charles Humphrey, también MVP de XNA/DirectX.

En cambio, el MVP Open Day es un evento parecido pero a menor escala: solo dura un día y es a nivel local (aquí lo celebramos españoles y los portugueses juntos). Lo gracioso del MVP Open Day es que durante la cena se “bautiza” a los nuevos MVPs, una costumbre que creo solo tenemos aquí en España. Este año además había venido la nueva jefe de los MVP Leads (la persona de Microsoft que maneja el programa MVP de cada zona) y la bautizamos también (menos mal que se lo tomó bien :p).

Rotor’scope – The Secret of Endless Energy

[ Blog: Vicente - Jad Engine Blog ]
2010:02:13 20:25:00

Así se llama el último juego del estudio español Nivel21, desarrollado en XNA y ganador del segundo premio en el concurso Dream-Build-Play Challenge 09 de Microsoft. Rotor’Scope es un juego de puzzles muy original, con una historia y trama bastante trabajadas para que no sea un simplemente “me paso este puzzle, me paso este otro puzzle,…”. La verdad que quería nombrarlo en el blog por varios motivos:

  • Muestra que hacer un juego de calidad no es cuestión de la plataforma, lenguaje,… si no de las ganas que se tengan. Está claro que las herramientas ayudan, y soy de la opinión que C# + XNA es una combinación realmente productiva, pero que nadie se engañe diciendo: "es que este lenguaje/framework/engine/… no me da suficiente rendimiento". Ja, excusas.
  • Ahora mismo es uno de los juegos más trabajados de los XBox Live Indie Games, y ciertamente tiene el nivel suficiente para ser un juego de XBLA.
  • Han creado un motor open source llamado Tomahawk que es una de las mejores herramientas disponibles actualmente para hacer un juego con XNA. Se nota que la gente que lo ha hecho tiene experiencia profesional.
  • Han dado un ejemplo de “no atarse a las limitaciones” implementando conectividad con Facebook cuando técnicamente no se puede. No solo Facebook, Twitter y similares son unas herramientas de promoción increíbles entre los compradores, además han dado mucho de que hablar entre los desarrolladores con esta característica.

Así que nada, si os gustan los puzzles os animo a que le echéis un vistazo lo compréis en la XBox360. Aquí os dejo el enlance al marketplace y unas capturas sacadas de su web:

rotorscope_screenshot_01

rotorscope_screenshot_06

rotorscope_screenshot_05

dynamic (III): DynamicObject

[ Blog: Vicente - Jad Engine Blog ]
2010:01:20 19:33:00

Puede que se dé la ocasión que necesitamos un comportamiento parecido al de ExpandoObject pero queramos cambiar alguna cosa. Por ejemplo, el siguiente código lanza una RuntimeBinderException ya que la propiedad Name no ha sido asignada con anterioridad.

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic expando = new ExpandoObject();
            Console.WriteLine(expando.Name);
        }
    }
}

Pero, ¿y si quisiéramos que cuando no exista un miembro se devuelva null en vez de una excepción? Con ExpandoObject esto es imposible, pero la buena noticia es que podemos hacer nuestro propio ExpandoObject si implementamos la interfaz IDynamicMetaObjectProvider.

Mirando la información en la MSDN de la interfaz y ojeando en internet un rato, descubrimos dos cosas:

a) Implementar IDynamicMetaObjectProvider es bastante difícil.

b) Microsoft ha proporcionado una clase que proporciona una implementación por defecto de IDynamicMetaObjectProvider: DynamicObject.

DynamicObject proporciona un montón de métodos de la forma “TrySomething” que son los que se usan en la ligadura dinámica. Por ejemplo, TryGetMember y TrySetMember nos permiten definir qué ocurre cuando se accede a un miembro de la clase de forma dinámica. Con esto ya podemos hacer nuestra propia versión de ExpandoObject:

public class MyExpando : DynamicObject
{
    private Dictionary<string, object> members = new Dictionary<string, object>();
 
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (this.members.TryGetValue(binder.Name, out result))
        {
            return true;
        }
        else
        {
            return true;
        }
    }
 
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (members.ContainsKey(binder.Name))
        {
            members[binder.Name] = value;
        }
        else
        {
            members.Add(binder.Name, value);
        }
 
        return true;
    }
}

Lo que hacemos es muy parecido a lo que intuíamos que hacía internamente ExpandoObject: cuando se asigna un valor (TrySetMember) se guarda en un diccionario, y luego cuando se recupera (TryGetMember) se mira si existe y en caso de que no exista se devuelve null (en vez de una excepción). Para comprobar que todo funciona bien, un pequeño programa de prueba:

class Program
{
    static void Main(string[] args)
    {
        dynamic expando = new MyExpando();
 
        expando.FirstName = "Hola";
        Console.WriteLine(expando.FirstName);
 
        if (expando.LastName == null)
        {
            Console.WriteLine("null");
        }
 
        Console.ReadKey();
    }
}

La salida es “Hola” en una línea y “null” en la siguiente. Si en cambio en el else del TryGetMember hubiéramos escrito un “return false;” el comportamiento sería idéntico al de ExpandoObject: RuntimeBinderException.

En el próximo post retomaré el experimento de librería para CRPGs y como DynamicObject simplifica la implementación del patrón prototype.

Dynamic (II): ExpandoObject

[ Blog: Vicente - Jad Engine Blog ]
2010:01:07 18:00:01

El uso de dynamic no está solamente limitado a crear variables, métodos, lambdas,… con tipos dinámicos, si no que se ha añadido un nuevo namespace a C# 4.0 llamado System.Dynamic que contiene diferentes clases e interfaces relacionadas con la resolución de operaciones dinámicas (las clases de nombre XYZBinder). A parte de estas clases hay dos especiales que merece la pena comentar con más detalle: ExpandoObject y DynamicObject.

ExpandoObject está definido de la siguiente manera en la MSDN:

Represents an object whose members can be dynamically added and removed at run time.

Básicamente ExpandoObject es un objeto al que se le pueden añadir nuevas propiedades, métodos, eventos,… en tiempo de ejecución. Vamos a ver cómo. Si declaramos una variable de tipo ExpandoObject podemos observar que no tiene casi métodos o propiedades:

expando

La “magia” ocurre cuando declaramos un ExpandoObject como dynamic:

expando2

Intellisense nos avisa que como expando es una variable dinámica, todas las operaciones se resolverán en tiempo de ejecución. Lo cual nos va a permitir hacer cosas como esta:

expando3

Era de esperar que el código compilara ya que usando una variable del tipo dynamic casi cualquier cosa vale. Pero lo que no está tan claro es porque el código ejecuta, ya que como vimos en la primera captura ExpandoObject no tiene una propiedad llamada Lives ni un método llamado SomeMethod que acepte un int y devuelve un string. Si volvemos a la MSDN nos encontramos que la clase está declarada de la siguiente manera:

public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>, IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged

ExpandoObject implementa muchas interfaces, pero la única “especial” es IDynamicMetaObjectProvider, así que podemos asumir que es la que está relacionada con la “magia” de antes. De todas formas también vemos que ExpandoObject se comporta como un IDictionary<string, object>, así que es más o menos fácil imaginarse que puede estar pasando internamente: cuando se asigna un valor a una propiedad que no existe, de alguna forma que desconocemos se guarda el nombre de la propiedad y el valor en un diccionario interno y cuando se lee la propiedad este valor se recupera del mismo. Nada muy sorprendente, se podría incluso pensar que esto es solo “syntactic sugar” que traduce expando.Lives = 3 a expando.Add(“Lives”, 3) o expando[“Lives”] = 3 (no lo es, pero lo parece).

¿Y cuándo usar ExpandoObject? Pues ExpandoObject debería usarse en los sitios que se tenga un Dictionary<string, object>, por ejemplo cuando se leen pares de clave-valor de ficheros de configuración, o cuando se necesite una clase a la que se le pueda añadir funcionalidad en tiempo de ejecución, lo cual es más raro, pero hay casos de sistemas que requieren esta flexibilidad y las alternativas a usar ExpandoObject suelen tener una sintaxis horrorosa y no ofrecen casi ninguna ventaja.

Y finalmente, ¿y sí queremos modificar el comportamiento de ExpandoObject? Pues desgraciadamente no se puede, pero la buena noticia es que podemos hacer nuestra propia versión de ExpandoObject si implementamos IDynamicMetaObjectProvider. Pero eso lo dejo para el próximo post.

Novedades C# 4.0: dynamic

[ Blog: Vicente - Jad Engine Blog ]
2009:12:29 14:24:00

NET está haciendo una apuesta muy fuerte por los lenguajes dinámicos y sus características. Primero con toda la infraestructura del DLR (Dynamic Language Runtime), IronRuby, IronPython,… y ahora añadiendo mejoras en la interacción de estos nuevos lenguajes con C# a través de la palabra reservada dynamic.

dynamic es un nuevo tipo, pero es un tipo especial que se resuelve en tiempo de ejecución y no en tiempo de compilación, es decir, podemos hacer algo como:

 

dynamic a = GetDynamicObject();

a.SomeMethod();

 

Y realmente, podríamos ejecutar cualquier cosa sobre a, porque el Visual Studio no tiene ni idea de que es a hasta que se ejecute este código (vamos, que cuando le damos al punto no sale nada en el Intellisense ;) ). Esto seguramente le resultará raro a mucha gente, ya que por lo general los programadores de C# estamos acostumbrados al tipado estático (los tipos se saben en tiempo de compilación) pero si queremos poder interactuar con lenguajes dinámicos necesitamos que C# soporte el tipado dinámico.

Hay que tener en cuenta que dynamic no es lo mismo que object ni que var. Por ejemplo, esto compila con dynamic:

 

dynamic a = "hola";

a.SomeMethod();

int i = a;

 

Como a es dinámico, todas las operaciones en las que a esté involucrado se resolverán en tiempo de ejecución (a pesar de que claramente las dos van a petar). Si hacemos esto:

 

dynamic num = 3;

var result = num + 5;

 

Y usamos el visual para ver el tipo de result, nos saldrá que es dynamic, ya que como num es dynamic, a pesar de que tiene un entero dentro y le estamos sumando otro entero, toda la operación pasa a ser dinámica. Así mismo dynamic no solo puede usarse para declarar tipos aislados, sino también para parámetros en funciones. Esto es perfectamente legal:

 

public void Method(dynamic argument)

{

  argument.DoSomething();

}

 

En tiempo de compilación funcionará, y luego en tiempo de ejecución dependerá de si el objeto argument tiene un método llamado DoSomething sin parámetros. Si no es el caso recibiremos una RuntimeException al llegar a esa línea de código. Esto también es legal en tiempo de compilación:

 

Func<dynamic, bool> func = x => x.BoolenValue;

 

Donde habríamos declarado un delegado que recibe un tipo dinámico y devuelve un bool.

La verdad que para C# dynamic es un arma de doble filo: por un lado te permite hacer aberraciones ya que cualquier cosa dinámica compila y todos los errores te los vas a encontrar en tiempo de ejecución. Pero por otro lado te permite hacer cosas que son muy difíciles (o engorrosas) de expresar con C# 3.0 y que en ciertas situaciones son muy útiles. En los próximos posts explicaré más en detalle nuevas características de dynamic y el DLR y como nos pueden ayudar a hacer sistemas muy flexibles en C#.

Para más información: http://msdn.microsoft.com/en-us/library/dd264736%28VS.100%29.aspx

MVP otro año más

[ Blog: Vicente - Jad Engine Blog ]
2009:07:06 16:30:34

Hace unos días recibí una noticia que la verdad me hacía mucha ilusión recibir: he sido renovado como MVP de DirectX/XNA :) Este es mi segundo año como MVP y estoy encantado de poder seguir participando en esta tecnología que personalmente creo que tiene mucho futuro (aunque los principios siempre sean difíciles).

Además este año (que yo sepa) se nos unen como MVPs de DirectX/XNA dos personas que admiro muchísimo: Iñaki Ayucar (¡otro español!) y Promit Roy. ¡Enhorabuena a ambos!

mvplogo[1]


El patrón Singleton en C#

[ Blog: Vicente - Jad Engine Blog ]
2009:05:20 17:21:00

Una de las cosas que creo es importante cuando usas un lenguaje es entender como funciona por dentro. Por ejemplo es cierto que C# se parece mucho a Java pero a bajo nivel presentan muchas diferencias de filosofía y diseño que creo son importantes de entender para hacer un uso eficaz del mismo. Algo similar ocurre cuando alguien que está acostumbrado a C++ se pasa a C#, muchas veces piensa que es un C++ “fácil” (sin punteros, sin gestión de memoria) y luego se queja de que su rendimiento es mucho peor, que va lento,… cuando a veces todo esto es porque está usando C# como si fuera C++ y las cosas no funcionan así.

Un ejemplo de libro de esta situación es la implementación del patrón Singleton en C#. Si buscáis un poco, en muchas páginas webs para implementar un Singleton lazy y thread-safe en Java/C++ se recomienda la siguiente implementación:

public sealed class Singleton

{

    static Singleton instance = null;

    static readonly object padlock = new object();

 

    Singleton()

    {

    }

 

    public static Singleton Instance

    {

        get

        {

            if (instance == null)

            {

                lock (padlock)

                {

                    if (instance == null)

                    {

                        instance = new Singleton();

                    }

                }

            }

 

            return instance;

        }

    }

}

La sintaxis es de C#, pero lo importante es la idea del if/lock/if. A esto se le llama double-checked-locking y por motivos bastante sutiles esa implementación no es totalmente thread-safe (más detalles en este paper). El problema de thread-safe se puede solucionar haciendo la variable instance volatile (a partir de la JDK 5.0 y Visual C++ 2005, ni idea en otros compiladores de C++).

El problema es que como mucha gente de Java/C++ se ha acostumbrado a implementar el Singleton de esa manera, cuando llegan a C# hacen lo mismo. Pero resulta que en C# la implementación correcta es la siguiente:

public sealed class Singleton

{

    static readonly Singleton instance = new Singleton();

 

    static Singleton()

    {

    }

 

    Singleton()

    {

    }

 

    public static Singleton Instance

    {

        get

        {

            return instance;

        }

    }

}

Visto así por encima, esa implementación no parece ni lazy, ni thread-safe, ni nada de nada. Pero si nos cogemos el gran CLR via C# (libro totalmente recomendado) podemos entender como es que tan poco código hace tantas cosas. Toda la implementación gira en torno a los constructores estáticos y como funcionan dentro de .NET. Lo primero es entender que esto:

public sealed class Singleton

{

    static int a = 5;

}

En IL se traduce a esto:

public sealed class Singleton

{

    static int a;

 

    static Singleton()

    {

        a = 5;

    }

}

Y que por ejemplo esto otro:

public sealed class Singleton

{

    static int a = 5;

    static int b;

 

    static Singleton()

    {

        b = 10;

    }

}

En IL queda así:

public sealed class Singleton

{

    static int a;

    static int b;

 

    static Singleton()

    {

        a = 5;

        b = 10;

    }

}

Vamos, que las inicializaciones de variables estáticas una vez compilada la clase se incluyen dentro de un constructor estático (si el constructor existe se añaden al principio en el orden que son declaradas, si no existe se genera un constructor y se añaden).

En C#, cuando el compilador JIT (el que pasa de IL a código máquina) encuentra un constructor estático, mira si ese constructor ya se ha ejecutado o no:

  • Si no se ha ejecutado, emite un lock, el código de ejecución y un unlock.
  • Si se ha ejecutado, no emite nada.

Es decir, el JIT se asegura que el constructor estático solo se ejecute una vez aunque haya varios hilos, por eso en C# no hace falta poner el lock, ya que la línea new Singleton() se ejecuta dentro del constructor estático y el propio JIT ya se ha encargado que ese constructor solo sea llamado una vez. Con esto ya tenemos cubierto el tema de thread-safe, pero ¿y lo de que sea lazy?

Primero, tengo que reconocer que os he mentido un poco antes. Esta clase:

public sealed class Singleton

{

    static int a = 5;

}

Y esta otra clase:

public sealed class Singleton

{

    static int a;

 

    static Singleton()

    {

        a = 5;

    }

}

No generan exactamente el mismo IL: la primera está marcada con un atributo que se llama BeforeFieldInit y la segunda no. Cuando una clase está marcada como BeforeFieldInit el runtime del framework puede decidir ejecutar su inicializador de tipo (constructor estático) cuando se haga la primera referencia a ese tipo o antes, según le parezca. Pero si no está marcada con BeforeFieldInit (porque hemos puesto un constructor estático explícito) entonces el inicializador del tipo solo puede ejecutarse en el momento que se haga uso de ese tipo.

Es decir, como mi implementación del Singleton tiene un constructor estático, esta clase no está marcada como BeforeFieldInit y lo que haya dentro del constructor estático (new Singleton()) se ejecutará justo cuando haga Singleton.Instance. Pero si no tuviera un constructor estático la línea new Singleton() se podría ejecutar una hora antes de llamar a Singleton.Instance (por ejemplo), según decida el runtime. Y esto puede ser un problema porque no tenemos ni idea de cuando se va a ejecutar ese constructor y si tiene código muy pesado puede ralentizar el resto del programa en algún punto que no sea adecuado, o incluso ejecutarse y que luego resulte que nunca se utiliza en el programa.

Podéis encontrar una discusión mucho más en profundidad del tema en este artículo y este otro (cuentan lo mismo pero de forma mucho más técnica).


Emprendedores

[ Blog: Vicente - Jad Engine Blog ]
2009:04:08 07:21:00

Hay un tipo de personas a las que envidio admiro de sobremanera: los emprendedores. Yo siempre he tenido ideas que he pensado que podrían ser un buen producto, o al menos suficentemente decente para funcionar. Cuando empecé con esto de los videojuegos tenía la idea del juego definitivo, normalmente un refrito de los tres o cuatro juegos de moda del momento, y junto con algunos amigos y algún colaborador nos lanzábamos a lo loco a intentar realizarlos - seguro que al igual que muchos de los que leéis estas líneas.

Todo empezaba genial, con la gente muy animada dedicando buena parte de su tiempo libre y de repente, un día:

  • Pepito ha ligado el finde anterior y ya no tiene tiempo para seguir en el proyecto.
  • Juanito lleva 5 días sin dormir enganchado al Call of Duty 6. Pero es para intentar conseguir nuevas ideas, ya sabéis, hay que jugar a todas las obras maestras - aunque tu juego sea un clon del pong.
  • Luisito está más pelao que las ratas y se ha buscado un trabajo, así que cuando termina su jornada solo le apetece tumbarse en el sofá y ver la tele.
  • Jaimito viendo que los demás no hacen ni el huevo, obviamente se contagia del espíritu reinante y tampoco hace nada.

Total, que al cabo de dos meses el resultado es un proyecto cancelado y lo mismo hasta alguna bronca o discusión entre los integrantes del equipo. Después de un tiempo, y ya siendo más “maduros”, este proceso se vuelve a repetir con idénticos resultados y así N veces hasta que uno tras otro nos vamos dando cuenta que mejor dedicarnos a otra cosa.

Pero hay gente que es capaz de salir de este círculo y llevar sus ideas adelante. Cuando te pones a analizarlo el resultado es sorprendente:

¡han convertido su proyecto en un trabajo!

Traduciendo: de lunes a viernes dedican entre las 9 y las 19 a su idea (cuando las cosas van bien, cuando hay que apretar parecen un 7 Eleven). Y eso que también tienen novias y les encanta viciarse al Call of Duty 6. Además, ¡la de riesgos a los que se exponen frente a un trabajo tradicional! Que si no encuentras clientes, los proveedores te la lían, no consigues financiación,…

Y esa es la forma de pensar que hace que uno no emprenda. O al menos es la que hace que yo no me atreva a emprender y admire a la gente que tiene los cojones de arriesgarse, y más en este país donde el fracaso está tan mal considerado – demasiado en mi opinión.

Así que este post va dedicado a toda esa gente que da ese salto, que pone todo su esfuerzo en perseguir sus ideas, en confiar en ellas, y en no dejarse achantar por todos los posibles problemas que puedan cruzarse en su camino.

Por suerte para mi, porque considero una fortuna poder hablar con este tipo de personas, conozco a bastante gente que ha emprendido y me gustaría nombrarles por aquí un poco:

  • A Iñaki Ayucar que posiblemente sea el tío que más sabe de gráficos y código manejado de España, y que lleva años apostando por su empresa Simax, un simulador de conducción que es sencillamente impresionante.
  • A mis compañeros de facultad que fundaron Vaelsys, una empresa especializada en visión artificial. Nunca se me olvidarán momentos como cuando Jorge hizo su parte de una práctica de Criptografía en Latín, o cuando Edu se vino a mi casa con su compañera a hacer prácticas de POO y el cabrón terminó comiendo palomitas mientras yo hacía el trabajo. Y encima al cabo de unas semanas vino quejándose de que solo había sacado un notable. Está claro que se le da bien ser jefe (y que yo soy un pringao).
  • A la gente de Signum Software y en particular a Olmo del Corral, que se han lanzado a la aventura de lanzar un ORM open source en .NET con ideas bastante novedosas en algunos aspectos.
  • A Cokidoo, empresa fundada por yens y tirso (entre otros), dos conocidos de Stratos-AD. Están poniendo toda la carne en el asador con una red social enfocada a estudiantes de movilidad (erasmus,…) que tiene un acabado impecable. Ahora mismo están participando en el concurso BBVA Open Talent, así que pasaros por aquí y votadles.
  • A ethernet, otro Stratero al que tuve la oportunidad de conocer en el Congreso de Desrrolladores de Videojuegos 08. Javi ha creado un producto llamado Agroguía que es un sistema de guiado GPS para tractores. Un curioso nicho de mercado, todo sea dicho :p
  • A SiPoX, un habitual de las Kdds madrileñas de Stratos-AD que ha fundado Undead Code, otra empresa orientada hacia el tema de aplicaciones web y web 2.0. También participan en el BBVA Open Talent con Somflee, una mezcla entre red social y herramienta de gestión de contenidos digitales. Podéis votarles aquí.

Para todos ellos, lo mejor. A ver si un día de tanto hablar con vosotros se me contagia algo y me lanzo yo también a la aventura :)