apenas uma figura bonitinha

6.  Controle de Fluxo

 

Ahhhh, controle de fluxo. É aqui que tudo se junta. Ainda que este capítulo seja mais curto e fácil que o capítulo sobre métodos, ele vai abrir um mundo de possibilidades de programação. Após este capítulo, poderemos escrever programas realmente interativos; antes fizemos programas que dizem coisas diferentes dependendo do que você escreve, mas após este capítulo eles farão coisas diferentes, também. Todavia, temos que poder comparar objetos no nosso programa. Precisamos de...

Métodos de Comparação

Vamos ser rápidos por aqui para chegar até as ramificações, que é onde as coisas legais começam a acontecer. Para ver se um objeto é maior ou menor que outro, usamos os métodos > e <, assim:

puts 1 > 2
puts 1 < 2
false
true

Tudo em ordem. Do mesmo modo, podemos descobrir se um objeto é maior-ou-igual-que (ou menor-ou-igual-que) outro com os métodos >= e <=.

puts 5 >= 5
puts 5 <= 4
true
false

Por fim, podemos descobrir se dois objetos são iguais ou não usando == (que significa "estes objetos são iguais?") e != (que significa "estes objetos são diferentes?"). É importante não confundir = com ==. = serve para dizer a uma variável que aponte para um objeto (atribuição), e == é para fazer a pergunta: "Estes dois objetos são iguais?".

puts 1 == 1
puts 2 != 1
true
true

E é claro que também podemos comparar strings. Quando strings são comparadas, leva-se em conta seus ordenamentos lexicográficos, que, trocando em miúdos, significa a ordem delas no dicionário. cachorro vem antes de gato no dicionário, então:

puts 'cachorro' < 'gato'
true

Há um porém: os computadores costumam ordenar letras maiúsculas antes de minúsculas, como se viessem antes (é assim que guardam as letras em fontes, por exemplo: todas as letras maiúsculas primeiro, seguidas das minúsculas). Isso significa que o computador vai pensar que 'Zoológico' vem antes de 'abelha', então se você quiser descobrir qual palavra viria primeiro num dicionário de verdade, use downcase (ou upcase ou capitalize) em ambas as palavras antes de tentar compará-las.

Uma última observação antes de Ramificações: os métodos de comparação não estão nos dando as strings 'true' e 'false'; elas estão nos dando os objetos especiais true e false (claro, true.to_s nos dá 'true', que é como puts imprimiu 'true'). true e false são usados o tempo todo em...

Ramificações (Branching)

"Ramificação" é um conceito simples, mas poderoso. Na verdade, é tão simples que aposto que nem tenho que explicá-lo; deixa eu mostrar para você:

puts 'Olá, qual é o seu nome?'
nome = gets.chomp
puts 'Olá, ' + nome + '.'
if nome == 'Chris'
  puts 'Que nome bonito!'
end
Olá, qual é o seu nome?
Chris
Olá, Chris.
Que nome bonito!

Mas se colocarmos um nome diferente...

Olá, qual é o seu nome?
Chewbacca
Olá, Chewbacca.

E isso é ramificar. Se o que vem depois de if (N.T.—se) é true, nós executamos o código entre if e end. Se o que vem depois de if é false, não executamos nada. Claro e simples.

Eu indentei o código entre if e end porque acho que fica mais fácil acompanhar as ramificações assim. Quase todos os programadores fazem isso, independente da linguagem em que estejam trabalhando. Pode não parecer muito útil neste exemplo pequeno, mas quando as coisas ficam mais complexas, faz uma baita diferença.

Muitas vezes gostaríamos que um programa fizesse uma coisa se uma expressão for true, e outra se for false. É para isso que serve else:

puts 'Eu sou um vidente. Diga-me seu nome:'
nome = gets.chomp
if nome == 'Chris'
  puts 'Vejo coisas maravilhosas no seu futuro.'
else
  puts 'Seu futuro é... Ó, Deus! Olha a hora!'
  puts 'Eu tenho que ir, mil perdões!'
end
Eu sou um vidente. Diga-me seu nome:
Chris
Vejo coisas maravilhosas no seu futuro.

Agora vamos tentar um nome diferente...

Eu sou um vidente. Diga-me seu nome:
Ringo
Seu futuro é... Ó, Deus! Olha a hora!
Eu tenho que ir, mil perdões!

Ramificar é como deparar com uma bifurcação no código: tomamos o caminho para as pessoas com o nome == 'Chris' ou else, tomamos o outro caminho?

E como os galhos de uma árvore, você pode ter ramificações que contêm suas próprias ramificações:

puts 'Olá, e bem-vindo à aula de Português.'
puts 'Meu nome é professora Hélia. Seu nome é...?'
nome = gets.chomp

if nome == nome.capitalize
  puts 'Por favor, sente-se, ' + nome + '.'
else
  puts nome + '?  Você quer dizer ' + nome.capitalize + ', não é?'
  puts 'Você não sabe nem escrever seu nome??'
  resposta = gets.chomp
  
  if resposta.downcase == 'sim'
    puts 'Hunf! Vá, sente-se!'
  else
    puts 'FORA!!!'
  end
end
Olá, e bem-vindo à aula de Português.
Meu nome é professora Hélia. Seu nome é...?
chris
chris?  Você quer dizer Chris, não é?
Você não sabe nem escrever seu nome??
sim
Hunf! Vá, sente-se!

Está bem, vou capitalizar...

Olá, e bem-vindo à aula de Português.
Meu nome é professora Hélia. Seu nome é...?
Chris
Por favor, sente-se, Chris.

Às vezes pode ficar confuso entender onde colocar os ifs, elses e ends. O que eu faço é escrever o end ao mesmo tempo que escrevo o if. Então enquanto eu estava escrevendo o programa acima, ele estava primeiro assim:

puts 'Olá, e bem-vindo à aula de Português.'
puts 'Meu nome é professora Hélia. Seu nome é...?'
nome = gets.chomp

if nome == nome.capitalize
else
end

Aí eu preenchi com comentários, coisas no código que o computador irá ignorar:

puts 'Olá, e bem-vindo à aula de Português.'
puts 'Meu nome é professora Hélia. Seu nome é...?'
nome = gets.chomp

if nome == nome.capitalize
  #  Ela é cordial.
else
  #  Ela fica brava.
end

Qualquer coisa após um # é considerado um comentário (a não ser, é claro, que você esteja em uma string). Depois de preencher com comentários, substituí-os por código funcional. Algumas pessoas gostam de deixá-los no arquivo; particularmente, creio que código bem-escrito fala por si. Eu costumava escrever mais comentários, mas quanto mais "fluente" fico em Ruby, menos faço uso deles. Eles me distraem boa parte do tempo. É uma escolha individual; você vai encontrar o seu estilo (normalmente em constante evolução). Então meu próximo passo ficou assim:

puts 'Olá, e bem-vindo à aula de Português.'
puts 'Meu nome é professora Hélia. Seu nome é...?'
nome = gets.chomp

if nome == nome.capitalize
  puts 'Por favor, sente-se, ' + nome + '.'
else
  puts nome + '?  Você quer dizer ' + nome.capitalize + ', não é?'
  puts 'Você não sabe nem escrever seu nome??'
  resposta = gets.chomp
  
  if resposta.downcase == 'sim'
  else
  end
end

Mais uma vez escrevi if, else e end ao mesmo tempo. Realmente me ajuda a saber "onde estou" no código. Também faz com que o trabalho pareça mais fácil porque posso me concentrar em uma parte pequena, como preencher o código entre if e else. Uma outra vantagem de fazê-lo desta maneira é que o computador pode entender o programa em qualquer estágio. Qualquer uma das versões inacabadas do programa que eu lhe mostrei rodariam. Elas não estavam terminadas, mas eram programas funcionais. Desta maneira eu pude testar enquanto escrevia, o que me ajudou a ver como o programa progredia e o que precisava ser melhorado. Quando ele passou em todos os testes, eu soube que estava pronto!

Essas dicas vão ajudá-lo a escrever programas que se ramificam, mas também ajudam com outro tipo central de controle de fluxo:

Repetição (Looping)

Você vai querer com alguma freqüência que o computador faça a mesma coisa várias e várias vezes—afinal, é nisso que os computadores, em teoria, são bons.

Quando você manda o seu computador ficar repetindo algo, você também precisa dizê-lo quando parar. Computadores nunca se entediam, então se você não mandar o seu parar, ele não parará. Garantimos que isso não aconteça ao dizermos que ele deve repetir certas partes de um programa while (N.T.—enquanto) uma condição especificada for verdadeira. O funcionamento é bem parecido com o do if:

comando = ''

while comando != 'tchau'
  puts comando
  comando = gets.chomp
end

puts 'Volte logo!'

Olá?
Olá?
Oi!
Oi!
Muito prazer em conhecê-lo.
Muito prazer em conhecê-lo.
Ah... que amor!
Ah... que amor!
tchau
Volte logo!

E isso é um loop (você deve ter notado a linha em branco no começo da saída; ela vem do primeiro puts, antes do primeiro gets. Como você modificaria o programa para se livrar dessa primeira linha? Teste! Funcionou exatamente como o programa acima, fora aquela primeira linha em branco?).

Loops, ou repetições, permitem que você faça várias coisas interessantes, como sei que você pode imaginar. Mas também podem causar problemas se você cometer algum erro. E se o computador ficar preso num loop infinito? Se você acha que isso pode ter acontecido, é só segurar a tecla Ctrl e pressionar C.

Antes de começarmos a brincar com loops, vamos aprender algumas coisinhas para facilitar nossa vida.

Um Pouco de Lógica

Vamos dar uma olhada no nosso primeiro programa com ramificações. E se minha esposa chegasse em casa, visse o programa, tentasse usá-lo e ele não dissesse que nome bonito ela tem? Eu não gostaria de magoá-la (ou de dormir no sofá), então vamos reescrevê-lo:

puts 'Olá, qual é o seu nome?'
nome = gets.chomp
puts 'Olá, ' + nome + '.'
if nome == 'Chris'
  puts 'Que nome bonito!'
else
  if nome == 'Katy'
    puts 'Que nome bonito!'
  end
end
Olá, qual é o seu nome?
Katy
Olá, Katy.
Que nome bonito!

Bom, funciona... mas não é lá um programa muito bonito. E por quê? A melhor regra que eu aprendi sobre programação foi a regra DRY: Don't Repeat Yourself (N.T.—Não Se Repita). Eu poderia escrever um livro só sobre o quão boa ela é. No nosso caso, repetimos a linha Que nome bonito!. Por que é que isso é um problema? Bem, e se eu cometi um erro de digitação quando eu reescrevi? E se eu quisesse mudar de bonito para gracioso em ambas as linhas? Eu sou preguiçoso, lembra? Basicamente, se eu quero que meu programa faça a mesma coisa quando receber Chris ou Katy, então ele realmente deve fazer a mesma coisa:

puts 'Olá, qual é o seu nome?'
nome = gets.chomp
puts 'Olá, ' + nome + '.'
if (nome == 'Chris' or nome == 'Katy')
  puts 'Que nome bonito!'
end
Olá, qual é o seu nome?
Katy
Olá, Katy.
Que nome bonito!

Muito melhor. Para que funcionasse, usei or. Os outros operadores lógicos são and e not. É sempre bom usar parênteses ao trabalhar com eles. Vamos ver como funcionam:

euSouChris  = true
euSouRoxo = false
euAmoComida = true
euComoPedras = false

puts (euSouChris and euAmoComida)
puts (euAmoComida and euComoPedras)
puts (euSouRoxo and euAmoComida)
puts (euSouRoxo and euComoPedras)
puts
puts (euSouChris or euAmoComida)
puts (euAmoComida or euComoPedras)
puts (euSouRoxo or euAmoComida)
puts (euSouRoxo or euComoPedras)
puts
puts (not euSouRoxo)
puts (not euSouChris)
true
false
false
false

true
true
true
false

true
false

O único deles que pode enganá-lo é or (N.T.—ou). Em português, usa-se "ou" para dizer "um ou outro, mas não os dois". Por exemplo, sua mãe pode lhe dizer: "Para sobremesa você pode escolher torta ou bolo". Ela não deu a opção de escolher os dois! Um computador, por outro lado, entende or como "ou um ou outro, ou os dois" (outro jeito de colocar é "ao menos um destes é verdadeiro"). É por isso que computadores são mais legais que mães.

Umas Coisinhas Para Tentar

"Um elefante incomoda muita gente..." Escreva um programa que imprima a letra para o clássico das viagens de carro, com um limite de 100 elefantes.

• Escreva um programa Velha Surda. O que quer que você diga à velha (o que quer que você digite), ela tem que responder com QUE?! FALA MAIS ALTO!, a não ser que você grite (digite tudo em maiúsculas). Se você gritar, ela pode lhe ouvir (ou ao menos pensa que pode), e sempre responde NÃO, NÃO DESDE 1938! Para fazer seu programa ser realmente verossímil, faça a velha gritar um número diferente a cada vez; talvez qualquer ano aleatório entre 1930 e 1950 (a última parte é opcional, e ficaria muito mais fácil se você lesse a seção sobre o gerador de números randômicos do Ruby no capítulo sobre métodos). Você não pode parar de falar com a velha enquanto não gritar TCHAU.
Dica: Não esqueça do chomp ! 'TCHAU' com um enter não é a mesma coisa que 'TCHAU' sem! Dica 2: Tente pensar em que partes do programa as coisas acontecem repetidamente. Todas elas devem estar no seu loop while.

• Melhore o seu programa Velha Surda: e se a velha não quiser que você vá embora? Quando você gritar TCHAU, ela pode fingir que não lhe ouve. Mude seu programa anterior para que você tenha que gritar TCHAU três vezes em seqüência. Teste bem o seu programa: se você gritar TCHAU três vezes, mas não em seqüência, você tem que continuar falando com a velha.

• Anos bissextos. Escreva um programa que pergunte um ano inicial e um ano final, e imprima com puts todos os anos bissextos entre eles (e os incluindo, se eles também forem bissextos). Anos bissextos são sempre divisíveis por quatro (como 1984 e 2004). Contudo, anos divisíveis por 100 não são bissextos (como 1800 e 1900) a não ser que sejam divisíveis por 400 (como 1600 e 2000, que foram de fato anos bissextos). (Sim, é bem confuso, mas não tão confuso como ter dezembro no meio do inverno, que é o que aconteceria no fim).

Quando você terminá-las, descanse um pouco! Você já aprendeu muitas coisas. Parabéns. Você está surpreso com a quantidade de coisas que se pode mandar o computador fazer? Mais alguns capítulos e você vai poder programar praticamente tudo. Sério mesmo! Veja só tudo que você pode fazer que não podia antes de aprender sobre loops e ramificações.

Agora vamos aprender sobre um novo tipo de objeto, que controla listas de outros objetos: arrays.

 

© 2003-2015 Chris Pine