Fluxo de controlo
Independentemente da simplicidade ou da complexidade de um método, sempre utilizará um ou vários dos três tipos de estruturas de programação. As estruturas de programação determinam o fluxo de execução, se serão executadas, e a ordem das linhas de instruções dentro do método. Há três tipos de estruturas:
-
Sequencial: uma estrutura sequencial é uma estrutura simples e linear. Uma sequência é uma série de sentenças que 4D executa uma atrás da outra, da primera à última. Uma instrução de uma linha, utilizada frequentemente para os métodos dos objetos, é o caso mais simples de uma estrutura sequencial. Por exemplo:
[People]lastName:=Uppercase([People]lastName)
-
Branching: uma estrutura de bifurcação permite que os métodos provem uma condição e tomem caminhos alternativos, dependendo do resultado. A condição é uma expressão booleana, uma expressão que avalia TRUE ou FALSE. Uma estrutura condicional e a estrutura
If... Else... End if
, que dirige o fluxo do programa ao longo de um dos dois caminhos. A outra estrutura condicional é a estruturaCase of... End case
que direciona fluxo de programa para um de muitas caminhos. -
Bucle: quando se escrevem métodos, é muito comum descobrir que se necessita que uma sequência de sentenças se repita um número de vezes. Para lidar com esta necessidade, a linguagem 4D oferece as estruturas de loop abaixo:
Os loops são controlados de duas maneiras: ou fazem loop até que uma condição seja satisfeita, ou fazem loop um número especificado de vezes. Cada estrutura de looping pode ser usada de qualquer forma, mas loopsWhile
e Repeat
são mais apropriados para repetir até que uma condição seja satisfeita, e loops For
são mais apropriados para looping um número especificado de vezes. For each... End for each
permite misturar ambas as formas e foi concebido para fazer loop dentro de objectos e colecções.
Nota: 4D permite incorporar estruturas de programação até uma "profundidade" de 512 níveis.
If... Else... End if
The formal syntax of the If... Else... End if
control flow structure is:
If(Boolean_Expression)
statement(s)
Else
statement(s)
End if
Note que a parte Else
é opcional; pode escrever:
If(Boolean_Expression)
statement(s)
End if
The If... Else... End if
structure lets your method choose between two actions, depending on whether a test (a Boolean expression) is TRUE or FALSE. Quando a expressão Booleana for TRUE, são executadas as declarações que seguem imediatamente ao teste. Se a expressão Booleana for FALSE, são executadas as declarações que seguem a linha Else. A declaração Else
é opcional; se omitir Else, a execução continua com a primeira instrução (se houver) que seguir End if
.
Note que a expressão booleana é sempre avaliada completamente. Considere particularmente o teste abaixo:
If(MethodA & MethodB)
...
End if
A expressão é TRUE apenas se ambos os métodos forem TRUE. Entretanto, mesmo se MethodA devolver FALSE, 4D ainda iria avaliar MethodB, o que seria uma perda de tempo. Nesse caso, é mais interessante usar uma estrutra como:
If(MethodA)
If(MethodB)
...
End if
End if
O resultado é parecido mas o MethodB é avaliado somente se necessário.
Note: The ternary operator allows writing one-line conditional expressions and can replace a full sequence of If..Else statements.
Exemplo
// Ask the user to enter a name
$Find:=Request(Type a name)
If(OK=1)
QUERY([People];[People]LastName=$Find)
Else
ALERT("You did not enter a name.")
End if
End if
End if
Dica: A ramificação pode ser realizada sem que as instruções sejam executadas em um caso ou no outro. Quando desenvolver um algoritmo ou uma aplicação especializada, nada impede que escreva:
If(Boolean_Expression)
Else
statement(s)
End if
ou :
If(Boolean_Expression)
statement(s)
Else
End if
Case of... Else... End case
The formal syntax of the Case of... Else... End case
control flow structure is:
Case of
:(Boolean_Expression)
statement(s)
:(Boolean_Expression)
statement(s)
.
.
.
:(Boolean_Expression)
statement(s)
Else
statement(s)
End case
Note que a parte Else
é opcional; pode escrever:
Case of
:(Boolean_Expression)
statement(s)
:(Boolean_Expression)
statement(s)
.
.
.
:(Boolean_Expression)
statement(s)
End case
As with the If... End if
structure, the Case of... End case
structure also lets your method choose between alternative actions. Unlike the If... End
if structure, the Case of... End case
structure can test a reasonable unlimited number of Boolean expressions and take action depending on which one is TRUE.
Cada expressão booleana é precedida de dois pontos (:
). A combinação dos dois pontos e da expressão booleana é chamada de um caso. Por exemplo, a linha abaixo é um caso:
:(bValidate=1)
Só são executadas as instruções que seguem o primeiro caso TRUE (até o próximo caso). Se nenhum dos casos for TRUE, nenhuma das instruções será executada (se nenhuma parte Else
for incluida).
Pode incluir uma instrução Else depois do último caso. Se todos os casos forem FALSE, as instruções que seguem Else
serão executadas.
Exemplo
Esse exemplo testa uma variável numérica e exibe uma caixa de alerta com uma apalavra:
Case of
:(vResult=1) //Teste se o número é 1
ALERT("One.") //Se for 1, mostrar um alerta
:(vResult=2) //Testar se o número é 2
ALERT("Two.") //Se for 2, exibe um alerta
:(vResult=3) //Testa se o número é 3
ALERT("Three.") //Se for 3, exibe um alerta
Else //Se não for 1, 2, ou 3, exibe um alerta
ALERT("It was not one, two, or three.")
//statement(s)
End case //If it is 2, display an alert
:(vResult=3) //Test if the number is 3
ALERT("Three.") //If it is 3, display an alert
Else //If it is not 1, 2, or 3, display an alert
ALERT("It was not one, two, or three.")
//statement(s)
End case
For comparison, here is the If... Else... End if
version of the same method:
If(vResult=1) //Teste se o número é 1
ALERT("One.") If(vResult=1) //Test if the number is 1
ALERT("One.") //If it is 1, display an alert
Else
If(vResult=2) //Test if the number is 2
ALERT("Two.") //If it is 2, display an alert
Else
If(vResult=3) //Test if the number is 3
ALERT("Three.") //If it is 3, display an alert
Else //If it is not 1, 2, or 3, display an alert
ALERT("It was not one, two, or three.")
End if
End if
End if //If it is 2, display an alert
Else
If(vResult=3) //Test if the number is 3
ALERT("Three.") //If it is 3, display an alert
Else //If it is not 1, 2, or 3, display an alert
ALERT("It was not one, two, or three.")
End if
End if
End if
Remember that with a Case of... Else... End case
structure, only the first TRUE case is executed. Mesmo se dois ou mais casos forem TRUE, só as instruções que seguirem o primeiro caso TRUE serão executadas.
Dessa maneira, quando quiser implementar testes hierárquicos, deve garantir que as declarações de condição que estejam mais abaixo no esquema hierárquico apareçam primeiro na sequência de testes. Por exemplo, o teste para a presença da condition1 cobre o teste para a preença de condition1&condition2 e portanto deveria estar localizada por último na sequência de testes. Por exemplo, o código abaixo nunca terá sua última condição detectada:
Case of
:((vResult=1) & (vCondition#2)) //this case will be detected first
... //statement(s)
:(vResult=1)
...
No código anterior, a presença da segunda condição não é detectada, já que o teste "vResult=1" ramifica o código antes de qualquer outro teste. Para que o código funcione corretamente, pode escrevê-lo assim:
Case of
:(vResult=1) //Test if the number is 1
ALERT("One.") //If it is 1, display an alert
:(vResult=2) //Test if the number is 2
ALERT("Two.") //If it is 2, display an alert
:(vResult=3) //Test if the number is 3
ALERT("Three.") //If it is 3, display an alert
Else //If it is not 1, 2, or 3, display an alert
ALERT("It was not one, two, or three.")
End case
Além disso, se quiser implementar teste hierárquico, pode considerar usar um código hierárquico.
Dica: a ramificação|branching pode ser feita sem que as instruções sejam executados em um caso ou outro Quando desenvolver um algoritmo ou uma aplicação especializada, nada impede que escreva: Quando desenvolver um algoritmo ou uma aplicação especializada, nada impede que escreva: Quando desenvolver um algoritmo ou uma aplicação especializada, nada impede que escreva: Quando desenvolver um algoritmo ou uma aplicação especializada, nada impede que escreva: Quando desenvolver um algoritmo ou uma aplicação especializada, nada impede que escreva:
Case of
:(Boolean_Expression)
:(Boolean_Expression)
...
:(Boolean_Expression)
statement(s)
Else
statement(s)
End case
ou :
Case of
:(Boolean_Expression)
statement(s)
:(Boolean_Expression)
statement(s)
...
:(Boolean_Expression)
statement(s)
Else
End case
ou :
Case of
Else
statement(s)
End case
While... End while
The formal syntax of the While... End while
control flow structure is:
While(Boolean_Expression)
statement(s)
{break}
{continue}
End while
A While...End while
loop executes the statements inside the loop as long as the Boolean expression is TRUE. Comprova a expressão booleana ao início do loop e não entra no loop se a expressão for FALSE.
The break
and continue
statements are described below.
It is common to initialize the value tested in the Boolean expression immediately before entering the While... End while
loop. Initializing the value means setting it to something appropriate, usually so that the Boolean expression will be TRUE and While... End while
executes the loop.
O valor da expressão booleana deve poder ser modificado por um elemento dentro do loop, do contrário será executado indefinidamente. O próximo loop continua para sempre porque NeverStop sempre será TRUE:
NeverStop:=True
While(NeverStop)
End while
Se você se encontrar em uma situação desse tipo, na qual um método fica executando de forma descontrolada, pode usar as funções de rastreamento para parar o loop e rastrear o problema. Para saber mais sobre o rastreio de um método veja a página Error handling.
Exemplo
CONFIRM("Add a new record?") //o usuário quer adicionar um registro? CONFIRM("Add a new record?") //The user wants to add a record?
While(OK=1) //Loop enquanto o usuário quiser
ADD RECORD([aTable]) //Adiciona um novo registro
End while //O loop sempre termina com End while
Nesse exemplo, o valor da variável sistema OK
é estabelecida pelo comando CONFIRM
antes de que inicia o loop. Se o usuário clicar no botão OK da caixa de diálogo de confirmação, a variável do sistema OK
toma o valor 1 e se inicia o loop. Senão, a variável de sistema OK
toma o valor 0 e se omite o loop. Quando iniciar o loop, o comando ADD RECORD
permite continuar a execução do loop porque se define a variável sistema OK
em 1 quando o usuário salvar o registro. Quando o usuário cancelar (não salvar) o último registro, a variável do sistema OK
é estabelecida como 0 e o loop para.
Repeat... Until
The formal syntax of the Repeat... Until
control flow structure is:
Repeat
statement(s)
{break}
{continue}
Until(Boolean_Expression)
Um ciclo Repeat...Until
é como um ciclo While...End while, exceto que testa a expressão booleana depois do ciclo e não antes. Thus, a Repeat...Until
loop always executes the loop once, whereas if the Boolean expression is initially False, a While...End while
loop does not execute the loop at all.
The other difference with a Repeat...Until
loop is that the loop continues until the Boolean expression is TRUE.
The break
and continue
statements are described below.
Exemplo
Compare the following example with the example for the While... End while
loop. Lembre que a expressão booleana não precisa ser iniciada - não há um comando CONFIRM
para inicializar a variável OK
.
Repeat
ADD RECORD([aTable])
Until(OK=0)
For...End for
The formal syntax of the For... End for
control flow structure is:
For(Counter_Variable;Start_Expression;End_Expression{;Increment_Expression})
statement(s)
{break}
{continue}
End for
The For... End for
loop is a loop controlled by a counter variable:
- The counter variable Counter_Variable is a numeric variable (Real or Long Integer) that the
For... End for
loop initializes to the value specified by Start_Expression. - Cada vez que se executa o loop, a variável do contador se incrementa no valor especificado no valor opcional Increment_Expression. Se não especificar Increment_Expression, a variável contadora é incrementada por um (1), que é o padrão.
- Quando a variável contador passar o valor End_Expression daí o loop para.
Importante: as expressões numéricas Start_Expression, End_Expression e Increment_Expression são avaliadas apenas uma vez no começo do loop. Se essas expressões forem variáveis, mudar uma deles dentro do loop não vai afetar o loop.
Dicas: Entretanto, para fins especiais, pode mudar o valor da variável Counter_Variable dentro do loop; isso afetará o loop.
- Geralmente Start_Expression pe menor que End_Expression.
- Se Start_Expression e End_Expression forem iguais, o loop se executará só uma vez.
- Se Start_Expression for maior que End_Expression, o loop não vai executar a não ser que especifique uma Increment_Expression negativa. Ver os exemplos.
The break
and continue
statements are described below.
Exemplos básicos
- O seguinte exemplo executa 100 iterações:
For(vCounter;1;100)
//Faz algo
End for
- O exemplo abaixo percorre todos os elementos no array anArray:
For($vlElem;1;Size of array(anArray))
//Fazer algo com o elemento
anArray{$vlElem}:=...
End for
- O exemplo abaixo recorre todos os caracteres do texto vtSomeText:
For($vlChar;1;Length(vtSomeText))
//Faz algo com o caractere se for uma TAB
If(Character code(vtSomeText[[$vlChar]])=Tab)
//...
End if
End for
- O exemplo abaixo recorre os registros selecionados para a tabela [aTable]:
FIRST RECORD([aTable])
For($vlRecord;1;Records in selection([aTable]))
//Faz algo com o registro
SEND RECORD([aTable])
//...
//Vai para o próximo registro
NEXT RECORD([aTable])
End for
Most of the For...End for
loops you will write in your projects will look like the ones listed in these examples.
Variável contador
Variável contador decrescente
Em alguns casos, pode querer ter um loop cuja variável de contador seja decrescente ao invés de crescente. Para fazer isso, deve especificar Start_Expression maior que End_Expression e Increment_Expression deve ser negativa. Os exemplos abaixo fazem a mesma coisa que nos exemplos acima, mas na ordem inversa:
- O seguinte exemplo executa 100 iterações:
For(vCounter;100;1;-1)
//Faz algo
End for
- O exemplo abaixo percorre todos os elementos no array anArray:
For($vlElem;Size of array(anArray);1;-1)
//Faz algo com o elemento
anArray{$vlElem}:=...
End for
- O exemplo abaixo recorre todos os caracteres do texto vtSomeText:
For($vlChar;Length(vtSomeText);1;-1)
//Faz algo com o caractere se for uma TAB
If(Character code(vtSomeText[[$vlChar]])=Tab)
//...
End if
End for
- O exemplo abaixo recorre os registros selecionados para a tabela [aTable]:
LAST RECORD([aTable])
For($vlRecord;Records in selection([aTable]);1;-1)
//Faz algo com o registro
SEND RECORD([aTable])
//...
//Ir ao registro anterior
PREVIOUS RECORD([aTable])
End for
Incrementar a variável do contador em mais de um
Se precisar, pode usar uma Increment_Expression (positiva ou negativa) cujo valor absoluto seja maior que um.
- O loop a seguir aborda só os elementos pares do array anArray:
For($vlElem;2;Size of array(anArray);2)
//Faz algo com o elemento #2,#4...#2n
anArray{$vlElem}:=...
End for
Optimizing the execution of the For... End for loops
Pode utilizar variáveis reais e inteiras, assim como contadores interprocesso, de processo e de variáveis locais. Para loops repetitivos longos, especialmente em modo compilado, use variáveis locais de tipo Inteiro longo.
- Aqui um exemplo simples:
var $vlCounter : Integer //usa variáveis Integer locais
For($vlCounter;1;10000)
//Faz algo
End for
Comparação de estruturas de loop
Let's go back to the first For... End for
example. O seguinte exemplo executa 100 iterações:
For(vCounter;1;100)
//Faz algo
End for
Here is the equivalent While... End while
loop:
$i:=1 //Initializa o contador
While($i<=100) //Loop 100 vezes
//Faz algo
$i:=$i+1 //Precisa incrementar o contador
End while
Here is the equivalent Repeat... Until
loop:
$i:=1 //Initializa o contador
Repeat
//Faz algo
$i:=$i+1 //Precisa incrementar o contador
Until($i=100) //Loop 100 vezes
Here is the equivalent While... Therefore, use the <code>For... End for
loop whenever possible.