Questo documento funge da definizione completa degli standard di codifica Android di Google per il codice sorgente nel linguaggio di programmazione Kotlin. Un file sorgente Kotlin viene descritto come in stile Google Android se e solo se rispetta le regole qui riportate.
Come altre guide di stile di programmazione, i problemi trattati riguardano non solo le questioni estetiche della formattazione, ma anche altri tipi di convenzioni o standard di codifica. Tuttavia, questo documento si concentra principalmente sulle regole rigide che seguiamo universalmente ed evita di fornire consigli che non sono chiaramente applicabili (da persone o strumenti).
Ultimo aggiornamento: 06/09/2023
File di origine
Tutti i file di origine devono essere codificati come UTF-8.
Denominazione
Se un file sorgente contiene una sola classe di primo livello, il nome file
deve riflettere il nome sensibile al maiuscolo/minuscolo più l'estensione .kt. Altrimenti,
se un file di origine contiene più dichiarazioni di primo livello, scegli un nome
che descriva i contenuti del file, applica PascalCase (camelCase è
accettabile se il nome file è plurale) e aggiungi l'estensione .kt.
// MyClass.kt class MyClass { }
// Bar.kt class Bar { } fun Runnable.toBar(): Bar = Bar()
// Map.kt fun <T, O> Set<T>.map(func: (T) -> O): List<O> = emptyList() fun <T, O> List<T>.map(func: (T) -> O): List<O> = emptyList()
// extensions.kt fun MyClass.process() = { /* ... */ } fun MyResult.print() = { /* ... */ }
Caratteri speciali
Caratteri di spazio vuoto
A parte la sequenza di terminazione della riga, il carattere di spazio orizzontale ASCII (0x20) è l'unico carattere di spaziatura che compare ovunque in un file di origine. Ciò implica che:
- Tutti gli altri caratteri di spazio vuoto nei valori letterali stringa e carattere vengono sottoposti a escape.
- I caratteri di tabulazione non vengono utilizzati per il rientro.
Sequenze di escape speciali
Per qualsiasi carattere con una sequenza di escape speciale
(\b, \n, \r, \t, \', \", \\ e \$),
viene utilizzata questa sequenza anziché l'escape Unicode
corrispondente (ad es. \u000a).
Caratteri non ASCII
Per i restanti caratteri non ASCII, viene utilizzato il carattere Unicode effettivo (ad es. ∞) o l'escape Unicode equivalente (ad es. \u221e).
La scelta dipende solo da quale rende il codice
più facile da leggere e comprendere.
Le sequenze di escape Unicode sono sconsigliate per i caratteri stampabili in qualsiasi posizione e
sono fortemente sconsigliate al di fuori dei valori letterali stringa e dei commenti.
| Esempio | Discussione |
|---|---|
val unitAbbrev = "μs" |
Ottima: perfettamente chiara anche senza un commento. |
val unitAbbrev = "\u03bcs" // μs |
Scarso: non c'è motivo di utilizzare un carattere di escape con un carattere stampabile. |
val unitAbbrev = "\u03bcs" |
Scarso: il lettore non ha idea di cosa sia. |
return "\ufeff" + content |
Buono: utilizza i caratteri di escape per i caratteri non stampabili e aggiungi un commento, se necessario. |
Strutturazione
Un file .kt comprende quanto segue, in ordine:
- (Facoltativo) Intestazione del copyright e/o della licenza
- Annotazioni a livello di file
- Estratto conto del pacchetto
- Importare estratti conto
- Dichiarazioni di primo livello
Ogni sezione è separata da una riga vuota.
Copyright / Licenza
Se un'intestazione di copyright o licenza appartiene al file, deve essere posizionata immediatamente in alto in un commento su più righe.
/* * Copyright 2017 Google, Inc. * * ... */
Non utilizzare un commento in stile KDoc o in stile a una sola riga.
/** * Copyright 2017 Google, Inc. * * ... */
// Copyright 2017 Google, Inc. // // ...
Annotazioni a livello di file
Le annotazioni con la destinazione "file" use-site vengono inserite tra qualsiasi commento dell'intestazione e la dichiarazione del pacchetto.
Estratto conto del pacchetto
La dichiarazione del pacchetto non è soggetta ad alcun limite di colonne e non viene mai mandata a capo.
Importare estratti conto
Le istruzioni di importazione per classi, funzioni e proprietà sono raggruppate in un unico elenco e ordinate in formato ASCII.
Le importazioni con caratteri jolly (di qualsiasi tipo) non sono consentite.
Analogamente all'istruzione package, le istruzioni import non sono soggette a un limite di colonne e non vengono mai mandate a capo.
Dichiarazioni di primo livello
Un file .kt può dichiarare uno o più tipi, funzioni, proprietà o alias di tipo
a livello principale.
I contenuti di un file devono essere incentrati su un singolo tema. Esempi di questo tipo sono un singolo tipo pubblico o un insieme di funzioni di estensione che eseguono la stessa operazione su più tipi di ricevitore. Le dichiarazioni non correlate devono essere separate in file propri e le dichiarazioni pubbliche all'interno di un singolo file devono essere ridotte al minimo.
Non viene imposta alcuna limitazione esplicita al numero o all'ordine dei contenuti di un file.
I file di origine vengono in genere letti dall'alto verso il basso, il che significa che l'ordine, in generale, dovrebbe riflettere il fatto che le dichiarazioni più in alto influiscono sulla comprensione di quelle più in basso. File diversi possono scegliere di ordinare i propri contenuti in modo diverso. Allo stesso modo, un file può contenere 100 proprietà, un altro 10 funzioni e un altro ancora una sola classe.
L'importante è che ogni file utilizzi un ordine logico, che il suo manutentore potrebbe spiegare se gli viene chiesto. Ad esempio, le nuove funzioni non vengono aggiunte abitualmente alla fine del file, in quanto ciò produrrebbe un ordinamento "cronologico per data di aggiunta", che non è un ordinamento logico.
Ordinamento dei membri del corso
L'ordine dei membri all'interno di una classe segue le stesse regole delle dichiarazioni di primo livello.
Formattazione
Apparecchi ortodontici
Le parentesi graffe non sono necessarie per i rami when e le espressioni if
che non hanno più di un ramo else e che rientrano in una sola riga.
if (string.isEmpty()) return val result = if (string.isEmpty()) DEFAULT_VALUE else string when (value) { 0 -> return // … }
Le parentesi graffe sono altrimenti necessarie per qualsiasi ramo if, for, when, do,
e per le istruzioni e le espressioni while, anche quando il corpo è vuoto o contiene solo
una singola istruzione.
if (string.isEmpty()) return // WRONG! if (string.isEmpty()) { return // Okay } if (string.isEmpty()) return // WRONG else doLotsOfProcessingOn(string, otherParametersHere) if (string.isEmpty()) { return // Okay } else { doLotsOfProcessingOn(string, otherParametersHere) }
Blocchi non vuoti
Le parentesi graffe seguono lo stile Kernighan e Ritchie ("parentesi egiziane") per blocchi non vuoti e costrutti simili a blocchi:
- Nessun interruzione di riga prima della parentesi graffa aperta.
- Interruzione di riga dopo la parentesi graffa di apertura.
- Interruzione di riga prima della parentesi chiusa.
- Interruzione di riga dopo la parentesi graffa di chiusura, solo se questa parentesi termina un'istruzione o il corpo di una funzione, un costruttore o una classe con nome.
Ad esempio, non c'è un'interruzione di riga dopo la parentesi graffa se è seguita da
elseo da una virgola.
return Runnable { while (condition()) { foo() } }
return object : MyClass() { override fun foo() { if (condition()) { try { something() } catch (e: ProblemException) { recover() } } else if (otherCondition()) { somethingElse() } else { lastThing() } } }
Di seguito sono riportate alcune eccezioni per le classi enum.
Blocchi vuoti
Un blocco vuoto o una struttura simile a un blocco deve essere in stile K&R.
try { doSomething() } catch (e: Exception) {} // WRONG!
try { doSomething() } catch (e: Exception) { } // Okay
Espressioni
Una condizione if/else utilizzata come espressione può
omettere le parentesi graffe solo se l'intera espressione rientra in una riga.
val value = if (string.isEmpty()) 0 else 1 // Okay
val value = if (string.isEmpty()) // WRONG! 0 else 1
val value = if (string.isEmpty()) { // Okay 0 } else { 1 }
Rientro
Ogni volta che viene aperto un nuovo blocco o una nuova struttura simile a un blocco, il rientro aumenta di quattro spazi. Al termine del blocco, il rientro torna al livello precedente. Il livello di rientro si applica sia al codice che ai commenti in tutto il blocco.
Un'istruzione per riga
Ogni affermazione è seguita da un'interruzione di riga. I punti e virgola non vengono utilizzati.
Ritorno a capo automatico
Il codice ha un limite di 100 caratteri per colonna. Ad eccezione di quanto indicato di seguito, qualsiasi riga che superi questo limite deve essere mandata a capo, come spiegato di seguito.
Eccezioni:
- Righe in cui non è possibile rispettare il limite di colonne (ad esempio, un URL lungo in KDoc)
packageeimport- Righe di comando in un commento che possono essere tagliate e incollate in una shell
Dove fare una pausa
La direttiva principale del ritorno a capo è: preferisci interrompere a un livello sintattico superiore. Inoltre:
- Quando una riga viene interrotta in corrispondenza di un operatore o del nome di una funzione infissa, l'interruzione avviene dopo l'operatore o il nome della funzione infissa.
- Quando una riga viene interrotta in corrispondenza dei seguenti simboli "simili a operatori", l'interruzione
si verifica prima del simbolo:
- Il separatore punto (
.,?.). - I due punti di un riferimento al membro (
::).
- Il separatore punto (
- Il nome di un metodo o di un costruttore rimane collegato alla parentesi aperta (
() che lo segue. - Una virgola (
,) rimane collegata al token che la precede. - Una freccia lambda (
->) rimane collegata all'elenco di argomenti che la precede.
Funzioni
Quando la firma di una funzione non rientra in una singola riga, dividi ogni dichiarazione di parametro su una riga separata. I parametri definiti in questo formato devono utilizzare un solo rientro (+4). La parentesi chiusa ()) e il tipo restituito si trovano su una riga separata senza rientro aggiuntivo.
fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "" ): String { // ... }
Funzioni di espressione
Quando una funzione contiene una sola espressione, può essere rappresentata come una funzione di espressione.
override fun toString(): String { return "Hey" }
override fun toString(): String = "Hey"
Proprietà
Quando un inizializzatore di proprietà non rientra in una singola riga, vai a capo dopo il segno di uguale (=) e utilizza un rientro.
private val defaultCharset: Charset? = EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)
Le proprietà che dichiarano una funzione get e/o set devono essere inserite su
righe separate con un rientro normale (+4). Formattali utilizzando le stesse regole
delle funzioni.
var directory: File? = null set(value) { // … }
val defaultExtension: String get() = "kt"
Spazio vuoto
Verticale
Viene visualizzata una singola riga vuota:
- Tra membri consecutivi di una classe: proprietà, costruttori,
funzioni, classi nidificate e così via.
- Eccezione: una riga vuota tra due proprietà consecutive (senza altro codice tra loro) è facoltativa. Queste righe vuote vengono utilizzate in base alle necessità per creare raggruppamenti logici di proprietà e associare le proprietà alla proprietà di backup, se presente.
- Eccezione:le righe vuote tra le costanti enum sono trattate di seguito.
- Tra le istruzioni, se necessario, per organizzare il codice in sottosezioni logiche.
- Facoltativamente prima della prima istruzione di una funzione, prima del primo membro di una classe o dopo l'ultimo membro di una classe (né incoraggiato né sconsigliato).
- Come richiesto da altre sezioni di questo documento (ad esempio la sezione Struttura).
Sono consentite più righe vuote consecutive, ma non sono incoraggiate o mai richieste.
Orizzontale
Oltre a quanto richiesto dalla lingua o da altre regole di stile, e a parte i valori letterali, i commenti e KDoc, uno spazio ASCII singolo viene visualizzato solo nei seguenti punti:
- Separando qualsiasi parola riservata, ad esempio
if,forocatchda una parentesi aperta (() che la segue sulla stessa riga.// WRONG! for(i in 0..1) { }
// Okay for (i in 0..1) { }
- Separando qualsiasi parola riservata, ad esempio
elseocatch, da una parentesi graffa chiusa (}) che la precede sulla stessa riga.// WRONG! }else { }
// Okay } else { }
-
Prima di qualsiasi parentesi graffa aperta (
{).// WRONG! if (list.isEmpty()){ }
// Okay if (list.isEmpty()) { }
-
Su entrambi i lati di qualsiasi operatore binario.
// WRONG! val two = 1+1
Ciò vale anche per i seguenti simboli "simili a operatori":// Okay val two = 1 + 1
- la freccia in un'espressione lambda (
->).// WRONG! ints.map { value->value.toString() }
// Okay ints.map { value -> value.toString() }
-
i due punti (
::) di un riferimento a un membro.// WRONG! val toString = Any :: toString
// Okay val toString = Any::toString
-
il separatore punto (
.).// WRONG it . toString()
// Okay it.toString()
-
l'operatore di intervallo (
..).// WRONG for (i in 1 .. 4) { print(i) }
// Okay for (i in 1..4) { print(i) }
- la freccia in un'espressione lambda (
-
Prima dei due punti (
:) solo se utilizzati in una dichiarazione di classe per specificare una classe base o interfacce oppure se utilizzati in una clausolawhereper vincoli generici.// WRONG! class Foo: Runnable
// Okay class Foo : Runnable
// WRONG fun <T: Comparable> max(a: T, b: T)
// Okay fun <T : Comparable<T>> max(a: T, b: T)
// WRONG fun <T> max(a: T, b: T) where T: Comparable<T>
// Okay fun <T> max(a: T, b: T) where T : Comparable<T> {}
-
Dopo una virgola (
,) o due punti (:).// WRONG! val oneAndTwo = listOf(1,2)
// Okay val oneAndTwo = listOf(1, 2)
// WRONG! class Foo :Runnable
// Okay class Foo : Runnable
-
Su entrambi i lati della doppia barra (
//) che inizia un commento di fine riga. Qui sono consentiti più spazi, ma non sono obbligatori.// WRONG! var debugging = false//disabled by default
// Okay var debugging = false // disabled by default
Questa regola non viene mai interpretata come se richiedesse o vietasse spazi aggiuntivi all'inizio o alla fine di una riga; riguarda solo lo spazio interno.
Costrutti specifici
Classi enum
Un'enumerazione senza funzioni e senza documentazione sulle costanti può essere formattata facoltativamente come una singola riga.
enum class Answer { YES, NO, MAYBE }
Quando le costanti di un'enumerazione vengono inserite su righe separate, non è necessaria una riga vuota tra loro, tranne nel caso in cui definiscano un corpo.
enum class Answer { YES, NO, MAYBE { override fun toString() = """¯\_(ツ)_/¯""" } }
Poiché le classi enum sono classi, si applicano tutte le altre regole per la formattazione delle classi.
Annotazioni
Le annotazioni di membri o tipi vengono inserite su righe separate immediatamente prima del costrutto annotato.
@Retention(SOURCE) @Target(FUNCTION, PROPERTY_SETTER, FIELD) annotation class Global
Le annotazioni senza argomenti possono essere inserite su una sola riga.
@JvmField @Volatile var disposable: Disposable? = null
Quando è presente una sola annotazione senza argomenti, può essere inserita sulla stessa riga della dichiarazione.
@Volatile var disposable: Disposable? = null @Test fun selectAll() { // … }
La sintassi @[...] può essere utilizzata solo con un target di utilizzo del sito esplicito e solo per
combinare due o più annotazioni senza argomenti su una singola riga.
@field:[JvmStatic Volatile] var disposable: Disposable? = null
Tipi di proprietà/restituzione implicita
Se il corpo di una funzione di espressione o un inizializzatore di proprietà è un valore scalare o il tipo restituito può essere dedotto chiaramente dal corpo, può essere omesso.
override fun toString(): String = "Hey" // becomes override fun toString() = "Hey"
private val ICON: Icon = IconLoader.getIcon("/icons/kotlin.png") // becomes private val ICON = IconLoader.getIcon("/icons/kotlin.png")
Quando scrivi una libreria, mantieni la dichiarazione di tipo esplicita quando fa parte dell'API pubblica.
Denominazione
Gli identificatori utilizzano solo lettere e cifre ASCII e, in un numero ridotto di casi indicati di seguito, trattini bassi. Pertanto, ogni nome di identificatore valido corrisponde all'espressione regolare \w+.
I prefissi o i suffissi speciali, come quelli mostrati negli esempi
name_, mName, s_name e kName, non vengono utilizzati, tranne nel caso di
proprietà di backup (vedi
Proprietà di backup).
Nomi pacchetto
I nomi dei pacchetti sono tutti in minuscolo e le parole consecutive vengono semplicemente concatenate (senza trattini bassi).
// Okay package com.example.deepspace // WRONG! package com.example.deepSpace // WRONG! package com.example.deep_space
Nomi dei tipi
I nomi delle classi sono scritti in PascalCase e in genere sono nomi o sintagmi
nominali. Ad esempio, Character o ImmutableList. I nomi delle interfacce possono
anche essere sostantivi o sintagmi nominali (ad esempio, List), ma
a volte possono essere aggettivi o sintagmi aggettivali (ad esempio Readable).
Le classi di test iniziano con il nome della classe che stanno testando e terminano con Test. Ad esempio, HashTest o
HashIntegrationTest.
Nomi delle funzioni
I nomi delle funzioni sono scritti in camelCase e sono in genere verbi o frasi verbali. Ad esempio, sendMessage o stop.
I trattini bassi sono consentiti nei nomi delle funzioni di test per separare i componenti logici del nome.
@Test fun pop_emptyStack() { // … }
Le funzioni annotate con @Composable che restituiscono Unit sono in formato PascalCase e denominate come sostantivi, come se fossero tipi.
@Composable fun NameTag(name: String) { // … }
I nomi delle funzioni non devono contenere spazi perché questa funzionalità non è supportata su tutte le piattaforme (in particolare, non è completamente supportata su Android).
// WRONG! fun `test every possible case`() {} // OK fun testEveryPossibleCase() {}
Nomi delle costanti
I nomi delle costanti utilizzano UPPER_SNAKE_CASE: tutte le lettere maiuscole, con le parole separate da trattini bassi. Ma che cos'è esattamente una costante?
Le costanti sono proprietà val senza funzione get personalizzata, il cui contenuto è
profondamente immutabile e le cui funzioni non hanno effetti collaterali rilevabili. Ciò include tipi immutabili e raccolte immutabili di tipi immutabili, nonché scalari e stringhe se contrassegnati come const. Se uno qualsiasi degli stati osservabili di un'istanza può cambiare, non è una costante. La semplice intenzione di
non modificare mai l'oggetto non è sufficiente.
const val NUMBER = 5 val NAMES = listOf("Alice", "Bob") val AGES = mapOf("Alice" to 35, "Bob" to 32) val COMMA_JOINED = NAMES.joinToString(", ") val EMPTY_ARRAY = arrayOf<SomeMutableType>()
Questi nomi sono in genere sostantivi o sintagmi nominali.
I valori costanti possono essere definiti solo all'interno di un object
o come dichiarazione di primo livello. I valori che altrimenti soddisfano il requisito di una costante, ma definiti all'interno di un class, devono utilizzare un nome non costante.
Le costanti che sono valori scalari devono utilizzare il const
modificatore.
Nomi non costanti
I nomi non costanti sono scritti in camelCase. Questi si applicano a proprietà dell'istanza, proprietà locali e nomi dei parametri.
val variable = "var" val nonConstScalar = "non-const" val mutableCollection: MutableSet<String> = HashSet() val mutableElements = listOf(mutableInstance) val mutableValues = mapOf("Alice" to mutableInstance, "Bob" to mutableInstance2) val logger = Logger.getLogger(MyClass::class.java.name) val nonEmptyArray = arrayOf("these", "can", "change")
Questi nomi sono in genere sostantivi o sintagmi nominali.
Proprietà di supporto
Quando è necessaria una proprietà di backup, il suo nome deve corrispondere esattamente a quello della proprietà reale, tranne che per il prefisso con un trattino basso.
private var _table: Map<String, Int>? = null val table: Map<String, Int> get() { if (_table == null) { _table = HashMap() } return _table ?: throw AssertionError() }
Digitare i nomi delle variabili
Ogni variabile di tipo ha un nome in uno dei due stili:
- Una singola lettera maiuscola, seguita facoltativamente da un
singolo numero (ad esempio
E,T,X,T2) - Un nome nel formato utilizzato per le classi, seguito dalla lettera
maiuscola
T(ad esempioRequestT,FooBarT)
Camel case
A volte esiste più di un modo ragionevole per convertire una frase inglese in camel case, ad esempio quando sono presenti acronimi o costrutti insoliti come "IPv6" o "iOS". Per migliorare la prevedibilità, utilizza il seguente schema.
A partire dalla forma in prosa del nome:
- Converti la frase in ASCII semplice e rimuovi gli apostrofi. Ad esempio, "Algoritmo di Müller" potrebbe diventare "Algoritmo di Muellers".
- Dividi questo risultato in parole, separando gli spazi e la punteggiatura rimanente (in genere i trattini). Consigliato:se una parola ha già un aspetto camel case convenzionale nell'uso comune, dividila nelle sue parti costituenti (ad es. "AdWords" diventa "ad words"). Tieni presente che una parola come "iOS" non è in camel case di per sé; non rispetta alcuna convenzione, quindi questo consiglio non si applica.
- Ora converti tutto in minuscolo (incluse le abbreviazioni), poi esegui una delle seguenti operazioni:
- Metti in maiuscolo il primo carattere di ogni parola per ottenere il formato Pascal.
- Metti in maiuscolo il primo carattere di ogni parola, tranne la prima, per ottenere il camel case.
- Infine, unisci tutte le parole in un unico identificatore.
Tieni presente che la distinzione tra maiuscole e minuscole delle parole originali viene quasi completamente ignorata.
| Prose form | Corretto | Risposta sbagliata |
|---|---|---|
| "XML Http Request" | XmlHttpRequest |
XMLHTTPRequest |
| "new customer ID" | newCustomerId |
newCustomerID |
| "cronometro interno" | innerStopwatch |
innerStopWatch |
| "supporta IPv6 su iOS" | supportsIpv6OnIos |
supportsIPv6OnIOS |
| "YouTube importer" | YouTubeImporter |
YoutubeImporter* |
(* Accettabile, ma non consigliato.)
Documentazione
Formattazione
La formattazione di base dei blocchi KDoc è illustrata in questo esempio:
/** * Multiple lines of KDoc text are written here, * wrapped normally… */ fun method(arg: String) { // … }
… o in questo esempio su una sola riga:
/** An especially short bit of KDoc. */
Il modulo base è sempre accettabile. Il modulo a una sola riga può essere sostituito quando l'intero blocco KDoc (inclusi i marcatori di commento) può essere contenuto in una sola riga. Tieni presente che questa opzione si applica solo quando non sono presenti
tag di blocco come @return.
Paragrafi
Tra i paragrafi e prima del gruppo di tag di blocco, se presenti, viene visualizzata una riga vuota, ovvero una riga contenente solo l'asterisco iniziale allineato
(*).
Tag di blocco
I "tag di blocco" standard utilizzati vengono visualizzati nell'ordine
@constructor, @receiver, @param, @property, @return,
@throws, @see e non vengono mai visualizzati con una descrizione vuota.
Quando un tag di blocco non rientra in una singola riga,
le righe di continuazione sono rientrate di 4 spazi rispetto alla posizione di @.
Frammento di riepilogo
Ogni blocco KDoc inizia con un breve frammento di riepilogo. Questo frammento è molto importante: è l'unica parte del testo che viene visualizzata in determinati contesti, come gli indici di classi e metodi.
Si tratta di un frammento, ovvero di una frase nominale o verbale, non di una frase completa.
Non inizia con "A `Foo` is a...",
o "This method returns...",
né deve formare una frase imperativa completa come
"Save the record.". Tuttavia, il frammento è scritto in maiuscolo e
punteggiato come se fosse una frase completa.
Utilizzo
Come minimo, KDoc è presente per ogni tipo di public e per ogni membro public o protected di questo tipo, con alcune eccezioni indicate di seguito.
Eccezione: funzioni autoesplicative
KDoc è facoltativo per le funzioni "semplici e ovvie" come getFoo
e le proprietà come foo, nei casi in cui non c'è davvero nient'altro di utile da dire se non "Restituisce foo".
Non è opportuno citare questa eccezione per giustificare l'omissione di informazioni pertinenti che un lettore tipo potrebbe aver bisogno di conoscere. Ad esempio, per
una funzione denominata getCanonicalName o una proprietà denominata canonicalName,
non omettere la documentazione (con la motivazione che direbbe solo
/** Returns the canonical name. */) se un lettore tipico potrebbe non avere
idea di cosa significhi il termine "nome canonico".
Eccezione: override
KDoc non è sempre presente in un metodo che esegue l'override di un metodo supertipo.