Go – specifiche del linguaggio – prima parte

Comincio in questo post a raccontare brevemente le specifiche del linguaggio Go, rimandando per una descrizione più approfondita a The Go Programming Language Specification

Anzi no! Ci ho provato ma viene una pizza di quelle che uno salta anche nel libro scritto su carta. Facciamo così: vale il link per le cose normali e sensate — quelle del C/C++ — qui annoto solo le novità. Verrà lo stesso una serie di post noiosi: assicurarsi il caffè (tanto) a portata di mano. Se poi non finite il post non mi offendo, vi capisco.

Caratteri
Tutti i caratteri sono unicode. Finiti per sempre i bei tempi dell’ASCII.

Commenti
Uguale-uguale a C++.

Punti-e-virgola
Qui un meraviglioso balzo in avanti rispetto al C, ma essendo nuovo di pacca richiede qualche attenzione, anzi la traduzione della specifica.
La grammatica formale usa “;” come terminatore in numerosi costrutti (productions). I programmi in Go possono omettere la maggior parte di questi punti-e-virgola usando le due regole seguenti:

  • Quando l’input è suddiviso in tokens un “;” è automaticamente inserito alla fine di una riga non-blank se il token finale è:
    • un identificatore
    • un numero intero, reale o immaginario, un carattere o una stringa
    • una delle parole riservate break, continue, fallthrough, o return
    • uno degli operatori e delimitatori ++, , ), ] o }
  • Per permettere istruzioni complesse di essere contenute in una singola riga il “;” può essere omesso prima di “)” o “}“. (Questa frase suona mysteriosa, assay: appena capisco cosa vuol dire ve lo farò sapere, promesso).

Identificatori
Definisono entità come variabili e tipi; un identificatore è una sequenza di una o più lettere e numeri; devono iniziare con una lettera. Esempi:

a
_x9  // _ è considerato una lettera
ThisVariableIsExported // inizia con una lettera Maiuscola, è visibile
                       // al di fuori del package in cui è definita
αβ // sì, grazie a Unicode possono essere usati caratteri esotici,
   // anche 磨 anche se nessuno --OK io, parlo per me--
   // saprà mai cosa vuol dire

Questo è sconvolgente: non solo avremo identificatori con i nomi non mnemonici (à la katso) ma etnici! Sarà vero? È il caso di provare, ecco okp.go:

package main

import "fmt"

func main(){
    确定 := "OK"
    恐慌 := "panico!"
    var ok, panico string
    ok, panico = "quèdìng", "kǒnghuāng"
    fmt.Printf("确定 恐慌\n(%s %s)\n%s, %s\n", ok, panico, 确定, 恐慌)
}

ed ecco cosa succede:

Dubbio: se uno si trova le variabili così e si lamenta è razzista? Ai posteri l’ardua sentenza (cit.).

Parole riservate
Le seguenti keywords sono riservate e non possono essere usate come identificatori:

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

Operatori e delimitatori
Le seguenti sequenze di caratteri rappresentano operatori, delimitatori e altri token speciali:

+    &     +=    &=     &&    ==    !=    (    )
-    |     -=    |=     ||    <     <=    [    ]
*    ^     *=    ^=     <-    >     >=    {    }
/    <<    /=    <<=    ++    =     :=    ,    ;
%    >>    %=    >>=    --    !     ...   .    :
&^   &^=

Numeri (costanti) interi, reali e immaginari
Tutto come previsto. Gli immaginari sono la parte immaginaria di un numero complesso. Consistono di un floating-point seguito dalla lettera minuscola “i

Costanti carattere
Uno o più caratteri Unicode racchiusi tra apici. Valgono le solite sequenze di escape con “\“. Esempi:

'a'
'ä'
'本'
'\t'
'00'
'07'
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'

Costanti stringa
Sono di due tipi: raw string literals e interpreted string literals.
Questo è simile, ma meglio, di alcuni linguaggi moderni: Python, Fortran, … Solo che ' è già usato per i caratteri e allora `.
Raw string literals sono sequenze di caratteri delimitate da accento graveback quote — “`“. (In Linux Alt Gr + ', in Windoze 96 sul tastierino numerico tenendo premuto Alt).
La stringa può contenere qualsiasi carattere eccetto l’accento grave; il backslash non è speciale e la stringa può essere su più righe.
Interpreted string literals solo sequenze di caratteri tra doppi apici . Il testo non può essere su più linee, le sequenze di backslash sono interpretate. \' è illegale, \” è legale. Possono essere usate tutte le sequenze descritte prima come sequenze carattere.

Costanti
Le constati possono essere un booleano, un intero, un floating-point, un numero immaginario, un carattere, una stringa, un identificatore denotante una costante o il risultato di certe funzioni built-in.
Le costanti numeriche (intere, floating-point e complesse) hanno precisione arbitraria e non sono soggette a overflow: niente più 12L.
Le sostanti possono essere tipizzate (typed) o no.
A una costante può essere assegnato il tipo esplicitamente nella dichiarazione o nella conversione o implicitamente quando usata in una dichiarazione di variabile o in un assegnamento o come operando in un’espressione.
Non c’è nessuna costante che denoti infinito e not-a-number ma nel package math le funzioni Inf, NaN, IsInf e IsNaN ritornano e verificano per questi valori a run-time.

Tipi
Il tipo determina i valori e le operazioni specifiche del tipo stesso.
Quasi come in C, con variazioni: da leggere sul documento originale. Il tipo string si comporta come un array di byte, una volta settati sono immutabili. Cioè è illegale assegnare un valore a &s[i].

Array
Gli array (quelli che una volta si chiamavano vettori e matrici) sono una sequesnza numerata di elementi dello stesso tipo chiamato tipo dell’array. Il numero degli elementi è chiamato lunghezza dell’array.
Rispetto al C e ai linguaggi usuali cambia il modo di scrivere la dichiarazione:

ArrayType   = "[" ArrayLength "]" ElementType
ArrayLength = Expression
ElementType = Type

La lunghezza è parte del tipo dell’array e dev’essere un’espressione costante che dia un risultato intero non negativo. Può essere ritrovata con la funzione len(a). Come nel C gli indici sono compresi in [0 .. len(a)-1]. I tipi sono sempre monodimensionali ma possono essere composti per creare tipi multidimensionali.
Esempi:

[32]byte
[2*N] struct { x, y int32 }
[1000]*float64
[3][5]int
[2][2][2]float64  // equivalente a [2]([2]([2]float64))

Slice
Qui se qualcuno sa come si traduce slice e me lo dice avrà per sempre la mia riconoscenza e una targa virtuale con il suo nome impressa nella mia memoria, emisfero sinistro, giurin-giuretta.
Per quel che ne so si dovrebbe dire “fetta” o “porzione” o “pezzo” ma non so se si usa e allora continuerò a usare slice, almeno fino all’arrivo di una dritta di cui al precedente paragrafo.
Una slice è un riferimento a un segmento contiguo di un array e contiene una sequenza numerata di elementi di quello stesso array. Il valore di una slice non ininizializzata è nil

SliceType = "[" "]" ElementType

Come gli array sono indicizzati e hanno una lunghezza, rintracciabile con len(s). A differenza degli array la lunghezza può variare durante l’esecuzione. Gli elementi sono indicizzati, ovviamente, tra 0 e len(s)-1.
Una volta inizializzato una slice è sempre associata all’array cui si riferisce. Quindi la slice condivide (share) la stessa allocazione di memoria dell’array e di altre slice dello stesso array.
L’array sottostante la slice può estendersi oltre la fine della slice. La capacità (capacity) misura questa estensione: è la somma della lunghezza della slice e la lunghezza dell’array oltre questa slice. La capacità può essere ritrovata con cap(a).
Una slice non inizializzata per il tipo di elementi T è costruita con make() che prende il tipo, la lunghezza e, opzionalmente, la capacità.

make([]T, length)
make([]T, length, capacity)

La chiamata a make() alloca un nuovo array nascosto al quale la slice si riferisce. Cioè eseguendo

make([]T, length, capacity)

si produce la stessa slice come creare l’array e slice-izzandolo (ahemm…), cosicchè i due esempi sono producono lo stesso effetto:

make([]int, 50, 100)
new([100]int)[0:50]

Come per gli array le slice sono sempre monodimensionali ma possono essere composte per creare oggetti di più dimensioni. Per gli array di array gli array costituenti sono sempre della stessa lunghezza per costruzione; diversamente per le slice di slice (o array di slice) le lunghezza possono cambiare dinamicamente. Inoltre le slice costituenti devono essere allocate individualmente, con make().

A questo punto
Time out 😀 (sempre che ci sia ancora qualcuno 8)
Credo ci sia parecchia carne al fuoco, cose ereditate dal C e cose nuove.
Ad esempio le slice m’intrigano. Roba per le prossime puntate, forse 😉

Posta un commento o usa questo indirizzo per il trackback.

Commenti

  • lightuono  Il 13 marzo 2011 alle 12:52

    Gli identificatori fatti così sono il MALE. Immagina un codice sorgente di un programmatore GO Giapponese. Immagine di capire e decodificare le variabili scritte nella loro lingua. Il PANICO :D!

    • juhan  Il 13 marzo 2011 alle 13:02

      Lightuono ci hai raggione centopeccento 😀
      Ma com’è che ti trovi all’alba (quasi) della domenica a leggere queste cose?

Lascia un commento

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.