Logo

Marco Cantù
Pascal Esencial

Capítulo 5 Actualizar
Instrucciones

Si los tipos de datos forman una de las bases de la programación en Pascal, la otra la forman las instrucciones. Las instrucciones de este lenguaje de programación están basadas en palabras clave (keywords) y otros elementos que permiten indicarle a un programa una sucesión de operaciones a realizar. Las instrucciones a menudo se encierran en procedimientos o funciones, como veremos en el capítulo siguiente. Ahora, nos ceñiremos al estudio de tipos básicos de comandos que pueden usarse para crear un programa.


Instrucciones simples y compuestas

Una instrucción en Pascal es simple si no contiene otras instrucciones. Ejemplos de instrucciones sencillas son las de asignación y las de llamada a procedimientos. Las instrucciones simples se separan con punto-y-comas :

X := Y + Z;  // asignación
Randomize;   // llamada a un procedimiento

Normalmente, las instrucciones se agrupan en instrucciones compuestas, delimitadas por los comandos begin y end. Una instrucción compuesta puede aparecer en lugar de una instrucción en Pascal, genérica. Sigue un ejemplo :

begin
  A := B;
  C := A * 2;
end;

El punto y coma tras la última instrucción previa al end no es imprescindible, como se ve aquí :

begin
  A := B;
  C := A * 2
end;

Ambas versiones son correctas. La primera incluye un punto y coma innecesario (pero inofensivo). El punto y coma es, de hecho, una instrucción nula, una instrucción sin código. Dése cuenta de que, a veces, las instrucciones nulas pueden ser utilizadas dentro de bucles, o en otros casos particulares.

Nota: Aunque estos punto-y-comas finales no tienen finalidad, tiendo a usarlos, y le sugiero que haga lo mismo. A veces, tras escribir un cierto número de líneas, podría necesitar añadir otra. Si el último punto y coma fue omitido en primera instancia, tendrá que añadirlo después, y esto resulta algo más engorroso que ponerlo desde un principio.


Instrucciones de asignación

Las asignaciones en Pascal usan el operador formado por dos puntos seguidos por el signo 'igual', una notación extraña para programadores acostumbrados a otros lenguajes. El operador =, utilizado para asignar valores en otros lenguajes de programación, se usa en Pascal para comprobar la igualdad de dos valores.

Nota: Al usar distintos símbolos para asignación y para prueba de igualdad, el compilador de Pascal (como el de C) puede traducir código fuente más rápidamente, porque no necesita examinar el contexto en que el operador se utiliza, para determinar su significado. El uso de dos operadores diferentes también hace que el código sea más fácil de leer al ser humano.

Instrucciones condicionales

Una instrucción condicional se usa para ejecutar bien una de las instrucciones que incluye o ninguna, dependiendo de cierta comprobación. Hay dos tipos básicos de instrucciones condicionales: instrucciones if e instrucciones case.

Instrucciones If

La instrucción if puede usarse para ejecutar una instrucción sólo si se cumple una cierta condición (if-then; si...entonces), o para elegir entre dos alternativas (if-then-else; si...entonces..., y, si no, ...) La condición viene expresada mediante una expresión Booleana. Un ejemplo sencillo en Delphi puede mostrar cómo escribir instrucciones condicionales. Primero, cree una aplicación nueva, y coloque dos casillas de selección y cuatro botones en el formulario. No cambie los nombres de los botones o las casillas de selección, sino haga doble clic en cada botón para añadir un gestor de eventos para el evento OnClick correspondiente. He aquí una instrucción if sencilla para el primer botón :

procedure TForm1.Button1Click(Sender: TObject);
begin
  // simple if statement
  if CheckBox1.Checked then
    ShowMessage ('CheckBox1 is checked')
end;

Cuando pulse botón, si la primera casilla de selección lleva un signo de activación, el programa mostrará un breve mensaje (vea la Figura 5.1). He usado la función ShowMessage porque es la función Delphi más sencilla que puede usar para mostrar un mensaje breve al usuario.

Figura 5.1: El mensaje mostrado por el ejemplo IfTest cuando se pulsa el primer botón y la primera casilla de selección está activada.

Si pulsa el botón y no pasa nada, significa que la casilla no había sido activada. En un caso así, probablemente sería mejor hacer esto más explícito, como con el código para el segundo botón, que usa una instrucción if-then-else :

b>procedure TForm1.Button2Click(Sender: TObject);
begin
  // instrucción if-then-else
  if CheckBox2.Checked then
    ShowMessage ('La casilla CheckBox2 está activada')
  else
    ShowMessage ('CheckBox2 NO está activada');
end;

Dése cuenta de que no puede colocar un punto y coma entre la primera instrucción y la palabra clave else, o el compilador mostrará un error de sintaxis. De hecho, la instrucción if-then-else, de hecho, es una sola instrucción, así que no puede colocar un punto y coma en medio de ella.

Una instrucción if puede ser bastante compleja. La condición puede ser convertida en una serie de condiciones (usando los operadores Booleanos and, or y not), o bien la instrucción if puede incluir otra instrucción if. Los dos últimos botones del ejemplo IfTest muestran estos casos :

procedure TForm1.Button3Click(Sender: TObject);
begin
  // instrucción de doble condición
  if CheckBox1.Checked and CheckBox2.Checked then
    ShowMessage ('Ambas casillas están activadas')
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  // instrucción if compuesta
  if CheckBox1.Checked then
    if CheckBox2.Checked then
      ShowMessage ('Las casillas 1 y 2 están activadas')
    else
      ShowMessage ('Sólo la casilla 1 está activada')
  else
    ShowMessage (
      'La casilla 1 no está activada. ¿A quién le importa la 2?')
end;

Observe detenidamente el código y ejecute el programa, para ver si lo entiende todo. Cuando tenga dudas sobre la conformación de un programa, escribir un programa muy simple como este, puede ayudarle a aprender mucho. Puede añadir más casillas de selección y aumentar la complejidad de este breve ejemplo, haciendo todas las pruebas que necesite.

Instrucciones Case

Si sus instrucciones if se hacen muy complejas, a veces puede reemplazarlas con instrucciones case. Una instrucción case consiste en una expresión usada para seleccionar un valor, una lista de posibles valores, o una gama de valores. Estos valores son constantes, y deben ser únicos y de tipo ordinal. Finalmente, puede haber una instrucción else que sea ejecutada si ninguna de las etiquetas se corresponde con el valor del selector. Siguen dos ejemplos sencillos :

case Number of
  1: Text := 'Uno';
  2: Text := 'Dos';
  3: Text := 'Tres';
end;

case MyChar of
  '+' : Text := 'Signo más';
  '-' : Text := 'Signo menos';
  '*', '/': Text := 'Multiplicación o división';
  '0'..'9': Text := 'Número';
  'a'..'z': Text := 'Minúscula';
  'A'..'Z': Text := 'Mayúscula';
else
  Text := 'Carácter desconocido';
end;

Bucles en Pascal

El lenguaje Pascal tiene las instrucciones recursivas típicas de la mayoría de lenguajes de programación, incluyendo las instrucciones for, while y repeat. La mayoría de lo que hacen estos bucles le resultará familiar si conoce otros lenguajes de programación, por lo que los comentaré muy brevemente.

El bucle For

Este tipo de bucle, en Pascal, está basado estrictamente en un contador, que puede ser incrementado o decrementado, cada vez que se ejecuta el bucle.
He aquí un ejemplo sencillo de un bucle for que se usa para añadir los primeros diez números.

var
  K, I: Integer;
begin
  K := 0;
  for I := 1 to 10 do
    K := K + I;

Esta misma instrucción for podría haber sido escrita usando un contador inverso :

var
  K, I: Integer;
begin
  K := 0;
  for I := 10 downto 1 do
    K := K + I;

El bucle for es menos flexible en Pascal que en otros lenguajes (no es posible especificar un incremento distinto de uno), pero es sencillo y fácil de entender. Si quiere incorporar una comprobación más compleja, o proporcionar un contador personalizado, necesitará usar una instrucción while o repeat, en vez de un bucle for.

Nota: El contador de un bucle for no tiene por qué ser un número. Puede ser un valor de cualquier tipo ordinario, como un carácter o un tipo enumerado.

Instrucciones While y Repeat

La diferencia entre el bucle while-do (mientras ... haz) y el bucle repeat-until (repite ... hasta que) consiste en que el código de la instrucción repeat se ejecuta siempre al menos una vez. Puede comprender fácilmente por qué, observando un ejemplo sencillo :

while (I <= 100) and (J <= 100) do
begin
  // usamos I y J para calcular algo ...
  I := I + 1;
  J := J + 1;
end;

repeat
  // usamos I y J para calcular algo ...
  I := I + 1;
  J := J + 1;
until (I > 100) or (J > 100);

Si el valor inicial de I o J es mayor que 100, las instrucciones en el interior del bucle repeat-until son ejecutadas una vez, a pesar de ello.

La otra diferencia clave entre estos dos bucles es que el bucle repeat-until incluye una condición inversa. El bucle se ejecuta mientras la condición no se cumpla. Cuando sí lo hace, el bucle finaliza. Esto es lo contrario de lo que pasa con un bucle while-do, que se ejecuta mientras la condición sea cierta. Por esta razón tuve que invertir la condición en el código que aparece arriba, para obtener una instrucción equivalente.


Un ejemplo de bucles

Para explorar los detalles de los bucles, echemos un vistazo a un pequeño ejemplo en Delphi. El programa Loops destaca la diferencia entre un bucle con contador fijo y otro con un contador casi aleatorio. Comience con un proyecto nuevo, coloque una casilla de lista (listbox) y dos botones en el formulario principal, y déle a los botones un nombre propio (BtnFor y BtnWhile), estableciendo su propiedad Name en el Object Inspector. También puede quitar la palabra Btn de la propiedad Caption (e, incluso, finalmente, añadirle el carácter & para activar la siguiente letra como tecla de acceso directo). Aquí aparece lo más importante de la descripción en código de tal formulario :

object Form1: TForm1
  Caption = 'Loops'
  object ListBox1: TListBox ...
  object BtnFor: TButton
    Caption = '&For'
    OnClick = BtnForClick
  end
  object BtnWhile: TButton
    Caption = '&While'
    OnClick = BtnWhileClick
  end
end

Figura 5.2: Cada vez que pulse el botón For del ejemplo Loops, la casilla de lista se llena con números correlativos.

Ahora podemos añadir algo de código a los eventos OnClick de sendos botones. El primero de ellos incluye un sencillo bucle for para representar una lista de números, como se ve en la Figura 5.2. Antes de ejecutar este bucle, que añade un cierto número de cadenas a la propiedad Items de la casilla de lista, es necesario eliminar el contenido de la casilla misma :

procedure TForm1.BtnForClick(Sender: TObject);
var
  I: Integer;
begin
  ListBox1.Items.Clear;
  for I := 1 to 20 do
    Listbox1.Items.Add ('String ' + IntToStr (I));
end;

El código asociado con el segundo botón es un poco más complejo. En este caso, hay un bucle while basado en un contador, que se va incrementando de forma aleatoria. Para conseguir esto, he efectuado una llamada al procedimiento Randomize, que inicializa el generador de números aleatorios, y la función Random, con una gama de 100 valores. El resultado de esta función es un número entre 0 y 99, elegido al azar. La sucesión de números aleatorios controla cuántas veces se ejecuta el bucle while.

procedure TForm1.BtnWhileClick(Sender: TObject);
var
  I: Integer;
begin
  ListBox1.Items.Clear;
  Randomize;
  I := 0;
  while I < 1000 do
  begin
    I := I + Random (100);
    Listbox1.Items.Add ('Random Number: ' + IntToStr (I));
  end;
end;

Cada vez que pulse el botón While, los números son distintos, porque dependen del generador de números aleatorios. La Figura 5.3 muestra los resultados de dos clics de botón distintos. Observe que no sólo cambian los números generados de una vez a otra, sino también el número de elementos. Esto es, este bucle while se ejecuta un número aleatorio de veces. Si pulsa el botón While varias veces seguidas, verá que la casilla de lista tiene un número distinto de líneas.

Figura 5.3: El contenido de la casilla de lista del ejemplo Loops cambia cada vez que se pulsa el botón While. Como el contador de bucle se incrementa con un valor aleatorio, cada vez que pulse el botón, el bucle se ejecuta un número distinto de veces.mes.


Nota: Se puede alterar el flujo normal de la ejecución de un bucle, usando los procedimientos de sistema Break y Continue.
El primero interrumpe el bucle; el segundo se usa para saltar directamente a la comprobación del bucle o al incremento del contador, siguiendo con la siguiente iteración del bucle (a no ser que la condición sea cero, o que el contador haya llegado a su máximo valor). Otros dos procedimientos de sistema, Exit y Halt, le permiten volver inmediatamente de la función o el procedimiento actual o finalizar el programa.


La instrucción With

El último tipo de instrucción Pascal que comentaré es la instrucción with, que es específica de este lenguaje de programación (introducida recientemente en Visual Basic), y muy útil en la programación Delphi.

La instrucción with no es otra cosa que una abreviatura. Cuando necesite referirse a una variable de tipo registro (record) o a un objeto, en vez de repetir su nombre cada vez, puede usar una instrucción with. Por ejemplo, al presentar el tipo record, escribí este código :

type
  Date = record
    Year: Integer;
    Month: Byte;
    Day: Byte;
  end;

var
  BirthDay: Date;

begin
  BirthDay.Year := 1997;
  BirthDay.Month := 2;
  BirthDay.Day := 14;

Mediante la instrucción with puedo mejorar la parte final de este código, como sigue :

begin
  with BirthDay do
  begin
    Year := 1995;
    Month := 2;
    Day := 14;
  end;

Este enfoque puede ser usado en progamas Delphi para referirse a componentes y otros tipos de clases. Por ejemplo, podemos reescribir la última parte del ejemplo anterior a este, usando una instrucción with para acceder a los elementos de la casilla de lista :

procedure TForm1.WhileButtonClick(Sender: TObject);

var
  I: Integer;
begin
  with ListBox1.Items do
  begin
    Clear; // acceso directo
    Randomize;
    I := 0;
    while I < 1000 do
    begin
      I := I + Random (100);
      // shortcut:
      Add ('Random Number: ' + IntToStr (I));
    end;
  end;
end;

Cuando trabaje con componentes o clases en general, la instrucción with le permitirá ahorrarse algo de código, en especial para campos anidados. Por ejemplo, suponga que necesita cambiar la anchura (Width) y el Color del lápiz de dibujo para un formulario. Puede aplicar el siguiente código :

Form1.Canvas.Pen.Width := 2;
Form1.Canvas.Pen.Color := clRed;

Pero, ciertamente, es más fácil escribir este otro :

with Form1.Canvas.Pen do
begin
  Width := 2;
  Color := clRed;
end;

Cuando se escribe código complejo, la instrucción with puede ser efectiva, y le ahorra la declaración de algunas variables temporales, pero tiene una desventaja. Puede hacer que el código sea más ilegible, en especial si está trabajando con distintos objectos que tienen propiedades similares o correspondientes entre sí.

Otra desventaja es que usar la instrucción with puede permitir la aparición de sutiles errores lógicos en el código, que el compilador no detectará. Por ejemplo :

with Button1 do
begin
  Width := 200;
  Caption := 'New Caption';
  Color := clRed;
end;

Este código cambia el Caption y el Width del botón, pero afecta a la propiedad Color del formulario, ¡no del botón! La razón es que los componentes TButton no tienen propiedad Color, y, como el código se ejecuta para un objeto que forma parte de un formulario (estamos escribiendo un método para éste), se accede a este objeto por defecto. Si hubiéramos escrito, en su lugar ...

Button1.Width := 200;
Button1.Caption := 'New Caption';
Button1.Color := clRed; // error!

... el compilador habría mostrado un mensaje de error. En general, se puede decir que, como la instrucción with introduce nuevos identificadores en el ámbito actual, podríamos esconder identificadores presentes, o acceder por error a identificadores que se encuentran en el mismo ámbito (como en la primera versión de este fragmento de código). Incluso considerando este tipo de desventaja, le sugiero que se acostumbre a las instrucciones with, porque pueden ser realmente manejables, y a veces aun hacen que el código sea más legible.

De cualquier manera, debería evitar usar instrucciones múltiples, como :

with ListBox1, Button1 do...

El código que siguiese a esto sería, probablemente, muy ilegible, porque para cada propiedad definida en este bloque, tendría que plantearse a qué componente afecta, dependiendo de las propiedades respectivas y del orden de los componentes en la instrucción with.

Nota: Hablando de legibilidad, Pascal no tiene instrucción alguna de tipo endif ó endcase. Si una instrucción if incluye un bloque begin-end, el final de tal bloque marca el fin de esa instrucción. Por su parte, la instrucción case siempre acaba en end. Todas estas instrucciones end, que a menudo se encuentran una tras otra, pueden hacer que el código sea difícil de seguir. Sólo siguiendo las sangrías en el código se puede ver a qué instrucción afecta un end en particular. Una forma habitual de resolver este problema y hacer el código más legible es añadir un comentario tras la instrucción end, indicando su papel, como en :

if ... then
 ...
end; // if

Conclusión

En este capítulo se describe cómo se codifican instrucciones condicionales y bucles. En vez de escribir listas largas de tales instrucciones, los programas se desmembran normalmente en rutinas, procedimientos o funciones. Este es el asunto del siguiente capítulo, que introduce también algunos elementos avanzados de Pascal.


Capítulo siguiente: Procedimientos


© Copyright Marco Cantù, Wintech Italia Srl 1995-99
© Copyright de la traducción, Rafael Barranco-Droege, 2000