• Non ci sono risultati.

2.3 Sintassi e funzionalit` a di Kotlin

2.3.1 Hello world

La modalit`a pi`u rapida per provare il linguaggio senza necessit`a di installare alcun software `e quella di utilizzare Kotlin Koans Online11: `e infatti possibile esegui-

re codice utilizzando le implementazioni JVM Kotlin o JavaScript e scegliere la versione di Kotlin desiderata fra le differenti disponibili.

La funzione main, come per Java, rimane il punto di partenza per ogni ap- plicazione Kotlin; questa funzione viene chiamata quando il programma si avvia (listato 2.7):

1 fun main ( a r g s : Array<String>) {

2 p r i n t l n (" H e l l o w o r l d ! ")

3 }

Listato 2.7: Esempio di Hello world in Kotlin

Nelle applicazioni Android, tuttavia, la funzione main non viene mai scritta di- rettamente dal programmatore; essa viene infatti chiamata implicitamente dal framework, quindi in questo specifico caso non pu`o essere utilizzata in maniera esplicita per eseguire un Hello world in Kotlin. Nel successivo listato 2.8 vie- ne dunque mostrato il codice Kotlin necessario per far apparire un messaggio di saluto all’interno di una TextView nell’activity principale:

1 import k o t l i n x . a n d r o i d . s y n t h e t i c . main . a c t i v i t y m a i n . t e x t V i e w

2

3 c l a s s M a i n A c t i v i t y : AppCompatActivity ( ) {

4 override fun o n C r e a t e ( s a v e d I n s t a n c e S t a t e : Bundle ? ) {

5 super. o n C r e a t e ( s a v e d I n s t a n c e S t a t e )

6 s e t C o n t e n t V i e w (R . l a y o u t . a c t i v i t y m a i n )

7 t e x t V i e w . t e x t = " H e l l o w o r l d ! "

8 }

9 }

Listato 2.8: Esempio di Hello world in Kotlin su Android

Come si pu`o da subito notare, una caratteristica ben visibile che contraddistin- gue questo linguaggio da Java `e sicuramente l’assenza del punto e virgola come

terminatore delle istruzioni: in Kotlin non `e difatti pi`u necessario, a meno che si vogliano concatenare pi`u istruzioni su una stessa linea di codice.

A parte quest’evidente differenza di base, ora non `e necessario comprendere perfettamente le altre caratteristiche e meccanismi mostrati nei due esempi prece- denti (utili soprattutto per farsi un’idea generale della sintassi di Kotlin), poich´e verranno spiegati nel dettaglio successivamente.

2.3.2

Variabili

In Kotlin tutto `e rappresentato da oggetti, di conseguenza anche le variabili pos- siedono sempre un tipo oggetto e mai tipi primitivi12, poich´e il linguaggio non ne

prevede (diversamente da Java); questo rende il codice meno complesso.

Le variabili in Kotlin possono essere dichiarate utilizzando una delle due parole chiave: var oppure val.

La prima indica un riferimento mutabile che pu`o subire modifiche e aggior- namenti dopo l’inizializzazione; `e l’equivalente di una ‘normale‘ (cio`e non finale) variabile in Java. Dunque se una variabile necessita di cambiare valore nel tempo, essa deve necessariamente essere dichiarata usando la parola chiave var.

La seconda invece, val, indica un riferimento immutabile (read-only) che non pu`o essere riassegnato una volta inizializzato; `e l’equivalente di una variabile finale (dichiarata utilizzando il modificatore final) in Java. Utilizzare una variabile di tipo val `e utile e sempre consigliato ove possibile, in quanto assicura che la stessa non venga mai modificata erroneamente. Risulta inoltre vantaggioso impiegare variabili di questa tipologia quando si lavora con pi`u thread: poich´e promuovono immutabilit`a, semplificando la sincronizzazione degli accessi [22].

Un semplice esempio esplicativo nel seguente listato 2.9:

1 var a n i m a l = " cat "

2 a n i m a l = " l i o n " // C o r r e c t

3

4 val c r a f t = " p a i n t e r "

5 c r a f t = " s c u l p t o r " // C o m p i l a t i o n e r r o r : val c a n n o t be r e a s s i g n e d

Listato 2.9: Esempio di variabili dichiarate var e val

Da notare che quando si utilizza val non si `e pi`u in grado di cambiare il riferimento che punta ad un particolare oggetto, ma questo non sempre significa che non si possano modificare le propriet`a interne dell’oggetto stesso. La parola chiave val non pu`o infatti garantire che l’oggetto referenziato sia immutabile. Per chiarire il concetto, viene mostrato un esempio nel listato 2.10:

12In realt`a alcuni tipi oggetto particolari, quali quelli per indicare numeri, caratteri e booleani, vengono rappresentati (se non nulli) tramite i rispettivi tipi primitivi a tempo d’esecuzione; tuttavia il processo `e del tutto trasparente e l’utente li pu`o (li deve) sempre trattare come ordinarie classi: la conversione `e implicita e scaricata sul compilatore.

1 val l i s t = m u t a b l e L i s t O f (" a ", " b ", " c ")

2 l i s t . remove (" a ") // L i s t m o d i f i e d , c o r r e c t

3 l i s t = m u t a b l e L i s t O f (" d ", " e ") // R e f e r e n c e m o d i f i e d , i n c o r r e c t !

Listato 2.10: Variabile val, modifica dello stato dell’oggetto e del riferimento

Se `e invece necessario che un oggetto non venga in alcun modo modificato, allora si deve utilizzare un riferimento immutabile e un oggetto immutabile: al fine di favorire l’uso di strutture dati immutabili, la libreria standard di Kotlin contiene un equivalente immutabile per ogni collezione (List per MutableList, Map per MutableMap, e cos`ı via).

2.3.3

Tipi di dato

I tipi di dato presenti in Kotlin si ispirano a quelli di Java, sebbene si possano fa- cilmente rilevare alcune differenze importanti che meritano di essere sottolineate. Come gi`a specificato precedentemente, una differenza risiede nel fatto che il type system di Kotlin non prevede tipi di dato primitivi (posseduti invece da Java), poich´e il linguaggio abbraccia una filosofia totalmente a oggetti; tuttavia, que- sta non `e l’unica differenza che contraddistingue Kotlin dal suo predecessore (le rimanenti disparit`a verranno presto evidenziate).

In questa sottosezione vengono elencati e descritti separatamente i tipi di dato di base presenti in Kotlin, fondamentali per la rappresentazione rispettivamente di numeri, caratteri, booleani, vettori e stringhe.

Numeri

I tipi di dato per rappresentare i numeri in Kotlin (tabella 2.1) sono simili a quelli presenti in Java, tranne per il fatto che non esistono implicite conversioni fra tipi compatibili e che Char non pu`o contenere numeri (esempi nel listato 2.11).

Type Bit width Byte 8 Short 16 Int 32 Long 64 Float 32 Double 64

Tabella 2.1: Tipi di dato per rappresentare i numeri in Kotlin

1 val s : Short = 3

2 val i 1 : Int = s // Error , i n c o r r e c t t y p e c o n v e r s i o n !

3 val i 2 : Int = s . t o I n t ( ) // C o r r e c t t y p e c o n v e r s i o n

4

5 val b : Char = 1 // Error , i n c o r r e c t !

Listato 2.11: Alcuni esempi con tipi di dato numerici in Kotlin

Un’altra differenza con Java sta nel fatto che in Kotlin non sono supportate le costanti letterali per i valori in ottale.

Caratteri

I caratteri in Kotlin sono rappresentati dal tipo di dato Char che, come mostrato nel precedente listato 2.11, non pu`o contenere numeri.

Come per Java, i caratteri devono essere essere delimitati necessariamente da apici semplici e quelli speciali devono iniziare con un backslash. Le sequenze di escape supportate sono \t, \b, \n, \r, \’, \", \\, \$ e \u.

Nel prossimo listato 2.12 sono presenti alcuni esempi:

1 val c 1 : Char = ’ z ’

2 val c 2 : Char = " z " // I n c o r r e c t : " z " is a S t r i n g !

3

4 val i : Int = ’ 3 ’ . t o I n t ( ) // Correct , ’3 ’ is a C h a r

5

6 val c 3 : Char = ’ \ uFF00 ’ // C o r r e c t use of e s c a p e s e q u e n c e

Booleani

I booleani in Kotlin sono rappresentati dal tipo di dato Boolean. Questo pu`o assumere come prevedibile soltanto sue possibili valori: true o false.

Sono inoltre supportate la operazioni standard built-in che sono generalmente disponibili anche in altri moderni linguaggi di programmazione:

• || : rappresenta l’OR logico. Restituisce true quando uno dei due predicati ritorna true.

• && : rappresenta l’AND logico. Restituisce true quando entrambi i predicati ritornano true.

• ! : operatore di negazione. Restituisce true per false e viceversa.

Come accade in Java, || e && sono valutati in maniera lazy (rispettivamente tramite lazy disjunction e lazy conjunction).

Vettori

In Kotlin, i vettori (array) vengono rappresentati dalla classe Array, che possiede i metodi get e set per prelevare ed impostare valori e il campo size per ottenere la lunghezza del vettore.

Diversamente da Java, gli array in Kotlin sono invarianti; questo significa che in Kotlin non `e permesso assegnare un Array<Int> a un Array<Any>, per pre- venire possibili errori a tempo di esecuzione. Si possono definire in Kotlin array covarianti con Array<out Any> (che corrisponde ad Array<? extends Object> in Java) oppure array controvarianti con Array<in String> (che corrisponde ad Array<? super String> in Java).

Per creare un vettore pu`o essere utilizzata la funzione di libreria arrayOf(), a cui passare come argomenti i valori da inserire, oppure direttamente il costruttore di Array che prende in ingresso la lunghezza e una funzione che restituisce il valore di ogni elemento del vettore per ogni dato indice. Alcuni esempi nel listato 2.13:

1 val a r r a y = a r r a y O f ( 1 , 2 , 3 , 4 ) // I n f e r r e d t y p e : Array < Int >

2 val a r r a y 2 : Array<Long> = a r r a y O f ( 1 , 2 , 3 , 4 )

3

4 // C r e a t e s an Array < String > w i t h v a l u e s ["0" , "3" , "6" , "9" , "12" , " 1 5 " ]

5 val a r r a y 3 = Array( 6 , { i −> ( i ∗ 3 ) . t o S t r i n g ( ) } )

Stringhe e string templates

Il comportamento delle stringhe in Kotlin `e simile a quello visibile in Java, con alcuni miglioramenti.

Le stringhe in Kotlin si indicano con il tipo di dato String e sono, come in Java, immutabili.

´

E possibile accedere agli elementi delle stringhe tramite l’indexing operator (per esempio str[i]), nello stesso modo in cui si accede agli elementi di un vettore, op- pure tramite l’iterazione all’interno di un ciclo. La concatenazione di pi`u stringhe avviene come in Java tramite l’operatore + e funziona anche quando `e necessario concatenare stringhe e altri tipi di valori.

Nonostante sia presente l’operatore di concatenazione, `e spesso preferibile uti- lizzare i cosiddetti string templates: `e possibile posizionare una variabile all’inter- no di una stringa tramite l’uso del carattere $ che funge da segnaposto. Durante l’interpolazione, i segnaposto vengono rimpiazzati con i rispettivi valori. Questo meccanismo rende il codice pi`u ordinato, evitando di dividere la stringa in porzioni ogniqualvolta occorra inserire il valore di una variabile o di un’espressione.

Nel listato 2.14 vengono mostrati alcuni esempi:

1 val s t r = " H e l l o " 2 val c = s t r[1] // I n f e r r e d t y p e : C h a r 3 f o r ( i in s t r ) { 4 // ... 5 } 6 7 val s t r 2 = " a l f a " + 1 + " b e t a " + 2 // s t r 2 = " a l f a 1 b e t a 2 " 8 9 val i = 30 10 p r i n t l n (" i = $i ") // P r i n t s " i = 30" 11 12 val s t r 3 = " a b c d e " 13 p r i n t l n (" $ s t r 3 . l e n g t h is $ { s t r 3 . l e n g t h } ") // P r i n t s " a b c d e . l e n g t h is 5"

Listato 2.14: Alcuni esempi di utilizzo delle stringhe e string templates in Kotlin

Documenti correlati