No uses goto, que yo lo usaré

Estaba yo esta mañana más aburrido que una ostra (y eso que tengo curro, pero a veces uno no es capaz de tirar una sola línea de código) y me dio por abrir el .NET Reflector, ahora de Red Gate.


A veces suele darme por mirar en las tripas del .NET, sólo por mera curiosidad y completamente al azar, y a veces también me desespero al ver cómo una llamada en código .NET termina, tras varios niveles de anidación completamente vacíos, en una llamada a una función nativa de Win32. Conociendo el fabuloso desempeño del jitter de .NET con el código muerto (recomiendo leer toda la serie desde la primera entrada hasta la última), me asombra que a veces la máquina virtual llegue a funcionar a una velocidad aceptable (que lo hace).


Pero esta mañana me he llevado una sorpresa. Abriendo el árbol de System.IO me encuentro con una clase llamada «Pipes». Hasta donde yo sabía, el .NET Framework no soportaba el concepto de pipe nativo, pero parece ser que en la versión 3.5 ha sido añadido.


Como me ha llamado la curiosidad, me he metido dentro del código y en el primer sitio que he mirado, el método Connect() de NamepClientPipeStream, los ojos han empezado a llorarme. Al lector también pueden llenársele de lágrimas si mira la imagen adjunta. Sí, efectivamente, hay tres equiquetas de tipo «label» y nada más y nada menos que cuatro gotos diferentes…


image


No me vale que me digáis que es cosa del optimizador: el optimizador de C# no es capaz de transformar el código de esa forma (cosa que el de C++ no sólo es capaz de eso, sino de más).


Pero la cosa no acaba ahí, sino que el método WriteFileNative de la clase PipeStream es todavía, si cabe, más curioso:


image


Básicamente se está saltando toda la seguridad y está escribiendo directamente desde un puntero de C# bloqueado con la sentencia fixed que se correspondería con un pin_ptr de C++/CLI (Hay que decir, que las clases que llaman a este método comprueban muchas cosas antes de llamarlo)…


Personalmente opino que el uso de todos esos gotos está más que justificado, pero vamos a dejar al lector que piense por qué.

6 comentarios sobre “No uses goto, que yo lo usaré”

  1. Hola Rafa: creo que es claro (a lo mejor no lo es) que se trata de código que no ha sido escrito por humanos. Y en ese caso vale. Por otra parte, los gotos no est’an prohibidos ni mucho menos, es m’as, los creadores de c# (un lenguaje maduro) lo han incorporado desde un principio al igual que muchos otros lenguajes.

    Yo te recomiendo que, si tienes tiempo, leas el cap’itulo del libro Code Complete dedicado exclusivamente a este tema que has planteado. Los dos sabemos que no vas a encontrar nada sobrenatural en esas p’aginas pero es excelente como plantea la evoluci’on del pensamiento desde Dijkstra hasta esta parte.

    Saludos Rafa

  2. Si te fijas bien en el código del método Connect te darás cuenta que los label y el goto corresponden a una instrucción while y un continue. Es más me atrevería a asegurar que es un while(true) en toda regla.

  3. No entiendo porque te alarmas al ver goto’s al utilizar reflector. Si se recomienda (prohíbe) no usar goto’s no es por rendimiento, si no por facilidad de mantenimiento. Seguramente sea más rápido los goto’s. El código ensamblador no tiene while’s ni swich ni sentencias tan elaboradas. Todos son saltos y movimientos de memoria.
    Así que al compilar código a IL aparezcan goto’s no tiene por que sorprender. Seguramente cuando se convierta ese IL a código máquina ni se parezca el resultado.

  4. Hola, Rafa!

    Me parece estar de acuerdo con Andrés, seguramente Reflector no hace aquí el trabajo de «reconstruir» sentencias de alto nivel a partir del IL…

    Por ejemplo, este trozo de código al principio de WriteFileNative:

    if (((int) buffer.Length) != null)
    {
    goto Label_000B;
    }
    *((int*) hr) = 0;
    return 0;
    Label_000B:
    num = 0;
    num2 = 0;
    // …

    Probablemente se escribió en C# así:

    if (buffer.Length == 0)
    {
    hr = 0;
    return 0;
    }
    else
    {
    num = 0;
    num2 = 0;
    // …
    }

    Seguramente esto puede verse si se activa la depuración del código fuente de .NET:

    http://weblogs.asp.net/scottgu/archive/2007/10/03/releasing-the-source-code-for-the-net-framework-libraries.aspx

    Este artículo mío en C# Dev Center tiene relación con los pipes de .NET 3.5:

    http://msdn.microsoft.com/en-us/vcsharp/cc178927.aspx

    Slds – Octavio

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *