Accedi come Scuola



Controllo del Flusso

Ahhhh, il controllo del flusso di esecuzione. Questo è dove tutto va al proprio posto. Sebbene questo capitolo sia più corto e più semplice di quello sui metodi, sarà quello che rivelerà un intero mondo di nuove possibilità. Dopo questo capitolo, saremo in grado di scrivere programmi veramente interattivi; finora abbiamo scritto programmi che dicevano cose diverse sulla base di ciò che era fornito come input da tastiera, ma dopo questo capitolo i nostri programmi potranno effettivamente anche fare cose diverse. Ma prima di poterci riuscire, ci servono dei modi che ci consentano di confrontare fra loro i diversi oggetti dei nostri programmi. Ci servono...

Metodi di Confronto

Corriamo attraverso questa sezione così da raggiungere in fretta la prossima sul Branching, dove accadono tutte le cose più "cool" [NdT: in italiano sento la mancanza di una parola come "cool" che in questo contesto significa essenzialmente "fiche" senza però essere volgare...]. Dunque, per vedere se un oggetto è più piccolo o più grande di un altro, utilizziamo i metodi > e <, così:

puts 1 > 2
puts 1 < 2
false
true

No problem. Allo stesso modo possiamo scoprire se un oggetto è maggiore o uguale (o minore o uguale) a un altro coi metodi >= e <=, così:

# encoding: utf-8
puts 5 >= 5
puts 5 <= 4
true
false

E infine, possiamo vedere se due oggetti sono uguali o no utilizzando == (che significa "sono uguali?") e != (che significa "sono differenti?"). E' importante non confondere = con ==. = è per dire a una variabile di puntare a un oggetto (assegnamento, in cui la variabile si trova a sinistra del = mentre l'oggetto cui deve puntare è alla sua destra), mentre == è per chiedere la domanda: "Questi due oggetti sono uguali?"

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

[ NdT: 'true' significa 'vero' e 'false' significa 'falso'.]
Ovviamente, possiamo confrontare fra loro anche le stringhe. Quando vengono confrontate ciò che in realtà si confronta è il loro ordine lessicografico, che sostanzialmente equivale al loro ordine nel dizionario. cane viene prima di gatto nel dizionario, quindi:

puts 'cane' < 'gatto'
true

Però c'è una fregatura: i computer ordinano le lettere maiuscole prima delle lettere minuscole. (E questo è come memorizzano le lettere nei font, per esempio: prima tutte le lettere maiuscole, e poi tutte quelle minuscole). Questo significa che il computer è convinto che 'Zoo' venga prima di 'ape', quindi se il tuo scopo è capire quale parola venga prima in ordine alfabetico (come in un vero dizionario), assicurati di chiamare il metodo downcase (o upcase o capitalize) su ciascuna delle due parole prima di provare a confrontarle.

Un'ultima fondamentale nota prima di Diramare: La comparazione non ci sta restituendo le stringhe 'true' e 'false'; Bensì gli oggetti speciali true e false. (Ovviamente true.to_s ci restituisce 'true', che è il motivo per cui puts (che chiama sempre il metodo ".to_s" sugli oggetti che deve stampare) ha stampato 'true').
true e false si utilizzano continuamente nel...

Il Branching

Il Branching (che significa "Diramare", "Ramificare" NdT) è un semplice ma potentissimo concetto. In effetti è così semplice che scommetto di non dovertelo nemmeno spiegare; te lo mostrerò soltanto:

puts 'Ciao, come ti chiami?'
nome = gets.chomp
puts 'Ciao, ' + nome + '.'
if nome == 'Chris'
  puts 'Ma che bel nome!'
end
Ciao, come ti chiami?
Chris
Ciao, Chris.
Ma che bel nome!

Ma se inseriamo un nome diverso...

Ciao, come ti chiami?
Castrazzio
Ciao, Castrazzio.

E questo è il "branching". Se ciò che si trova dopo l'if (che vuol dire "se") è true ("vero"), il calcolatore esegue il codice che si trova tra l'if e l'end ("fine"). Se invece ciò che si trova dopo l'if è false ("falso"), non lo esegue. Chiaro e semplice.

Ho indentato il codice fra gli if e gli end solo perché sono convinto che in questo modo sia più semplice tener traccia della diramazione. Praticamente tutti i programmatori lo fanno, a prescindere dal linguaggio in cui stanno scrivendo. Potrebbe non sembrare un grande aiuto in un esempio così semplice, ma ti assicuro che quando le cose si fanno più complesse, una corretta indentazione fa una grande differenza.

Spesso ci capiterà di volere che un programma faccia qualcosa se un'espressione è true, e un'altra cosa se la stessa espressione è false. E a proprio questo serve il comando else ("oppure"):

# encoding: utf-8
puts 'Io sono un indovino. Dimmi il tuo nome:'
nome = gets.chomp
if nome == 'Chris'
  puts 'Vedo grandi cose nel tuo futuro.'
else
  puts 'Nel tuo futuro vedo... Oh porc!  Si è fatto tardi!'
  puts 'Scusa, ma devo proprio scappare!'
end
Io sono un indovino. Dimmi il tuo nome:
Chris
Vedo grandi cose nel tuo futuro.

Ora proviamo un nome diverso...

Io sono un indovino. Dimmi il tuo nome:
Ringo
Nel tuo futuro vedo... Oh porc!  Si è fatto tardi!
Scusa, ma devo proprio scappare!

Il branching è un po' come un bivio nel codice: Seguiamo il percorso per le persone il cui nome == 'Chris', oppure else seguiamo l'altro percorso?

E proprio come per i rami di un albero (NdT: in inglese "ramo" si dice proprio "branch"), possono esserci rami a loro volta ramificati:

# encoding: utf-8
puts 'Buongiorno e benvenuti al corso avanzato di grammatica italiana.'
puts 'Io sono la Prof.ssa Beatrice. Mentre tu ti chiami...?'
nome = gets.chomp

if nome == nome.capitalize
  puts 'Prendi pure posto, ' + nome + '.'
else
  puts nome + '?  Intendevi dire ' + nome.capitalize + ', vero?'
  puts 'Sai almeno come scrivere il tuo nome??'
  risposta = gets.chomp

  if risposta.downcase == 'si'
    puts 'Hmmph!  Va bene, siediti!'
  else
    puts 'FUORI!!'
  end    
end
Buongiorno e benvenuti al corso avanzato di grammatica italiana.
Io sono la Prof.ssa Beatrice. Mentre tu ti chiami...?
chris
chris?  Intendevi dire Chris, vero?
Sai almeno come scrivere il tuo nome??
si
Hmmph!  Va bene, siediti!

Ok, Provo capitalizzandolo correttamente...

Buongiorno e benvenuti al corso avanzato di grammatica italiana.
Io sono la Prof.ssa Beatrice. Mentre tu ti chiami...?
Chris
Prendi pure posto, Chris.

Alle volte il cercare di capire dove vanno tutti gli if, gli else, e gli end. Quello che faccio è scrivere gli end subito dopo aver scritto gli if. Quindi mentre scrivevo il programmino di cui sopra, all'inizio appariva così:

# encoding: utf-8
puts 'Buongiorno e benvenuti al corso avanzato di grammatica italiana.'
puts 'Io sono la Prof.ssa Beatrice. Mentre tu ti chiami...?'
nome = gets.chomp

if nome == nome.capitalize
else
end

Poi ho inserito i commenti, testo nel codice che il computer ignorerà:

# encoding: utf-8
puts 'Buongiorno e benvenuti al corso avanzato di grammatica italiana.'
puts 'Io sono la Prof.ssa Beatrice. Mentre tu ti chiami...?'
nome = gets.chomp

if nome == nome.capitalize
  #  Si comporta bene.
else
  #  Si arrabbia.
end

Qualsiasi cosa ci sia scritta dopo un # diventa un commento (a meno che, ovviamente, si trovi in una stringa). Dopodiché ho sostituito i commenti con del codice funzionante. Alcune persone preferiscono lasciare i commenti; personalmente credo che del codice ben scritto possa essere "auto commentante". Inizialmente usavo più commenti, ma più sono diventato bravo in Ruby, meno commenti ho utilizzato. Effettivamente talvolta li trovo dispersivi. E' una scelta personale; troverai il tuo stile e sarà sempre in evoluzione. Quindi il mio step successivo appariva così:

# encoding: utf-8
puts 'Buongiorno e benvenuti al corso avanzato di grammatica italiana.'
puts 'Io sono la Prof.ssa Beatrice. Mentre tu ti chiami...?'
nome = gets.chomp

if nome == nome.capitalize
  puts 'Prendi pure posto, ' + nome + '.'
else
  puts nome + '?  Intendevi dire ' + nome.capitalize + ', vero?'
  puts 'Sai almeno come scrivere il tuo nome??'
  risposta = gets.chomp
  
  if risposta.downcase == 'si'
  else
  end   
end

Di nuovo, ho scritto prima if, else, ed end tutti assieme. Questa cosa mi aiuta davvero a tenere traccia di "dove mi trovo" all'interno del codice. Inoltre fa sembrare il lavoro più semplice perché posso concentrarmi di volta in volta su una piccola parte, come lo scrivere il codice compreso fra l'if e l'else. L'altro beneficio di programmare in questo modo è che il computer può capire il codice in ogni fase. Ciascuna delle versioni provvisorie del programma, pur non essendo finite, possono essere eseguite correttamente. In questo modo si può testare il corretto funzionamento di un programma già mentre lo si scrive, rendendo più semplice il capire a che punto ci si trova e cosa serve per finire. Quando ha superato tutti i test allora ho potuto considerarlo finito!

Questi suggerimenti non solo ti aiuteranno a scrivere programmi col branching, ma potrai altresì applicarli alle altre strutture principali di controllo del flusso di esecuzione:

Il Looping

[NdT: "Looping" significa "ciclare", cioè proprio "ripetere lo stesso procedimento più volte", e "loop" significa "ciclo".] Spesso ti capiterà di volere che il tuo computer faccia sempre la stessa cosa più e più volte—dopotutto, questo è ciò che ai computer riesce meglio!

Quando dici a un computer di continuare a ripetere qualcosa, devi anche dirgli quando fermarsi. I computer non si annoiano mai quindi se non gli dici di fermarsi, non lo fanno. Ci assicuriamo che questo non accada dicendo al computer di ripetere alcune parti di un programma solo finché una certa condizione è vera. E finché in inglese si dice while. Questo comando funziona in modo molto simile a come funziona il già visto if:

# encoding: utf-8
comando = ''

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

puts 'Alla prossima!'
C'è nessuno?
C'è nessuno?
Ciao!
Ciao!
Molto piacere di conoscerti.
Molto piacere di conoscerti.
Oh... troppo gentile!
Oh... troppo gentile!
Arrivederci
Alla prossima!

Ed ecco un loop. (Potresti aver notato la linea vuota all'inizio dell'output; è per via del primo puts eseguito prima del primo gets. Come cambieresti il programma per non avere quella prima linea vuota? Provaci! Ha funzionato esattamente come il programma qui sopra a parte la prima linea in bianco?)

I loop (o cicli) ti permettono di realizzare ogni genere d'interessante cosuccia, e sono sicuro che qualcosa riesci già a immaginarla. Tuttavia possono creare problemi se commetti un errore. Che succede se il tuo computer rimane intrappolato in un loop infinito? Se dovesse capitarti, per uscirne ti basterà tenere premuto il tasto Ctrl e poi, tenendolo premuto, premere anche il tasto C.

Prima di cominciare a giocherellare coi loop, impariamo un po' di cose che ci rendano il lavoro più semplice.

Un Pochino di Logica

Riguardiamo ancora il nostro primo programma col branching. Cosa accadrebbe se mia moglie tornasse a casa, vedesse il programma, lo provasse e questo non si complimentasse con lei per quanto bello sia il suo nome? Non vorrei mai urtare i suoi sentimenti (e dormire sul divano), quindi riscriviamolo:

puts 'Ciao, come ti chiami?'
nome = gets.chomp
puts 'Ciao, ' + nome + '.'
if nome == 'Chris'
  puts 'Ma che bel nome!'
else
  if nome == 'Katy'
    puts 'Ma che bel nome!'
  end
end
Ciao, come ti chiami?
Katy
Ciao, Katy.
Ma che bel nome!

Beh, funziona... ma non è granché come programma. Perché no? Ebbene, perché la migliore regola che abbia mai imparato sulla programmazione è la regola "DRY": Don't Repeat Yourself (NdT: in italiano significa "Non Ripeterti", mentre "DRY" significa "ASCIUTTO"). Probabilmente potrei scrivere un libricino solo sul perché si tratti proprio di una regola aurea. Nel nostro caso, abbiamo ripetuto la linea puts 'Ma che bel nome!'. Perché è un problema? Beh, e se avessi commesso un errore di battitura quando l'ho riscritta? E se volessi cambiare 'bel' in 'bellissimo' in entrambe le linee? Sono pigro, ricordi? In sostanza, se vogliamo che il programma faccia la stessa cosa quando ottiene 'Chris' o 'Katy', allora dovrebbe davvero fare la stessa cosa:

puts 'Ciao, come ti chiami?'
nome = gets.chomp
puts 'Ciao, ' + nome + '.'
if (nome == 'Chris' or nome == 'Katy')
  puts 'Ma che bel nome!'
end
Ciao, come ti chiami?
Katy
Ciao, Katy.
Ma che bel nome!

Molto meglio. Per farlo funzionare, ho usato l'operatore logico or (NdT: che in italiano significa proprio "o" congiunzione). Gli altri operatori logici sono and e not. (NdT: "and" significa "e" congiunzione, mentre "not" significa "non"). E' sempre una buona idea utilizzare delle parentesi quando li si utilizza. Guarda come funzionano:

sonoChris  = true
sonoVerde   = false
bevoBirra   = true
mangioSassi = false

puts (sonoChris  and bevoBirra)
puts (bevoBirra   and mangioSassi)
puts (sonoVerde   and bevoBirra)
puts (sonoVerde   and mangioSassi)
puts
puts (sonoChris  or bevoBirra)
puts (bevoBirra   or mangioSassi)
puts (sonoVerde   or bevoBirra)
puts (sonoVerde   or mangioSassi)
puts
puts (not sonoVerde)
puts (not sonoChris)
true
false
false
false

true
true
true
false

true
false

Gli unici esempi che potrebbero confonderti sono quelli con or. In inglese "or" (in italiano "o") significa "uno o l'altro, ma non entrambi." Per esempio, tua mamma potrebbe dirti: "Per dessert puoi prendere un gelato o una fetta di torta". Tua mamma non intende certo dire che puoi mangiarli entrambi! Un computer, invece, con or intende proprio "uno o l'altro, o entrambi". (Un altro modo di intenderlo è: "almeno uno di questi è vero"). E' per questo che i computer sono più divertenti delle mamme.

Un Po' di Cose da Provare

  • "99 bottles of beer on the wall..." Scrivi un programma che scriva il testo di quella classica canzoncina inglese, tanto amata dagli studentelli in gita scolastica.
  • Scrivi un programma "Nonna Sorda". Qualsiasi cosa tu dica alla nonna (qualsiasi cosa tu scriva al programma), lei dovrebbe rispondere con un EH?!  ALZA LA VOCE, FIGLIUOLO!, a meno che tu non l'abbia gridato (scritto in lettere maiuscole). Se gridi allora può sentirti (o almeno così pensa) e allora ti risponde: NO, NON DAL 1938!. Per rendere questo programmino davvero credibile, fai in modo che la nonna gridi un anno differente tutte le volte; magari un numero casuale tra il 1930 e il 1950. (Questa parte è opzionale, ma ti risulterebbe molto più semplice se leggessi la sezione sui numeri casuali alla fine del capitolo sui metodi). Non puoi smettere di parlare con la nonna finché non gridi CIAO.
    Suggerimento: Non dimenticarti di chomp! 'CIAO'con un Invio non è la stessa cosa di un 'CIAO' senza!
    Suggerimento 2: Prova innanzitutto a pensare quali parti del tuo programma dovranno ripetersi ancora e ancora. Tutte queste parti dovranno essere nel tuo ciclo while.
  • Estendi il tuo programma Nonna Sorda: E se la nonna non volesse che te ne andassi? Quando gridi CIAO, potrebbe far finta di non sentirti. Modifica il programma precedente per fare in modo che tu debba gridare CIAO tre volte di fila per far sì che la nonna ti saluti e il programma termini. Se gridi CIAO tre volte ma non di fila starai ancora parlando alla nonna.
  • Anni Bisestili. Scrivi un programma che ti chieda un anno di partenza e uno finale, e quindi putsa tutti gli anni bisestili inclusi fra i due (inclusi, se sono anni bisestili). Gli anni bisestili sono divisibili per quattro (come 1984 e 2004). Tuttavia, gli anni divisibili per 100 non sono bisestili (come 1800 e 1900) a meno che essi siano divisibili per 400 (come 1600 e 2000, che effettivamente sono anni bisestili). (Si, è un bel casino, ma non quanto lo sarebbe trovarsi Luglio nel bel mezzo di un inverno, che è ciò che prima o poi accadrebbe se non avessero inventato gli anni bisestili).

Quando hai finito questi, prenditi una pausa! Hai già imparato parecchio. Complimenti! Sei sorpreso di quante cose puoi dire di fare a un computer? Ancora qualche capitolo e sarai in grado di programmare qualsiasi cosa. Seriamente! Guarda solo cosa sai fare adesso ma che non potevi fare prima di conoscere il looping e il branching.

Ora andiamo a fare la conoscenza di un nuovo tipo di oggetto, un oggetto che tiene traccia di liste di altri oggetti: gli array.

Che ne dici?

Scritto da

Duccio Armenise

Founder Corsidia & co-Founder WorldBridge

Aiuto solo i migliori Maestri a trovare i loro prossimi Studenti. Come? Così! :)

Per

Corsidia

I tuoi prossimi Studenti ti stanno già cercando, tu ci sei?