Clases con Clase (C#, nosecuántos)

Hoy vamos a hablar un poco de las clases. Como todo el mundo sabe la herencia sin polimorfismo no es herencia y el polimorfismo sin virtualización, tampoco. Pero puede ocurrir que malinterpretemos cierto comportamiento si no tenemos clara la estructura jerárquica de las mismas, ya que dependiendo del lenguaje que utilicemos la declaración de las mismas podría resultar confusa en algunas situaciones. C# viene en nuestra ayuda forzando nos en cierta medida a especificar el tipo de clase que queremos.


Si queremos crear una clase abstracta, es decir, aquella de la que no se puede instanciar y que meramente nos sirva de base polimórfica, debemos definirla con la palabra abstract; de esta forma el compilador sabe que no debe instanciar de ella y a nosotros nos resulta mucho más fácil identificar el tipo de clase.


También podríamos querer una clase de la cual no se pueda heredar, característica que no suele estar disponible habitualmente en otros lenguajes. En este caso tenemos que sellarla mediante la palabra reservada sealed.


Y todavía tenemos un nuevo tipo de clases cuya finalidad es la de definir un interfaz común. En lenguajes más tradicionales esto se hace teniendo lo que se llama una clase virtual pura, es decir, una clase cuyos miembros están todos asignados a cero. Pero el Net nos lo pone mucho más fácil, ya que nos permite declarar un tipo de clase llamado interfaz mediante la palabra reservada Interface.


Cuando utilizamos la herencia también nos deshacemos de las posibles confusiones a la hora de ocultar o redefinir un método mediante el modificador new, evitando así la posibilidad de tener un nombre de método que queremos nuevo pero que ya existe en alguna clase base. Si sobrescribimos algún método existente sin colocar el modificador el compilador nos avisará, y también lo hará si lo colocamos y dicho método no está en ninguna clase base. Y de igual manera que podemos ocultar un método miembro existente también podemos ocultar el nombre de una clase anidada utilizando el mismo modificador. Si queremos acceder al método culto desde nuestra clase simplemente debemos cualificarlo con su firma completa.


Es típico que la accesibilidad de una clase o de un método sea público, protegido o privado, pero el Net nos amplía las posibilidades añadiendo el acceso a interno y cambiando en cierta medida la definición de acceso público. Ahora un acceso público significa que dicho elemento o clase estará disponible globalmente tanto en el ensamblado en el cual está definida como en cualquier otro ensamblado siempre y cuando incluyamos su espacio de nombre, y el acceso interno indica que dicho elemento sólo estará disponible dentro del ensamblado actual. También podemos definir la accesibilidad protegida e interna simultáneamente.


Nombres de miembro reservados


Como cosa curiosa tenemos que decir algo sobre las propiedades, los eventos y los indexadores. Cuando definimos una propiedad que se llama, por poner un ejemplo, nombre, automáticamente quedan reservados dos nombres de método, a saber, get_hola y set_hola, independientemente de sea dicha propiedad es de sólo lectura o sólo escritura. En C++/CLI la cosa está mucho más clara y nítida, ya que somos nosotros los que directamente definimos los métodos get y set.


Lo mismo ocurre en con los indexadores, y también con los eventos. En el caso de estos últimos los dos nombres de miembros reservados son add_<nombre> y remove<nombre>. También está reservada la firma void Finalize(); utilizada en aquellas clases que dispongan de destructor.


Constantes, elementos estáticos y volátiles


El uso de un elemento estático para que sea compartido entre todas las instancias de la misma clase es ya conocido y ampliamente utilizado, pero dadas las características especiales del C# el uso de este tipo de elementos también se suele utilizar en sustitución de las constantes en aquellas situaciones en las que el uso de un elemento constante en no está definido.


Porque disponemos de elementos definidos como constantes (mediante la palabra reservada const) siempre y cuando éstos sean tipos básicos o clases-valor, y no está permitido el uso de clases referencia constantes. Esto es una limitación del motor de ejecución Net, limitación que podemos soslayar utilizando campus de solo lectura y campos estáticos de solo lectura, aunque me queda por determinar si dichos valores realmente se sustituyen en el código como números mágicos (que es el efecto deseado) o llevan consigo toda la parafernalia de la verificación de tipos en tiempo de ejecución.


Un tipo de solo lectura se declara mediante la palabra reservada readonly y debe ser inicializado en su declaración, aunque hay ciertos tipos que no podrán serlo. En este caso debemos definirlos como estáticos y de solo lectura mediante el uso de las palabras reservadas static readonly, y en este caso podemos realizar su inicialización en el constructor estático o directamente durante la declaración.


Personalmente opino que todo lo de arriba no es más que una deficiencia del lenguaje C#, que muy bien podría haberse solucionado ampliando el uso del preprocesador o la inclusión de las características pertinentes dentro del motor Net.


En contrapartida con todo lo anterior disponemos de las variables volátiles, que deben ser utilizadas para los tipos básicos que sean modificados por varios hilos, evitando así toda la parafernalia de objetor de sincronización y semáforos.


Pasó de un número variable de argumentos


Tradicionalmente se ha permitido que lenguajes de muy alto nivel (y también de muy bajo nivel) permitan alguna forma de pasar un número variable de argumentos en un método. El C# lo soluciona de forma elegante aunque a mi modo de ver bastante limitada.


Si queremos que un método pueda recibir un número variable de argumentos tan sólo debemos especificar en su firma que va a recibir un array de una sola dimensión. La implementación de dicho método deberá recorrer todos y cada uno de sus elementos de la matriz y realizar las acciones oportunas con cada uno de ellos. Dadas las características polimórficas del C# si pasamos un array de objetos podremos convertir fácilmente estos a su tipo real mediante reflexión.


A la hora de llamar a este método podremos hacerlo tanto mediante el uso de un array como por el número de parámetros adecuado como se muestra en el fragmento de código siguiente.


void HazAlgo(params object[] args)
{
  
foreach(object o in args)
    

}

Object[] o=new object[]={1.»dos»,3,»cuatro»};
HazAlgo(o);
HazAlgo(1,»dos»,3,»cuatro»);

El caso de los bytes perdidos

    Hola, ínclito lector. Espero que seas paciente conmigo, ya que tengo que hablarte de algo bastante importante y que seguro te afecta en la misma medida que lo hace a mí. Pero antes de entrar en materia tengo que justificar y explicar algunas cosas, así que espero que leas lo que viene si no con interés porque te resulte ya conocido, sí al menos con cierta condescendencia hacia este penitente del teclado. En fin, vamos allá.

    La unidad básica de información es el bit, que es un uno o un cero, aunque la representación real pueda ser diferente, como un flanco de subida para el uno y uno de bajada para el cero. O al revés. O incluso mediante lógica negativa se puede representar un 1 como ausencia de tensión y un cero como presencia. A nivel lógico no nos importa mucho, ya que de la forma que se represente el contenido de información es el mismo.

    Históricamente los bits se agrupan en bytes, que son 8 bits juntos. No vamos a entrar en muchos detalles en por qué se implementó de esta forma y no, por ejemplo, que 10 bits formaran 1 byte. El hecho, igual que antes, es que a un grupo de 8 bits se le asigna el nombre de byte y dicho byte se trata como la unidad básica de información en informática.

    Con 1 byte podemos representar hasta 255 valores diferentes aparte del cero mediante combinaciones de ceros y unos. Empezando con 00000000b para el cero, siguiendo con 00000001b para el número 1, 00000010b para el 2, 00000011b para el tres hasta 11111111b, que representa el número 255 (o -127, según se mire, pero de nuevo no vamos a entrar en detalles).

    Otra forma de representar un byte es mediante números hexadecimales, es decir, números en base 16, en los que por convención los dígitos válidos son 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F. Si nos fijamos un poco observamos que el número binario 11111111b se puede representar como FF en hexadecimal. O como nos gusta a los informáticos: 0xFF.

    Pero lo más curioso del tema es que 28 es el número de valores posibles que caben en un byte, es decir, 28=256 (o sea, 255 más el cero). Si nos damos cuenta el número es 256 y no 250, porque estamos trabajando en números binarios y al hacer la conversión matemática y real es lo que nos da. Y no podemos modificar la matemática porque es así. Lo que sí podríamos hacer es crearnos un sistema numérico en el que 28 fuera 250. Pero no valdría para nuestro universo.

    Siguiendo con el tema, si juntamos dos bytes uno al lado del otro, obtenemos un número que se puede representar con 0xFFFF en hexadecimal o bbbb bbbb bbbb bbbb en binario, en donde cada b representa un uno o un cero. Y su valor máximo, o el máximo número de valores que podemos guardar ahí son 28x28, es decir 28+8=216=65536. Y no 65000. Y son matemáticas casi de escuela primaria.

    Pero adelantemos un poco. ¿Qué ocurre si medimos en cantidad de miles de bytes en lugar de en bytes, subiendo la escala tres órdenes? A poco que uno sea riguroso pensando, deducirá que un kilo-byte son 1024 bytes. Es decir, 1KByte=1024Byte. Veamos por qué.

    Si trabajamos en metros y queremos pasar una cantidad a kilómetros, multiplicamos por 1000, es decir, por 103. En otras palabras, elevamos al cubo la base numérica. Pero lo que en base decimal es fácil, en base binaria no lo es tanto. Y tenemos que sumergirnos en razones históricas sobre el diseño y la arquitectura de los ordenadores. Intentaremos ser breves.

    Tradicionalmente la construcción de computadores ha sido muy cara, y más cara todavía la construcción de memoria. Toda la informática está basada en lo que se conoce como báscula (latch en inglés) lógica, generalmente de tipo D. Una báscula representa 1 bit. 10 básculas, 10 bits. Pero con 10 básculas podemos guardar 210 números diferentes, que son 1024 valores. No 1000 ni 1100. Y en la época en la que se diseñaron los primeros ordenadores, desperdiciar 24 números de cada 1000 era un derroche impensable, aparte de que calculando así obtenemos más ventajas que no son observables a simple vista, pero que están ahí. Como evitarnos lógica física (o sea, electrónica) para evitar esos 24 números que nos sobran.

    ¿Qué ocurre si juntamos un grupo de 8 básculas y las optimizamos para que sean 1 byte (que llamaremos por simplicidad báscula-8) y luego juntamos grupos de 10 básculas-8? Pues que tenemos 1024 formas de almacenar 1 byte. No 1000 ni 1100. Y volvemos al tema anterior del desperdicio de esos 24 números posibles.

    Quizás no sea la combinación perfecta, pero es la que hay. En su momento se decidió por agrupar los bits en atados de 8 para que cupieran exactamente dos dígitos hexadecimales, y luego agrupar dichos atados de 8 bits en atados de 10. Podrían haber agrupado dichas básculas-8 en grupos de 8, pero entonces habría que trabajar en números octales, y estos no presentan las ventajas de los hexadecimales (de hecho en un tiempo se trabajó con ellos, pero rápidamente fueron descartados). También podrían haber agrupado los bits de 10 en 10, pero ocurría lo mismo, los números no cuadraban de forma «mágica».

    Y si agrupamos 10 grupos de 10 básculas-8 por cada báscula-8 en una especie de matriz de dos dimensiones obtendremos 210x210 bytes, es decir, 1024×1024 o lo que es lo mismo, 1.048.576. Y si lo ajustáramos a nuestro formato decimal, ahora estamos perdiendo 48.576 «celdillas mágicas» por un quítame allá esas pajas.

    Hay más razones para estos agrupamientos, como el hecho de que 210 es un número natural dentro del sistema de numeración en base 2, mientras que el número 103 no tiene representación directa. También está el hecho del direccionamiento físico de las líneas de datos y direcciones dentro de un microprocesador y de una memoria, pero vamos a detenernos aquí.

    Así que ocurrió lo que tenía que pasar: 1KByte pasó a ser 1024Bytes, la correlación era instantánea y prácticamente irresistible. Y 1Mbyte = 1024 Kbyte. Y así subiendo de escala.

    Trabajando así tenemos dos ventajas a la hora de fabricar chips de memoria: tenemos una cantidad de celdas extra (y gratis) y encima el proceso de fabricación es más sencillo. El Sistema Internacional de Pesas y Medidas ha protestado, pero no ha regularizado porque es absurdo forzar la escala decimal, absurdo y muy caro en implementación física. Y a fecha de hoy, hablando dentro del mundo de la informática, un kilobytes son 210=1024 bytes, por mucho que algunos rabien.

    ¿Pero qué ocurre cuando vas a una tienda a comprar un chip de memoria para tu ordenador? Llegas al mostrador y pides un módulo de «un giga». ¿Y qué te venden, medido en bytes? Pues 1 GByte = 1024 MByte = 1024×1024 Kbyte = 1024x1024x1024 Byte. O 1 GByte = 210 MByte = 220 Kbyte = 230 Byte. A fin de cuentas, te están vendiendo 1.073.741.824 bytes. Y desde luego si ese módulo llevara 1.000.000.000 seguro que reclamarías esos setenta y tres mil y pico bytes que faltan. Además, fíjate que podrías comprar 512 «megas», no 500, sino 512. O 256, pero no 250.

    Sin embargo, veamos qué ocurre cuando vas a comprarte un disco duro. Llegas a la tienda y pides uno de 120 «gigas». Vas todo contento, lo montas y… descubres que ¡sólo tiene 111,79! ¿Y eso? Te faltan 8,21 GB. ¿Se perdieron por el camino? No, porque cuando lo instalas y lo formateas en una sola partición descubres tus 120 GB. Pero 120 justitos, justitos.

    Vaya. Haciendo cálculos descubres que 120 GB son 128.849.018.880 bytes. Sin embargo tu disco duro sólo tiene 120.000.000.000 bytes. Imagina que compras un módulo de memoria de un «giga» que solo tuviera 1.000.000.000 bytes. Pues es lo mismo.

    ¿Qué está pasando aquí?, te preguntas. La respuesta es fácil: los fabricantes de discos duros han decidido por su cuenta y riesgo que 1 KB son 1000 bytes. Y que 1 MB son 1000 KB. Y ellos te venden un disco duro de 120 de «sus gigas», no de los «gigas» que todos conocemos.

    Si uno va a una tienda y compra una cinta métrica de 1 kilómetro (suponiendo que las haya) le venden una tira de tela que mide 1000 metros. No mide 1024 metros. Porque hablamos de metros, no de bytes. Si las cintas métricas se midieran en bytes, de seguro que los tendría. Y para muestra, los módulos de memoria, que también se miden en bytes.

    Desde luego que yo me siento no solo insultado, sino también robado. Me están vendiendo algo que no es lo que ofrecen. Porque me están vendiendo un disco duro de 111 Gigabytes como si fuera de 120. Y la pérdida aumenta considerablemente conforme aumentan las capacidades. Los 320 «gigas» comprados son en realidad apenas un poco más de 298. ¡Joder, me han quitado casi 22 «gigas»! Por su cara bonita.

    Y esto no sólo ocurre en España, el país de los «pobrecitos habladores», sino que es algo completamente generalizado a nivel mundial. Se aprovechan de nosotros. Y encima nosotros tragamos como tontos. ¿Has comprado un disco duro recientemente? ¿Sí? Pues hala, otro tonto más al bote. Yo la última compra que hice fue de cincuenta. Y pagué sin rechistar (bueno, pagó mi empresa). Y la próxima será de por lo menos cien unidades. Cien veces tonto y cien veces robado. Y los fabricantes de discos duros partiéndose el culo de risa a nuestra costa.

    Pero todavía hay más, al menos en España. Si vas a una tienda y compras un rollo de 5 metros de papel de aluminio que realmente tiene 4,99 el fabricante está cometiendo un delito. Está estipulado en la ley. Los fabricantes de discos duros también la están violando. Te están vendiendo algo de un supuesto tamaño que realmente tiene menos. Y estás pagando por el tamaño total. Delito con todas las palabras de la ley.

    Y no se trata de 10 milímetros. Se trata de magnitudes mayores. Y sin embargo nadie hace nada. Bueno, algunos tontos nos dedicamos a patalear, pero con eso nos quedamos. Aunque al menos no tragamos, por lo que quizás seamos menos tontos que los que compran sin rechistar. O más. Porque encima de tragar, dedicamos dos horas a escribir cosas como estas.

    Además, los fabricantes no pueden excusarse en que siempre ha sido así en los discos duros. Hace unos años los tamaños eran los reales, no como ahora. Simplemente se juntaron y decidieron cambiar las normas unilateralmente. Y creo que eso también es delito. Y nosotros sentados en nuestra silla, felizmente ignorantes de que nos roban nuestra energía (el dinero es trabajo, que al final es un gasto de energía), mientras que ellos se van al Caribe con la modelo de turno con el dinero extra que nos han sacado.

    En fin, que ahí queda dicho. Para quien quiera escuchar.

Forzar la carga de drivers no firmados en Windows Vista x64

Corrección
Para escarnio y pública befa propia, lo escrito más abajo, por desgracia,


no funciona


Y que conste que lo he comprobado. Pero me parece a mi que se trata de la misma opción que arrancar pulsando F8, es necesario ejecutarlo cada vez que queramos que el siguiente reinicio sea con drivers sin firmar… En fin, que en lugar de borrar la entrada la dejo para rechifla propia y ajena.


Ahora el texto original:
En primer lugar decir que la idea o el truco no es mío, sino de un tal John Savill, alias JSI, MVP de Microsoft. La entrada original se puede encontrar aquí; también comentar que el truco lo he visto en los grupos de noticias de Tella, publicado por Peni y confirmado por mi mismo (ya puedo cargar mi WebCam Genius GE111 sin tener que estar presionando F8 cada vez que reinicio Vista –que realmente no son tantas) y por Javier Inglés, otro MVP.


La firma de controladores es una nueva característica que dispone la versión de 64 bits de Windows Vista; con ella se pretende evitar la instalación inadvertida de drivers defectuosos o no deseados, y por extensión cualquier otro software de sistema potencialmente dañino.


El primer paso para habilitarla o deshabilitarla consiste en abrir una consola de comandos con permisos elevados. Para ello nos vamos al menú inicio y buscamos el enlace directo a ella y con el botón derecho del ratón la lanzamos con permisos de administrador.


Para forzar que sólo se carguen drivers firmados debemos teclear en ella lo siguiente:


bcdedit /set nointegritychecks OFF


Y para permitir tanto la carga de drivers firmados como no firmados lo que tenemos que teclear es:


bcdedit /set nointegritychecks ON


Una vez cambiada cualquiera de estas dos opciones sólo tenemos que reiniciar para que nuestro cambio sea efectivo.

Más cosas curiosas sobre el C#

    Voy a comentar más cosas curiosas que estoy descubriéndole al C# y que quizás los expertos del lenguaje vean como obvias, pero que personalmente considero son bastante interesantes. Vamos allá.


La sentencia switch 
    Esta sentencia es muy curiosa (y muy potente, quizás más que su equivalente en C++). Lo más curioso de todo es que se puede utilizar una cadena (del tipo string como valor comparativo. Algo así:


switch(miCad)
{
    case «Hola»: 
        break; 
    case «Adiós»: 
        break; 
    default: 
        break;
}


    Y no es una característica pobre el poder hacer esto, que tradicionalmente se suele hacer mediante la concatenación de condicionales.


    Otra cosa curiosa es la imposibilidad de «caer a través» de un case, lo que si en principio puede parecer una limitación, realmente no lo es, porque existe una forma correcta de «caer» y que, al contrario que con otros lenguajes, no es propenso a cometer errores. Porque amigos, el error más común en una sentencia swtich es que se te olvide un break, y dicho olvido puede causar interesantes efectos laterales no deseados que pueden causar una buena tanda de problemas. Veamos un ejemplo:


switch(f)

    case 1: 
        CasoUno();    //Error, falta break 
    case 2:
        CasoDos(); 
        goto default; 
    case 3: 
        CasoTres(); 
        break; 
    case 4: 
        CasoCuatro(); 
        goto case 2; 
    case 5: 
    default: 
        break;
}


Menuda máquina de estados, está más liada que el pelo de un indigente. En el caso 1 tenemos un error, pues estamos «cayendo» sobre el caso 2. En el 2, tras ejecutar el método, saltamos al caso por defecto. Y finalmente en el caso 4, tras ejecutar el método, volvemos al caso 2. Como cosa curiosa decir que la forma del caso 5 está permitida para agrupar casos con el mismo comportamiento. Muy bonito y muy potente.


Además, los casos no tienen por qué estar ordenados, el compilador ya sabe por cuáles ha pasado y por cuáles no. Menuda gozada.


Alias para espacios de nombres
Con esta característica lo mismo sorprendo a alguien. Seguro. Podemos definir espacios de nombre (namespace) que son alias de otros espacios de nombres. Es un tema curioso y que creo que ni el C++ ni el C++/CLI tienen. Veamos un ejemplo:


namespace N1.N2

    class A{}
}


namespace N3

    using R=N1.N2; 
    class B:R.A{}
}


Observamos que la clase B hereda de la clase A del espacio de nombres N1.N2, pero lo hemos hecho utilizando un alias.


Las reglas de manejo de todo esto están explicadas en las páginas 266 y siguientes del The C# Programming Language que he citado por aquí en otros momentos. Son unas reglas un tanto pejigueras, puesto que no permiten anidación y están limitadas dentro de un espacio de nombres, pero bueno, ahí están para ser utilizadas.


Bloqueos y chequeos
Tenemos dos sentencias que permiten establecer la verificación de los cálculos matemáticos, lo que en ciertas aplicaciones científicas o comerciales pueden ser de gran ayuda. Si colocamos una serie de sentencias dentro de un bloque checked su interior será verificado por el compilador y el entorno de ejecución, generando excepciones en los casos que sea necesario o incluso impidiendo la compilación en los casos en los que la verificación puede comprobarse en tiempo de compilación. Con unchecked hacemos justo lo contrario. Y tenemos estas dos opciones porque podemos decir que nuestro código sea chequeado y tener partes no chequeadas y viceversa en las opciones del proyecto. También hay que tener en cuenta que los bloques verificados se ejecutan más lentos.


Podemos bloquear una variable y ejecutar un bloque de código con dicha variable bloqueada. Es una característica interesante aunque peligrosa si estamos utilizando hilos, porque podríamos bloquear la aplicación indefinidamente si dos hilos bloquean simultáneamente la misma variable, así que hay que andarse con ojo con esta característica, y mejor es utilizar otras opciones de sincronización ofrecidas por el sistema operativo o las bibliotecas de clases.


Me voy
El C# como todo lenguaje que se precie tiene la instrucción goto, aunque aparte del uso ya explicado poco sentido le veo; yo suelo usar goto cuando programo hardware (micros sin sistema operativo, interrupciones físicas, etc.), pero en un lenguaje de alto nivel (o con C/C++ pero en programas de alto nivel) la verdad es que dicha instrucción se desvirtúa.


Usando el uso
Esta característica me gusta poco aunque la considero útil. En mis programas en C++/CLI uso la destrucción determinista, pero en C# no se puede hacer. Para forzar la destrucción de recursos no manejados debemos utilizar la sentencia using, aunque personalmente nunca la he usado… pero no me olvido de cerrar el recurso abierto.


Un ejemplo de libro sobre este uso sería:


Using(TextReader r=File.OpenText(«hola.txt»)) { 
    String s; 
    While((s=r.ReadLine())!=null) { 
        Console.WriteLine(s); 
    }
}


Lo curioso de este ejemplo es que la sentencia while genera un warning en la asignación de s, pero no tiene nada que ver con lo que estamos explicando.

Por fin llegó la cosecha… digo tengo mi ORIGAMI.

Fe de erratas (que no de ratas)
Parece ser que ha habido un fallo de comunicación entre Tella y yo y me comenta que el Samsung tiene las mismas opciones de pantalla que el Asus, y que el Samsung viene con una sola partición.


El Texto Original:
Por fin tengo un ORIGAMI. Bueno, lo tengo desde hace dos semanas, así que ya puedo hablar con conocimiento de causa sobre él. Pero antes os voy a contar la historia de su compra.


El que lea esta bitácora habitualmente recordará una entrada que puse hace tiempo sobre mi intento infructuoso de conseguir un ORIGAMI. Lo cierto es que no ha llovido mucho desde entonces, y parece ser que el retardo sólo venía motivado por la obligatoria adaptación al mercado español que todo aparato debe sufrir, como la traducción de los manuales y la castellanización. Desde hace cosa de dos semanas es habitual ver en muchas tiendas las dos versiones más comunes de estos aparatos: el Asus R2H y el Samsung Q1.


Cansado de pedírselo mi proveedor de hardware y aprovechando un viaje a la capital de las Españas, decidí tomarme un día libre y recorrer unas cuantas tiendas. Y de paso, conocer a algunos impresentables que por aquellas latitudes moran, como Octavio Hernández y José Manuel Tella Llop. Con José quedé a media tarde, y con Octavio para la noche.


Bueno, una vez auto presentarnos, José y yo nos fuimos de tiendas, dimos una vuelta por la fnac y por el corte inglés mientras hablábamos de nuestras cosas; evidentemente, también cayó algún que otro golpecico.


En ambos lugares tenían el Samsung Q1, así que nos dedicamos a cacharrear un poco con él. Ambos quedamos gratamente sorprendidos por el rendimiento del trasto pese a su tamaño y escasas características. Por ejemplo, la carga del acrobat reader 7 apenas tardaba unos segundos, y la pantalla, aunque pequeña, tenía una gran calidad.


Yo quedé en volver al día siguiente, que también lo tenía libre, para adquirir el aparato (más que nada necesitaba ir al banco y sacar la pasta). La tarde y noche continuó desarrollándose a buen ritmo y mejores resultados.


Al día siguiente, tras pasar por caja, el que suscribe se presentó en el centro de Madrid y justo cuando iba a entrar por la puerta de la fnac para comprar el ORIGAMI, lo llama su proveedor de hardware para decirle que el martes recibía el Asus. Tras una conversación bastante insultiva (como tengo confianza con él y le conté lo que estaba a punto de hacer), me di media vuelta y me fui a otros menesteres. Porque la diferencia entre el Samsung en la fnac y el Asus en casa de mi proveedor era de aproximadamente 500 €.


Lo más chocante del caso es que cuando volví a hablar con José me contó que no había podido resistir la tentación y se había comprado el Samsung.


Bueno, pues tras dos semanas de uso de ambos aparatos por parte de José y mía, os voy a contar algunas cosas sobre ellos.


El ORIGAMI
Cuando uno compra uno de estos aparatos conoce de antemano el tamaño de la pantalla por lo que no ha lugar a quejas sobre el, aunque sí sobre su calidad. Parece ser que la pantalla del Samsung es de mayor calidad que la del Asus, ya que en la de éste puede verse la pantalla táctil con una especie de nieve que la recubre. Sin embargo, el Asus soporta más modos de resolución; tenemos la resolución nativa de 800 por 480, y dos más ampliadas de 800 por 600 y 1024 por 768. La ventaja del Asus esta en que dichas resoluciones pueden mostrarse tanto ajustadas al tamaño real de la pantalla como en forma de escritorio virtual en el que la pantalla real es una ventana que se desplaza a lo largo de todo el escritorio. En el Samsung sólo tenemos la segunda opción.


Otro tema un poco delicado es la duración de la batería, con el cacharro a pleno rendimiento apenas aguanta tres cuartos de hora, pero desconectando todos los periféricos y a un brillo de pantalla razonable, la duración se alarga hasta casi las dos horas. Quizá sea éste el peor punto de todos.


El rendimiento está a la altura de las expectativas y a veces lo supera. Enchufado a la red eléctrica o con batería pero al máximo rendimiento la carga de, por ejemplo, Excel, apenas tarda cuatro segundos en ambos modelos, y eso que el Asus sólo tiene 512 MB de RAM mientras que el Samsung llega al giga.


La conexión wi-fi es instantánea, y del bluetooth no puedo decir nada porque todavía no lo he probado. La carga del sistema operativo se hace eterna, pero con las opciones de suspender o de hibernar el encendido del aparato no es demasiado traumático.


Ambos dispositivos traen un disco duro de 60 gigas, y ambos lo traen dividido en dos particiones, una para el sistema operativo y otra para datos.


Más cosas sobre el Asus
Que es el que yo tengo y el que he probado más a fondo. Inicialmente el desempeño del aparato a era desesperante en cuanto a velocidad y a funcionamiento, con algún que otro cuelgue.


Lo primero que hice fue desinstalar toda la morralla del norton con lo que el aparato ganó bastante en rendimiento (Supongo que Symantec pagará a los OEM para que pongan su programa, porque es la única explicación que encuentro para ello). Luego fui mirando todos esos programas chorras que los fabricantes incluyen pensando en que mejoran la experiencia del usuario pero que realmente lo único que hacen es joder la marrana. Al final dejé el Asus Update, el controlador de pantalla de intel sin el cual los modos de pantalla no funcionan correctamente, y el controlador de wi-fi de Asus, que permite apagar y encender tanto el wi-fi como el bluetooth mediante la pulsación de uno de los botones que trae el aparato. También dejé la aplicación de seguridad integrada que permite manejar el ORIGAMI con la huella dactilar.


Tras pasar Windows Update, instalar PerfectDisk y darle un par de pasadas con él, el equipo empezó a funcionar bien de verdad. También le he instalado el Office 2007, y es toda una gozada utilizar el OneNote.


Pero tiene sus pegas. Tras un encendido completo el botón de apagar o suspender no funciona, es necesario suspenderlo por lo menos una vez mediante el menú inicio para que las siguientes suspensiones o hibernaciones se produzcan al pulsar dicho botón. También desaparece a veces el indicador de la batería, lo que me hace pensar que hay algún problema con el sistema de ACPI. Otro detalle más es que, igual que pasa con mi portátil grande, tras diez o doce hibernaciones se le va la cabeza y se hace necesario un reinicio completo (cosa que con mi PC de escritorio no pasa). Otras veces no guarda la configuración de la pantalla. Por lo demás el funcionamiento es impecable. Y me temo que el culpable de todo esto sea el sistema de seguridad de Asus. Ya veremos qué puede más, si pasar el dedo para iniciar la sesión o lo otro.

Trabajar con doble buffer en un Panel

Generalmente cuando trabajo con gráficos suelo pintar sobre el área cliente de la propia ficha, pero esta vez he tenido que hacerlo por narices en un panel.


Activar el sistema de doble buffer de una ficha es muy sencillo, tenemos que cambiar su estilo y aplicarlo. Algo así: 



this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint,true);
this.UpdateStyles();


El primer valor de ControlStyles indica que se va a activar el doble buffer, el segundo que se genere un evento de pintado cuando se redimensione el panel (este valor no es obligatorio pero me hace falta a mi),  y el tercero que todo el pintado se va a realizar en evento Paint (habitualmente el sistema primero pinta el fondo automáticamente en otro evento y luego llama al de pintado).


Pero lo que con una ficha es algo trivial con un Panel es imposible ya que dichos métodos son protegidos y no tenemos acceso a ellos. La solución políticamente correcta consiste en heredar del panel para tener acceso a los miembros protegidos del mismo, pero entonces quitamos la posibilidad de trabajar en el editor visual (a no ser que te crees un componente propio basado en un panel, pero es casi peor el remedio que la enfermedad).


Pero como el menda es bastante políticamente incorrecto, buscando por aquí y por allí ha encontrado un método alternativo mucho más fácil que el anterior, método que consiste en llamar a dichas funciones protegidas mediante el uso de la reflexión (y aquí es donde uno agradece ciertos aspectos del .NET):


 



//Activating DoubleBuffer techniques. We must do it with reflection because Panel.SetStyle is a protected member.
MethodInfo m=typeof(Panel).GetMethod(«SetStyle»,System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
Object[] parameters=new Object[2];
parameters[0]=
new ControlStyles();
parameters[0]=
ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint;
parameters[1] =
new bool();
parameters[1] =
true;
m.Invoke(m_pnlGuachindeil, parameters);
m =
typeof(Panel).GetMethod(«UpdateStyles», System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
m.Invoke(m_pnlGuachindeil,
null);


Siendo justos deberíamos controlar si el valor de m es válido, pero como este código va prefijado si algo falla es que debemos terminar, así que dejamos la salida, el lanzamiento de la excepción y la captura de la misma al sistema (eso si lo hace, cosa que no siempre ocurre como hemos podido ver en alguna entrada anterior).

Un gallinfante de regalo a quien sepa la respuesta

Esta entrada va a ser muy cortita. Es una pregunta dejada al aire, por si alguien la quiere recoger…


Existe la estructura RectangleF, que es un rectángulo con sus coordenadas marcadas en coma flotante.


Existen infinitud de métodos que permiten dibujar y operar con dichas estructuras como elementos de delimitación (DrawString, DrawImage, DrawEllipse, etc, etc…)


Entonces, ¿por qué no existe un método Invalidate que nos acepte un RectangleF?


Evidentemente existe un workaround, y es crear una región a partir de un RectangleF pero ya tenemos que trastear con asignaciones de memoria dentro de lugares en los que cuanto más rápido vayamos, mejor.



miControl.Invalidate(new Region(miRectangleF));

UAC (Usuarios Autistas Carentes de toda razón)


Ya lo dijo no sé quién: la condición humana consiste no estar nunca contento. O dicho de otra forma mucho más políticamente incorrecta, los programadores están intentando hacer programas cada vez más robustos frente a los usuarios, y el universo está haciendo usuarios cada vez más manazas, y por desgracia, de momento quién gana es el universo.


Antes windows era inseguro, o eso se decía, ahora windows es más seguro, o eso se dice. Antes la gente se quejaba porque se les instalaban virus, troyanos y demás fauna maliciosa, sin caer en la cuenta de que la culpa de que eso ocurriera en del propio usuario, o como dice alguien que conozco, el problema está entre la silla y el teclado. Y esto nadie puede discutirlo.


Porque señores, salvo excepciones, todos esos bichitos que pueden convivir en nuestros ordenadores no se instalan solos, sino que requiere la intervención activa del usuario; como poco has de navegar por lugares peligrosos, aceptar cosas que no deberías o instalar toda la mierda que venga en los cds de regalo.


O mejor el típico mensaje de correo cadena en el que se promete un video porno sadomasoquista con un teléfono móvil tremendamente interesante (el vídeo, no el teléfono), el último chiste sobre Bill Gates o el programa de apuestas que te va jubilar.


Pero siempre, siempre, está la intervención del usuario que decide aceptar e instalar. Y que nadie me vengan con cuentos chinos sobre cosas que se instalan solas o que mágicamente aparecen en el escritorio de tu ordenador.


La solución a ello es bien sencilla, y consiste en encontrar un método que impida la instalación automática mediante una simple pulsación de tecla de cualquier software, así como la necesidad de implementar algún sistema activo para que cuando se vaya a realizar una acción potencialmente crítica en un equipo el usuario sea consciente de que se está metiendo en camisa de once varas.


La solución clásica de windows y de la mayoría de los sistemas operativos consiste tener al menos 2 tipos de cuentas: aquellas en las que es posible realizar cualquier acción y otras en las que se impida activamente el poder destrozar cualquier cosa. Pero este modelo tiene una contrapartida en equipos de escritorio y para usuarios avanzados, y es que hay que estar continuamente cambiando de usuario ante ciertas tareas, lo que a veces resulta bastante tedioso y pesado.


Linux lo soluciona mediante la promoción automática del programa previo introducción de la clave de acceso de administrador; y muchas distribuciones vienen preparadas para no tener que hacer otra cosa más que introducir dicha clave.


Windows Vista lo soluciona de una manera similar pero mucho más elegante y sencilla. Es lo que se llama UAC. Mediante este sistema cuando vamos a hacer una tarea potencialmente peligrosa la pantalla se oscurece y windows nos pregunta si realmente queremos realizar tal acción. Un simple clic de ratón o la pulsación de una flecha y enter aceptan la acción, pero lo importante es que de ninguna manera podemos ignorar que vamos a realizar una acción potencialmente peligrosa. No valen justificaciones como que » no me he dado cuenta de que el mensaje preguntaba eso», » no me ha dicho nada», » es que estaba pensando en otra cosa».


El cambio de contexto que se produce dentro del ordenador es tan brutal que no deja lugar a dudas de que se va a realizar una acción peligrosa, y quizá sea eso lo que disguste en gran medida la mayoría de la gente, pero es una efectiva forma de llamar la atención. Sería equivalente a vivir en una cueva hace un millón de años y estar comiéndonos una chuleta tan tranquilamente, levantar la vista, y ver a un león acechándonos.


Pero lo queremos todo, queremos que nuestro windows sea seguro pero no queremos tomar medidas para ello, somos unos inconformistas de tomo y lomo, incapaces de ver lo que tenemos delante de las narices, y menos aún comprender que el único modo de evitar que cometamos pifias por nuestra propia estupidez es disponer de un sistema parecido al UAC. Y si Windows Vista te pregunta continuamente cada vez que abres o cambias de sitio uno de tus documentos ve pensando en hacer un curso de informática para enterarte de algunas cosas…


Quizás no sea el el mejor sistema de todos, pero lo prefiero por encima del de Linux, no veas lo que jode estar todo el día que tecleando una clave de acceso cada diez minutos. Porque Señores, si no se han dado cuenta, el funcionamiento bajo Linux es ese.


Estamos tan embebidos en nuestra propia estulticia que somos incapaces de reconocer una buena idea aunque provenga de lo que algunos llaman el lado oscuro de la informática; porque a ver una cosa, señores, todos esos que os quejais de que el UAC es como una mosca cojonera, despotricais por tener que mover el ratón unos centímetros o por pulsar dos teclas, decidme, ¿existe otra manera más sencilla de hacerlo? Al que no le guste que proponga una idea mejor.


Es muy bonito eso de despotricar de forma descerebrada sin detenerse ni un segundo a pensar las tonterías que se están diciendo. Cualquiera con dos dedos de frente se da cuenta de que es la única forma de evitar que el usuario compulsivo (por no decir tonto) se vea cogido en sus propias redes. No me refiero a la forma en que el UAC lo hace, sino a la necesidad de tener que preguntarle al usuario si está seguro de la tontería que va a cometer. Y la forma en que el UAC lo hace es, a mi modo de ver, la mejor de todas las posibles dentro de un entorno doméstico.


Y si no estáis de acuerdo, proponed una mejor.

La máquina virtual NET está podrida por dentro, 1

Esto ya clama al cielo. Al que me contradiga me lo como con patatas. Estoy hasta los mismísimos del .NET. Así de claro, y dado que por aquí hay filtro de contenidos, la VM .NET es una p*t* m**rd* pinchada en un palo. Así de sencillo. Y lo voy a demostrar con esta serie de artículos. A ver si se espabilan de una vez. Y a ver si aprenden a hacer las cosas bien. [Por cierto, si convenzo a mi jefe voy a girar una factura de una mañana completa mía a Microsoft, por la pérdida de tiempo que me ha ocasionado esto].

 A ver. Tomemos el siguiente código en C#:

Retangle[] m_arrowsRect=null;
float
xx = m_toppersRect[iTopper].Width / m_bitmap.Width * k_originalArrows[0].X;
float yy = m_toppersRect[iTopper].Height / m_bitmap.Height * k_originalArrows[0].Y;
m_arrowsRect[0] =
new RectangleF(xx + k_originalArrows[0].X, yy + k_originalArrows[0].Y, m_arrows[0].Width, m_arrows[0].Height);
m_arrowsRect[1] =
new RectangleF(xx + k_originalArrows[1].X, yy + k_originalArrows[1].Y, m_arrows[1].Width, m_arrows[1].Height);
m_arrowsRect[2] =
new RectangleF(xx + k_originalArrows[2].X, yy + k_originalArrows[2].Y, m_arrows[2].Width, m_arrows[2].Height);
m_arrowsRect[3] =
new RectangleF(xx + k_originalArrows[3].X, yy + k_originalArrows[3].Y, m_arrows[3].Width, m_arrows[3].Height);

Compilemos con AnyCPU y ejecutemoslo dentro de un evento SizeChanged en de una ficha. Ejecutemos en un Vista x64. ¿Qué ocurre? Pues nada, que el código llega a la primera asignación de m_arrowsRect y termina la ejecución del método sin más, sin excepciones ni nada.

Ahora compilemos con x86. ¿Qué ocurre? Se lanza una excepción en la primera asignación de m_arrowsRect.

m_arrowsRect no es una variable local (aunque lo haya puesto aquí por simplicidad), sino un miembro de la ficha. Cuando llegamos a Paint, el valor siguie siendo nill, en AnyCPU la aplicación se ejecuta sin pintar la parte que se corresponde a m_arrowsRect, pero no peta. En x86 sí, como es lógico.

Sin comentarios. Mañana, más.

ADDENDA
Para quien quiera probarlo: aquí un proyecto de demo. Este desde fuera del IDE peta, pero desde dentro funciona sin disparar las excepciones. En un Vista RTM x64 con el IDE ejecutando en modo Administrador.

NUEVA ADDENDA

Quizás escriba mal, pero creo que el tema está lo suficientemente claro: el código mal escrito, ejecutado en un Vista x64 desde el IDE y compilado con AnyCPU

NO GENERA NINGUNA EXCEPCIÓN

Y debería generar una, tal como lo hace si se compila con x86.

Y AHORA EN VIDEO
Pues es, lo he grabado en vídeo. El problema es que no se ve muy claro (es una cámara de fotos, no tengo otra cosa), pero se puede ver cómo no falla en AnyCPU y cómo falla en x86… Sinceramente estoy hartito de las risas bajo manga, como si no me enterara de qué va la cosa. Pero ahí está, fallando y grabado en vídeo. El que quiera está invitado a venir a verlo.

Aps, el vídeo, aquí. He puesto dos más en los que se ve algo más claro: aqui y aquí (está partido porque se me ha ido el dedo del botón de la cámara).