Más sobre el tipo PChar

julio 17, 2006 en Enlace interesante, Entrada Diario

Tomad nota del siguiente enlace:
http://spanish.joelonsoftware.com/Articles/BacktoBasics.html

Lo he copiado de la web de Jose Manuel Navarro (si quereis visitar sus páginas, -cosa altamente recomendable- su link figura en el panel de enlaces). Jose, con quien sabeis por referencias anteriores me une una buena amistad, ya me lo reseñó en correo anteriores. El me dió a conocer las páginas de Joel Spolsky, que sin duda son una buena muestra de lo interesante que puede ser este tipo de webs, aunque no mantengan código fuente.

El enlace que os he indicado es una traducción al castellano, hecha por el mismo Jose Manuel Navarro, y en ella se aborda la problematica de los PChars, planteado desde el mismo origen, C.

No obstante, si finalmente lo leeis, os aconsejo una lectura del resto de artículos de Joel Spolsky.

Una cosa que se suele acabar descubriendo es que ni todas las web que mantienen codigo fuente en internet son buenas (una gran mayoría se dedican a copiar el codigo de otras sin aportar nada propio) ni todas las que mantinen “experiencia” son malas… La experiencia es algo que no se puede comprar… ¡recordadlo!

Ya conocéis el refrán: “sabe mas el diablo por viejo que por diablo!”.

Despiste…

julio 13, 2006 en Advertencia, Consejo, Delphi, Entrada Diario

Muchas de las entradas de la bitácora son casi anecdóticas, como ya estáis adivinando. Quiero decir que una buena parte dependen del azar. Casi siempre surgen como respuesta a algún problema del día, o algún correo del foro que ha sido llamativo y ha terminado incitando a dejar el recuerdo de lo leido. Esa es la idea, mas o menos.
Hoy, como otros días, ha sido tranquilo. El verano tiene esas cosas. Muchas empresas que te pueden llamar andan aletargadas, preparando las esperadas vacaciones, y entretanto, parece que se presta la ocasión para retomar temas pendientes, en los que uno no suele tener demasiado tiempo para abordar. Así que llevo unas semanas con varios temas abiertos sobre mi mesa de escritorio:

Por un lado, UML y patrones de diseño aplicados a esta metodología. Concretamente, estoy leyendo un libro de Craig Larman, ‘UML y Patrones’, de la editorial Prentice Hall. Ese libro se me está haciendo eterno… :-( Es culpa mía… ya que suelo aprovechar la noche, antes de dormir, para leer alguna que otra página, y como es previsible… siempre me quedo dormido en la misma… :-) Tras varios días, tengo que hacer un esfuerzo para adelantar unas cuantas páginas porque es algo aburrido. ¡Aburridísimo y demasiado formal!… Así que me paro a pensar que es lo que ya he leido del libro… ¡y ya ni me acuerdo! :-)

Otro tema que tengo abierto en mi escritorio, es la creación de un pequeño framework (creo que ya lo comenté en alguna entrada anterior), solo que en lugar de abordarlo mediante la arquitectura de dos capas, cliente-servidor, que es la que utilizo habitualmente, me he empeñado en rehacerlo desde la perspectiva de DataSnap, que añade una tercera capa a la comunicación (cliente-servidor). Tengo bastante avanzado el tema y la idea principal, es simplemente crearme un marco de trabajo que me facilite la creción de las clásicas ventanas de altas/bajas/modificaciones. Cuando compré el último libro de Marteens, “La cara oculta de C#”, el autor tuvo el detalle de proporcionarme un dvd con ejercicios del curso de DataSnap. Es de bien nacido ser agradecido, que dice el refran, y no tengo reparo en decir que, como todo lo que escribe, “vale la pena”. No estoy haciendole publicidad porque no la necesita. Los ejercicios son bastante didácticos y entretenidos, y gracias a ellos, he podido comprender muchos detalles que se me escapaban de DataSnap.

Y el último tema que siempre está abierto son estás páginas. Todos los días me pregunto que puedo contar que le pueda interesar a la persona que se inicia en Delphi. Creo que ya se entiende que todo esto que escribo no va dirigido a los programadores avanzados… :-) Hoy por ejemplo he tenido un despiste “imperdonable” para una persona que lleva varios años programando en este entorno. Si lo pienso bien me da hasta la risa TONTA… ;-) Resulta que habia añadido unos objetos al interfaz gráfico. Exactamente se trataba de unos botones (llamemoslos así) generados por una clase similar a la TToolBar. Dicha clase, publicaba una propiedad booleana que permitía almacenar en el registro el estado de los componentes de la barra, en tiempo de ejecución para que el usuario pudiera personalizarla. Pues bueno… he pasado bastantes horas mareado tratando de descubrir porque razón en tiempo de diseño visualizaba los componentes, y en tiempo de ejecución habian varios que no, a pesar de que no había motivo alguno para que los escondiese. A toro pasado la solución era evidente, ya que anteriormente había sufrido un problema similar, sin embargo, mientras analizaba el problema, todo me inducía a pensar que el problema era de otra indole menos vulgar… :-D (jeje) Se trataba simplemente que algunos de los componentes se habían añadido, justo despues de haber activado la persistencia de la clase por lo que cada vez que ejecutaba, cargaba unicamente lo que encontraba en el registro e ignoraba lo añadido al interfaz…
Cuando me he dado cuenta he pensado… ¡seré imbecil…!

Muchos de los problemas a los que se enfrenta el programador que se inicia son similares a éste, como pequeñas trampas que uno tiene que superar: y una vez escaldado, sepa donde no tiene que pisar… :-)
Marcaba Neil J. Rubenking allá en los tiempo de Delphi 2, diez errores habituales que nos asaltaban en esos primeros pasos. Yo ahora solo voy a marcar algunos que me vienen a la cabeza y que recuerdo incluso a pesar de que han pasado tantos años desde que lo leí:

  • Los errores de cercado… Hacía referencia a las todos aquellos errores originados por acceder con un índice fuera del rango a una matriz. También a los errores en los bucles, en aquellos programadores que incorrectamente calculaban la condicion de finalización.
  • Instrucciones vacias y puntos y comas sobrantes… un punto y coma olvidado puede finalizar anticipadamente una sentencia… algo asi como poner:
for i:= 0 to 10 do;  <----- Desastre...
MiMatriz[i]:= 0;
  • La coma flotante. Un problema real que cualquier programador con experiencia no infravalora. Redondeos y descuadres. Y en los primerizos querer hacer comparaciones entre expresiones decimales… que te hacen descubrir la basura que encierra un tiparraco de esa calaña.
  • Olvidar el resultado de una función… Ya. Una función siempre devuelve un valor o casi siempre… En nuestros primeros pasos, suele ser habitual crear una implementación que pueda en determinadas circunstancias dejar indefinido el valor de retorno… así que siempre ¡cuidado!.
  • Apilando errores… Aquellas situaciones que crean bucles que se ejecutan infinitas veces, llamadas recursivas que no finalizan salvo que el usuario acabe golpeando el equipo con la primera silla que encuentre a mano… Desbordamientos de pila… Gracias a Dios, estos problemas estan bastante mejor enfocados ahora, con la perspectiva de Xp.
  • * Y por último el uso de los PChars, que todavía siguen siendo necesarios en bastantes ocasiones…

Estoy completamente convencido de que detrás de un día de lluvia siempre acaba escampando, así que si tienes un mal día y el programa se obstina en hacer lo que el quiere y no lo que tu le pides…, no lo tomes a mal… esto es así: sal a que te pegue un rato el aire (seguro que hace un día estupendo), lee un buen libro, un poco de deporte tampoco te vendrá mal, y sobretodo, diviertete programando.

El cortador de líneas

julio 11, 2006 en Delphi

Esta noche anterior, leía el último artículo de Nico Aragon que publicaba en su bitácora:
El cortador de lineas
y tras analizar el código, le hice algunos comentarios que me parecían de interés. De hecho, he leido su respuesta y creo que estamos básicamente de acuerdo en lo de objetos “inteligentes o tontos”, o como el llama “activos o pasivos”. Lo de menos es quizás el nombre sino el concepto que queda en el transfondo.
Acabo de modificar un poquito su código para que si algún compañero no lo ve, pueda apreciar la distinción a la que me refiero.

En el caso de esta unidad, la invocación del proceso cortador de lineas se haría mas o menos así, con la modificación o variación propuesta:

Cutter := TLineCutter.Create(//aquí el parámetro de tipo string);
try
  Cutter.OnNewLine := AddLine;
  Cutter.Start;
finally
  Cutter.Free;
end;

La diferencia entre un objeto u otro, es simplemente sobre quien recae la responsabilidad del analisis y de determinar cuando ha finalizado. Relacionado con este punto, he suprimido el estado de finalización por una función de control Eof, que le indica al objeto cuando ha finalizado el análisis.
Realmente hacen los dos objetos, el de Nico, o esta variación exactamente lo mismo, y responden los dos al mismo diagrama de estados que planteó como fondo de su propuesta.

Lo dificil en todos estos casos, no es plantear modificaciones, sino esa primera fase de análisis del algoritmo. A posteriori, siempre es relativamente fácil encontrar optimizaciones sobre algo que ya tienes planteado previamente. Y en ese sentido, le doy toda la razón a Nico cuando explica en las primeras lineas de su artículo, la necesidad de apoyarnos en razonamientos formales, como pueda ser un diagrama de estados para la implementación de un algoritmo determinado.

//variacion de la unidad LineCutters

//******************************
unit LineCutters;

interface

type

TOnNewLineEvent = procedure(const Line: string) of object;
TNotifyEvent = procedure(Sender: TObject) of object;
TLineCutterState = (stText, stCR, stCRLF, stLF);

TLineCutter = class
private
 Buffer: String;
 FIndex: Integer;
 FActive: Boolean;
 FOnFinish: TNotifyEvent;
 FOnNewLine: TOnNewLineEvent;
protected
 FTexto: string;
 State: TLineCutterState;
 procedure Process(const c: Char);
 procedure ReportLine;
 procedure DoProcess; virtual;
 procedure DoFinish; virtual;
 function EOF: Boolean;
public
 constructor Create(const ACadena: String); virtual;
 procedure Start;
 property Active: Boolean read FActive;
 property OnNewLine: TOnNewLineEvent read FOnNewLine write FOnNewLine;
 property OnFinish: TNotifyEvent read FOnFinish write FOnFinish;
end;

implementation

uses SysUtils;

{ TLineCutter }

constructor TLineCutter.Create(const ACadena: String);
begin
  inherited Create;
  FActive := False;
  FTexto := ACadena;
  State := stText;
end;

function TLineCutter.EOF: Boolean;
begin
  Result:= FIndex > Length(FTexto);
end;

procedure TLineCutter.Process(const c: Char);
begin
  case State of

    stText: begin
              if c = #13 then begin
                ReportLine;
                State := stCR;
              end else if c = #10 then begin
                ReportLine;
                State := stLF;
              end else begin
                Buffer := Buffer + c;
              end;
            end;

    stCr:   begin
              if c = #13 then begin
                ReportLine;
              end else if c = #10 then begin
                State := stCRLF;
              end else begin
                Buffer := Buffer + c;
                State := stText;
              end;
            end;

    stLf:   begin
              if c = #13 then begin
                ReportLine;
                State := stCR;
              end else if c = #10 then begin
                ReportLine;
                State := stLF;
              end else begin
                Buffer := Buffer + c;
                State := stText;
              end;
            end;

    stCRLF: begin
              if c = #13 then begin
                ReportLine;
                State := stCR;
              end else if c = #10 then begin
                ReportLine;
                State := stLF;
              end else begin
                Buffer := Buffer + c;
                State := stText;
              end;
            end;
  end;
end;

procedure TLineCutter.DoProcess;
begin
  //prevenimos que no se pueda invocar si está en proceso
  FActive:= True;
  FIndex:= 1;
  Buffer:= '';
  while not Eof do begin
    Process(FTexto[FIndex]);
    Inc(FIndex);
  end;
  if Buffer <> '' then ReportLine;
  //marcamos el final del algoritmo
  FActive:= False;
end;

procedure TLineCutter.ReportLine;
begin
  if Assigned(FOnNewLine) then FOnNewLine(Buffer);
  Buffer := '';
end;

procedure TLineCutter.DoFinish;
begin
  if Assigned(FOnFinish) then FOnFinish(self);
end;

procedure TLineCutter.Start;
begin
  if FActive then Raise Exception.Create('TLineCutter: In process');
  DoProcess;
  DoFinish; //comunicamos al usuario que el algoritmo finalizó
end;

end.

Sobre el creador de Delphi

julio 5, 2006 en Enlace interesante, Entrada Diario

Hace un par de días, he encontrado en uno de los foros una referencia a una entrevista que concedió Anders Hejlsberg en el año 2001, casualmente traducida al español. El enlace me ha parecido interesante, y tras leerlo, he pensado en compartirlo con vosotros. A fin de cuentas, es el padre o uno de los padres de nuestro Delphi.
La entrevista no tiene desperdicio y en ella se tocan numerosos temas, casi siempre girando alrededor de la plataforma .NET.
Lo podeis leer en:
Entrevista a Anders Hejlsberg

Mientras lo leía, pensaba para mi, en tono de asombro, en la gran cantidad de conocimientos que manejan estas personas, estos genios, que de alguna forma acaban marcando una estela a seguir…

¡Cuanta gente debe estar involucrada en este tipo de proyectos! Ufffff… Me cuesta imaginarme como puede ser el día a día en un proyecto de la magnitud de los abordados por Hejlsberg…