Le funzioni e gli operatori

16 Feb 2015

Impariamo a definire ed utilizzare le funzioni (o metodi) e introduciamo gli operatori di Ruby. Scopriamo if e scriviamo la nostra prima funzione numerica, sfruttando tutte le conoscenze acquisite fino ad ora.

Funzioni

Una funzione, e’ un particolare costrutto sintattico che permette di raggruppare diverse righe di codice in una struttura unica che possa essere richiamata piu’ volte attraverso il codice. Le funzioni permettono di racchiudere codice che esegue uno specifico algoritmo/sequenza di istruzioni in un punto solo, a vantaggio sia del tempo di sviluppo di un progetto, che della manutenibilita’ del codice.

Ruby e’ un linguaggio fortemente orientato agli oggetti, quindi solitamente le funzioni sono chiamate metodi.

Definire una funzione

La sintassi per definre una funzione e’ la seguente

#!/usr/bin/env ruby

# Funzione puts_asterisk
# input:
#   n - intero con numero di punti da scrivere
# returns:
#   ret_string - una stringa
# La funzione stampa una linea di asterischi lunga n elementi
def puts_asterisk(n)
  ret_string = "*" * n
  puts ret_string
  return ret_string
end

# La prossima linea invoca la funzione per 10 asterischi
result = puts_asterisk 10

puts result

La definizione di una funzione e’ caratterizzata dai seguenti elementi:

Operatori in Ruby

Per operatori intendiamo particolari tipi di funzione che hanno un elemento a sinistra e un elemento a destra. Gli operatori eseguono operazioni aritmetico/logiche o di assegnazione tra questi due elementi. L’elemento a sinistra e’ detto l-value, mentre quello a destra e’ detto r-value.

Operatori aritmetici

Facciamo una introduzione agli operatori aritmetici, che possono essere utilizzati tra variabili di tipo numerico.

Gli operatori aritmetici sono definiti per tutte le variabili Numeric. Tali operatori funzionano anche nel caso di varibili Fixnum, Float e Bignum, che sono tutte definite a partire della Numeric.

Operatore Descrizione Esempio
+ Addizione - Aggiunge r-value a l-value a + b
- Sottrazione - Sottrae r-value a l-value a - b
* Moltiplicazione - Moltiplica l-value per r-value a * b
/ Divisione - Ritorna il risultato della divisione tra l-value e r-value b / a
% Modulo - Ritorna il resto della divisione intera tra l-value e r-value b % a
** Esponente - Eleva l-value a r-value a**b

Operatori di assegnazione

Gli operatori di assegnazione sono tipologie di operatori aritmetici che effettuano direttamente la assegnazione

Operatore Descrizione Esempio
= Operatore di assegnazione semplice c = a + b
+= Aggiungi e Assegna, aggiunge il valore di r-value a l-value e assegna il risultato a l-value c += ac = c + a
-= Sottrai e Assegna, sottrae il valore di r-value a l-value e assegna il risultato a l-value c -= ac = c - a
*= Moltiplica e Assegna, moltiplica il valore di r-value a l-value e assegna il risultato a l-value c *= ac = c * a
/= Dividi e Assegna, esegue la divisione tra l-value e r-value e assegna il risultato a l-value c /= ac = c / a
%= Resto e Assegna, calcola il resto della divisione tra l-value e r-value e la assegna a l-value c %= ac = c % a
**= Esponente e Assegna, esegue l-value elevato a r-value e assegna il risultato a l-value c **= ac = c**a

Operatori di comparazione

Gli operatori di comparazione permettono di comparare il valore a sinistra con il valore a destra, secondo una regola logica. Immaginando a = 10 e b = 30.

Operatore Descrizione Esempio
== Controlla se l-value e’ uguale a r-value (a == b) → false
!= Controlla se l-value e’ diverso da r-value (a != b) → true
> Controlla se l-value e’ maggiore da r-value (a > b) → false
< Controlla se l-value e’ minore da r-value (a < b) → true
>= Controlla se l-value e’ maggiore o uguale da r-value (a >= b) → false
<= Controlla se l-value e’ minore o uguale da r-value (a <= b) → true
<=> Spaceship operator (a <=> b) → -1

Spaceship operator <=>

Questo operatore di comparazione e’ di tipo molto particolare, in quanto ritorna un valore numerico che copre diversi casi di comparazione:

In Ruby questo operatore e’ fondamentale, in quanto e’ sufficiente definire questo metodo e includere la classe Comparable per avere la definizione automatica di tutti gli altri operatori di comparazione. Vedremo nella lezione sule classi che cosa significa tutto questo.

Operatori logici

Tratti dalla algebra di Boole, gli operatori logici permettono di concatenare diverse affermazioni semplici al fine di ottenere espressioni di maggiore complessita’. Immaginando a = true e b = false.

Operatore Algebra di Boole Descrizione Esempio
and, && Ritorna vero se entrambi sono veri (a and b) → false
or, || Ritorna vero se uno dei due e’ vero (a or b) → true
! Ritorna la negazione !(b) → true

Gli operatori logici non devono essere scambiati con i bitwise operator, che sono operatori di natura diversa, facenti parte della algebra di Boole, e aventi come scopo la implementazione formale di tale algebra. Quelli presentati sono invece operatori logici, nati per ottenere espressioni complesse a partire da espressioni semplici, e rispondono in modo particolare ai diversi tipi contenuti negli l-value e r-value.

Operatori di range

Gli operatori di range permettono di costruire un intervallo tra due valori, uno iniziale e uno finale. Esistono due operatori di range, che differiscono nella inclusione o no del punto finale.

Operatore Insieme Descrizione Esempio
.. Costruisce un range con e inclusi (a..b)
... Costruisce un range con incluso e escluso (a...b)

Usiamo quanto imparato…

… per scrivere una funzione che ritorna le radici (anche complesse) di un polinomio di secondo ordine. Nello scrivere questa funzione introdurremo anche l’argomento della prossima lezione: le istruzioni condizionali, particolari construtti sintattici nati per definire il flusso di esecuzione di un codice.

Introduzione ad if

Il costrutto if, comune nella maggior parte dei linguaggi di programmazione, sfrutta lo stato di una condizione per decidere quali linee di codice eseguire:

se la condizione e’ vera, il codice eseguito e’ quello contenuto in , altrimenti il codice eseguito e’ quello contenuto in .

In Ruby:

#!/usr/bin/env ruby

a = 1

if a > 0 then
  puts "a > 0"
else
  puts "a < 0"
end

Radici di un polinomio

Dato un polinomio del secondo ordine:

univocamente defineito dai tre termini noti , tale polinomio ha radici complesse nella forma:

Le parti complesse di tali radici sono nulle se il discriminante e’ maggiore o uguale a 0, dove con discriminante si intende la espressione:

e le soluzioni sono nella forma:

abbiamo tutte le informazioni necessarie per poter implementare una funzione.

Implementazione

La funzione radice quadratain Ruby e’ Math.sqrt.

#!/usr/bin/env ruby

# Funzione radici_quadrate
# input
#  a - Float, coefficiente dell'elemento di 2 ordine
#  b - Float, coefficiente dell'elemento di 1 ordine
#  c - Float, termine noto
# return
#  [ radice reale 1, radice immaginaria 1,
#    radice reale 2, radice immaginaria 2 ] - array con le radici
# La funzione calcola le radice di un polinomio, specificati i
# coefficiente e i termini noti.
def radici_quadratica(a,b,c)

  # calcolo discriminante
  delta = b**2 - 4 * a * c

  if delta >= 0 then
    # caso radici reali
    sdelta = Math.sqrt(delta)
    x1r = (-b+sdelta)/(2*a)
    x2r = (-b-sdelta)/(2*a)
    x1i = 0
    x2i = 0
  else
    # caso radici complesse
    sdelta = Math.sqrt(-delta)
    x1r = -b/(2*a)
    x2r = -b/(2*a)
    x1i = sdelta/(2*a)
    x2i = -sdelta/(2*a)
  end

  return [x1r, x1i, x2r, x2i]
end

# Ora che abbiamo implementato la funzione,
# possiamo testarla. Ne approfittiamo per
# vedere come interpolare una stringa per inserire
# eventuali valori numerici
res = radici_quadratica(1,2,3)

puts "Prima radice:"
print "Parte reale      = ", res[0], "\n"
print "Parte imaginaria = ", res[1], "\n"

puts "Seconda radice:"
puts "Parte reale      = #{res[2]}"
puts "Parte imaginaria = #{res[3]}"