Kotlin स्टाइल गाइड

यह दस्तावेज़, Kotlin प्रोग्रामिंग लैंग्वेज में सोर्स कोड के लिए, Google के Android कोडिंग स्टैंडर्ड की पूरी परिभाषा के तौर पर काम करता है. किसी Kotlin सोर्स फ़ाइल को Google Android Style में तब ही माना जाता है, जब वह यहां दिए गए नियमों का पालन करती हो.

प्रोग्रामिंग की अन्य स्टाइल गाइड की तरह, इसमें फ़ॉर्मैटिंग की सिर्फ़ सामान्य समस्याएं शामिल नहीं हैं. इसमें अन्य तरह के नियम या कोडिंग स्टैंडर्ड भी शामिल हैं. हालांकि, इस दस्तावेज़ में मुख्य रूप से उन नियमों के बारे में बताया गया है जिनका हम हर जगह पालन करते हैं. साथ ही, इसमें ऐसी सलाह नहीं दी गई है जिसे साफ़ तौर पर लागू नहीं किया जा सकता. भले ही, इसे किसी व्यक्ति या टूल के ज़रिए लागू किया जाना हो.

पिछली बार अपडेट करने का समय: 06-09-2023

सोर्स फ़ाइलें

सभी सोर्स फ़ाइलें, UTF-8 के तौर पर एन्कोड होनी चाहिए.

इन्हें

अगर किसी सोर्स फ़ाइल में सिर्फ़ एक टॉप-लेवल क्लास है, तो फ़ाइल के नाम में केस-सेंसिटिव नाम के साथ-साथ .kt एक्सटेंशन भी होना चाहिए. अगर सोर्स फ़ाइल में कई टॉप-लेवल डिक्लेरेशन शामिल हैं, तो फ़ाइल के कॉन्टेंट के हिसाब से कोई नाम चुनें. साथ ही, PascalCase (अगर फ़ाइल का नाम प्लूरल है, तो camelCase का इस्तेमाल किया जा सकता है) लागू करें और .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() = { /* ... */ }

विशेष वर्ण

खाली सफ़ेद जगह वाले वर्ण

लाइन खत्म करने वाले क्रम के अलावा, ASCII हॉरिज़ॉन्टल स्पेस वर्ण (0x20) ही ऐसा व्हाइटस्पेस वर्ण है जो किसी सोर्स फ़ाइल में कहीं भी दिखता है. इसका मतलब है कि:

  • स्ट्रिंग और वर्ण लिटरल में मौजूद अन्य सभी खाली सफ़ेद जगहों को मार्क किया जाता है, ताकि उन्हें यूआरएल के हिस्से के तौर पर नहीं, बल्कि अलग पढ़ा जा सके.
  • इंडेंटेशन के लिए, टैब वर्णों का इस्तेमाल नहीं किया जाता है.

खास एस्केप सीक्वेंस

ऐसे वर्ण के लिए जिसका खास एस्केप सीक्वेंस (\b, \n, \r, \t, \', \", \\, और \$) होता है, उस सीक्वेंस का इस्तेमाल किया जाता है. इसके बजाय, उससे जुड़े यूनिकोड (जैसे, \u000a) एस्केप का इस्तेमाल नहीं किया जाता.

ऐसे वर्ण जो ASCII में शामिल नहीं हैं

बिना ASCII वाले बाकी वर्णों के लिए, असली यूनिकोड वर्ण (जैसे, ) या उसके जैसा यूनिकोड एस्केप (जैसे, \u221e) का इस्तेमाल किया जाता है. यह सिर्फ़ इस बात पर निर्भर करता है कि कोड को पढ़ना और समझना आसान हो. यूनिकोड एस्केप का इस्तेमाल, प्रिंट किए जा सकने वाले वर्णों के लिए किसी भी जगह पर नहीं करना चाहिए. साथ ही, स्ट्रिंग लिटरल और टिप्पणियों के बाहर इनका इस्तेमाल बिलकुल नहीं करना चाहिए.

उदाहरण चर्चा
val unitAbbrev = "μs" सबसे अच्छा: टिप्पणी के बिना भी साफ़ तौर पर समझ में आ रहा है.
val unitAbbrev = "\u03bcs" // μs खराब: प्रिंट किए जा सकने वाले वर्ण के साथ एस्केप का इस्तेमाल करने की कोई वजह नहीं है.
val unitAbbrev = "\u03bcs" खराब: रीडर को यह नहीं पता कि यह क्या है.
return "\ufeff" + content सही तरीका: प्रिंट न किए जा सकने वाले वर्णों के लिए, एस्केप का इस्तेमाल करें. साथ ही, अगर ज़रूरी हो, तो टिप्पणी करें.

संरचना

.kt फ़ाइल में, क्रम से ये चीज़ें शामिल होती हैं:

  • कॉपीराइट और/या लाइसेंस हेडर (ज़रूरी नहीं)
  • फ़ाइल-लेवल के एनोटेशन
  • पैकेज स्टेटमेंट
  • स्टेटमेंट इंपोर्ट करना
  • टॉप-लेवल के एलान

इनमें से हर सेक्शन को ठीक एक खाली लाइन से अलग किया गया है.

अगर फ़ाइल में कॉपीराइट या लाइसेंस हेडर शामिल करना है, तो उसे मल्टी-लाइन कमेंट में सबसे ऊपर रखना चाहिए.

/*
 * Copyright 2017 Google, Inc.
 *
 * ...
 */
 

KDoc-स्टाइल या सिंगल-लाइन-स्टाइल वाली टिप्पणी का इस्तेमाल न करें.

/**
 * Copyright 2017 Google, Inc.
 *
 * ...
 */
// Copyright 2017 Google, Inc.
//
// ...

फ़ाइल-लेवल के एनोटेशन

"file" use-site target वाले एनोटेशन, हेडर कमेंट और पैकेज डिक्लेरेशन के बीच रखे जाते हैं.

पैकेज स्टेटमेंट

पैकेज स्टेटमेंट में कॉलम की कोई सीमा नहीं होती है और यह कभी भी लाइन-रैप नहीं होता है.

स्टेटमेंट इंपोर्ट करना

क्लास, फ़ंक्शन, और प्रॉपर्टी के लिए इंपोर्ट स्टेटमेंट को एक सूची में ग्रुप किया जाता है और ASCII के हिसाब से क्रम में लगाया जाता है.

किसी भी तरह के वाइल्डकार्ड इंपोर्ट की अनुमति नहीं है.

पैकेज स्टेटमेंट की तरह, इंपोर्ट स्टेटमेंट में भी कॉलम की कोई सीमा नहीं होती. साथ ही, इन्हें कभी भी लाइन-रैप नहीं किया जाता.

टॉप-लेवल के एलान

.kt फ़ाइल में, टॉप-लेवल पर एक या उससे ज़्यादा टाइप, फ़ंक्शन, प्रॉपर्टी या टाइप के उपनामों का एलान किया जा सकता है.

किसी फ़ाइल का कॉन्टेंट, एक ही थीम पर आधारित होना चाहिए. इसके उदाहरण के तौर पर, एक ही सार्वजनिक टाइप या एक्सटेंशन फ़ंक्शन का ऐसा सेट हो सकता है जो कई रिसीवर टाइप पर एक ही कार्रवाई करता हो. अलग-अलग तरह के एलान को अलग-अलग फ़ाइलों में रखना चाहिए. साथ ही, एक ही फ़ाइल में सार्वजनिक एलान कम से कम होने चाहिए.

फ़ाइल के कॉन्टेंट की संख्या या क्रम पर कोई पाबंदी नहीं है.

सोर्स फ़ाइलों को आम तौर पर ऊपर से नीचे की ओर पढ़ा जाता है. इसका मतलब है कि क्रम में यह दिखना चाहिए कि ऊपर दिए गए एलान से, नीचे दिए गए एलान को समझने में मदद मिलेगी. अलग-अलग फ़ाइलें, अपने कॉन्टेंट को अलग-अलग क्रम में दिखा सकती हैं. इसी तरह, किसी फ़ाइल में 100 प्रॉपर्टी, दूसरी फ़ाइल में 10 फ़ंक्शन, और तीसरी फ़ाइल में एक क्लास हो सकती है.

यह ज़रूरी है कि हर फ़ाइल में कुछ लॉजिकल ऑर्डर का इस्तेमाल किया गया हो. अगर पूछा जाए, तो फ़ाइल को मैनेज करने वाला व्यक्ति इसके बारे में बता सकता है. उदाहरण के लिए, नए फ़ंक्शन को सिर्फ़ फ़ाइल के आखिर में नहीं जोड़ा जाता. ऐसा करने से, “जोड़ने की तारीख के हिसाब से क्रम” तय होता है, जो कि लॉजिकल क्रम नहीं है.

क्लास के सदस्यों को क्रम से लगाना

किसी क्लास में सदस्यों का क्रम, टॉप-लेवल के एलान वाले नियमों का पालन करता है.

फ़ॉर्मैटिंग

ब्रेसेस

when ब्रांच और if एक्सप्रेशन के लिए ब्रेसिज़ ज़रूरी नहीं हैं. हालांकि, ऐसा तब होता है, जब उनमें एक से ज़्यादा else ब्रांच न हों और वे एक लाइन में फ़िट हो जाएं.

if (string.isEmpty()) return

val result =
    if (string.isEmpty()) DEFAULT_VALUE else string

when (value) {
    0 -> return
    // …
}

हालांकि, if, for, when ब्रांच, do, और while स्टेटमेंट और एक्सप्रेशन के लिए, कर्ली ब्रैकेट का इस्तेमाल करना ज़रूरी है. भले ही, मुख्य हिस्सा खाली हो या उसमें सिर्फ़ एक स्टेटमेंट हो.

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)
}

ऐसे ब्लॉक जिनमें कुछ न कुछ मौजूद हो

नॉनएम्प्टी ब्लॉक और ब्लॉक जैसे कंस्ट्रक्ट के लिए, कर्ली ब्रेसिज़, कर्निघन और रिची स्टाइल ("इजिप्शियन ब्रैकेट") का पालन करते हैं:

  • ओपनिंग ब्रेस से पहले कोई लाइन ब्रेक नहीं होना चाहिए.
  • ओपनिंग ब्रेस के बाद लाइन ब्रेक.
  • बंद होने वाले ब्रेसिज़ से पहले लाइन ब्रेक.
  • क्लोज़िंग ब्रेस के बाद लाइन ब्रेक, सिर्फ़ तब होता है, जब वह ब्रेस किसी स्टेटमेंट या फ़ंक्शन, कंस्ट्रक्टर या नाम वाली क्लास के मुख्य हिस्से को खत्म करता है. उदाहरण के लिए, अगर ब्रेस के बाद else या कॉमा आता है, तो ब्रेस के बाद कोई लाइन ब्रेक नहीं होता है.

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()
        }
    }
}

enum क्लास के लिए कुछ अपवाद यहां दिए गए हैं.

खाली ब्लॉक

खाली ब्लॉक या ब्लॉक जैसे कंस्ट्रक्ट, K&R स्टाइल में होने चाहिए.

try {
    doSomething()
} catch (e: Exception) {} // WRONG!

try {
    doSomething()
} catch (e: Exception) {
} // Okay

एक्सप्रेशन

एक्सप्रेशन के तौर पर इस्तेमाल किए जाने वाले if/else कंडिशनल में, कर्ली ब्रेसिज़ सिर्फ़ तब नहीं लगाए जाते, जब पूरा एक्सप्रेशन एक लाइन में फ़िट हो जाता है.

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
}

इंडेंटेशन

हर बार जब कोई नया ब्लॉक या ब्लॉक जैसा कंस्ट्रक्ट खोला जाता है, तो इंडेंट चार स्पेस बढ़ जाता है. ब्लॉक खत्म होने पर, इंडेंट का लेवल पहले जैसा हो जाता है. इंडेंट लेवल, पूरे ब्लॉक में कोड और टिप्पणियों, दोनों पर लागू होता है.

हर लाइन में एक स्टेटमेंट

हर स्टेटमेंट के बाद एक लाइन ब्रेक होता है. सेमीकोलन का इस्तेमाल नहीं किया गया है.

लाइन रैप करने की सुविधा

कोड में ज़्यादा से ज़्यादा 100 वर्ण हो सकते हैं. यहां बताई गई बातों को छोड़कर, इस सीमा से ज़्यादा वर्णों वाली किसी भी लाइन को रैप किया जाना चाहिए. इसके बारे में यहां बताया गया है.

अपवाद:

  • ऐसी लाइनें जिनमें कॉलम की सीमा का पालन करना मुमकिन नहीं है (उदाहरण के लिए, KDoc में लंबा यूआरएल)
  • package और import के स्टेटमेंट
  • टिप्पणी में मौजूद कमांड लाइनें, जिन्हें शेल में कट और चिपकाया जा सकता है

कहां से तोड़ना है

लाइन रैपिंग का मुख्य सिद्धांत यह है: सिंटैक्टिक लेवल पर लाइन को ब्रेक करना बेहतर होता है. साथ ही:

  • जब किसी लाइन को ऑपरेटर या इनफ़िक्स फ़ंक्शन के नाम पर तोड़ा जाता है, तो लाइन को ऑपरेटर या इनफ़िक्स फ़ंक्शन के नाम के बाद तोड़ा जाता है.
  • जब किसी लाइन को यहां दिए गए “ऑपरेटर जैसे” सिंबल पर तोड़ा जाता है, तो लाइन को सिंबल से पहले तोड़ा जाता है:
    • डॉट सेपरेटर (., ?.).
    • सदस्यता के रेफ़रंस में मौजूद दो कोलन (::).
  • किसी तरीके या कंस्ट्रक्टर का नाम, उसके बाद आने वाले खुले ब्रैकेट (() से जुड़ा रहता है.
  • कॉमा (,) उस टोकन से जुड़ा रहता है जो उससे पहले आता है.
  • लैम्डा ऐरो (->), उससे पहले मौजूद आर्ग्युमेंट की सूची से जुड़ा रहता है.

फ़ंक्शन

अगर फ़ंक्शन सिग्नेचर एक लाइन में नहीं आता है, तो हर पैरामीटर के एलान को उसकी लाइन में ब्रेक करें. इस फ़ॉर्मैट में तय किए गए पैरामीटर में, एक इंडेंट (+4) का इस्तेमाल किया जाना चाहिए. बंद होने वाला पैरंट्थीसिस ()) और रिटर्न टाइप, अपनी लाइन में रखे जाते हैं. इनमें कोई अतिरिक्त इंडेंट नहीं होता.

fun <T> Iterable<T>.joinToString(
    separator: CharSequence = ", ",
    prefix: CharSequence = "",
    postfix: CharSequence = ""
): String {
    // ...
}

एक्सप्रेशन फ़ंक्शन

जब किसी फ़ंक्शन में सिर्फ़ एक एक्सप्रेशन होता है, तो उसे एक्सप्रेशन फ़ंक्शन के तौर पर दिखाया जा सकता है.

override fun toString(): String {
    return "Hey"
}

override fun toString(): String = "Hey"

प्रॉपर्टी

जब प्रॉपर्टी इनिशियलाइज़र एक लाइन में फ़िट नहीं होता है, तो बराबर के निशान (=) के बाद लाइन को तोड़ें और इंडेंट का इस्तेमाल करें.

private val defaultCharset: Charset? =
    EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)

get और/या set फ़ंक्शन का एलान करने वाली प्रॉपर्टी को, हर फ़ंक्शन को अपनी लाइन में रखना चाहिए. साथ ही, सामान्य इंडेंट (+4) का इस्तेमाल करना चाहिए. इन्हें फ़ंक्शन के नियमों के मुताबिक फ़ॉर्मैट करें.

var directory: File? = null
    set(value) {
        // …
    }
सिर्फ़ पढ़ने के लिए उपलब्ध प्रॉपर्टी, छोटे सिंटैक्स का इस्तेमाल कर सकती हैं. यह सिंटैक्स एक लाइन में फ़िट हो जाता है.

val defaultExtension: String get() = "kt"

वाइटस्‍पेस

वर्टिकल

एक खाली लाइन दिखती है:

  • क्लास के लगातार सदस्यों के बीच: प्रॉपर्टी, कंस्ट्रक्टर, फ़ंक्शन, नेस्ट की गई क्लास वगैरह.
    • अपवाद: दो लगातार प्रॉपर्टी (जिनके बीच कोई और कोड नहीं है) के बीच खाली लाइन छोड़ना ज़रूरी नहीं है. ज़रूरत के मुताबिक, ऐसी खाली लाइनों का इस्तेमाल किया जाता है, ताकि प्रॉपर्टी के लॉजिकल ग्रुप बनाए जा सकें. साथ ही, प्रॉपर्टी को उसकी बैकिंग प्रॉपर्टी के साथ जोड़ा जा सके.
    • अपवाद: enum कॉन्स्टेंट के बीच की खाली लाइनों के बारे में यहां बताया गया है.
  • स्टेटमेंट के बीच, कोड को लॉजिकल सब-सेक्शन में व्यवस्थित करने के लिए, ज़रूरत के मुताबिक.
  • किसी फ़ंक्शन में पहले स्टेटमेंट से पहले, किसी क्लास के पहले सदस्य से पहले या किसी क्लास के आखिरी सदस्य के बाद ज़रूरी नहीं है. हालांकि, ऐसा करने के लिए न तो बढ़ावा दिया जाता है और न ही रोका जाता है.
  • इस दस्तावेज़ के अन्य सेक्शन (जैसे कि स्ट्रक्चर सेक्शन) के लिए ज़रूरी है.

लगातार कई खाली लाइनों का इस्तेमाल किया जा सकता है. हालांकि, हम ऐसा करने का सुझाव नहीं देते. साथ ही, ऐसा करना कभी ज़रूरी नहीं होता.

हॉरिज़ॉन्टल

भाषा या स्टाइल से जुड़े अन्य नियमों के मुताबिक ज़रूरी जगहों के अलावा, लिटरल, टिप्पणियों, और KDoc के अलावा, एक ही ASCII स्पेस इन जगहों पर भी दिखता है:

  • किसी भी रिज़र्व किए गए शब्द, जैसे कि if, for या catch को उसी लाइन में मौजूद ओपन ब्रैकेट (() से अलग करना.
    // WRONG!
    for(i in 0..1) {
    }
    // Okay
    for (i in 0..1) {
    }
  • किसी भी रिज़र्व किए गए शब्द, जैसे कि else या catch को उस लाइन में मौजूद क्लोज़िंग कर्ली ब्रेस (}) से अलग करना.
    // WRONG!
    }else {
    }
    // Okay
    } else {
    }
  • ओपन कर्ली ब्रेस ({) से पहले.
    // WRONG!
    if (list.isEmpty()){
    }
    // Okay
    if (list.isEmpty()) {
    }
  • किसी भी बाइनरी ऑपरेटर के दोनों ओर.
    // WRONG!
    val two = 1+1
    // Okay
    val two = 1 + 1
    यह “ऑपरेटर जैसे” इन सिंबल पर भी लागू होता है:
    • लैम्डा एक्सप्रेशन में मौजूद ऐरो (->).
      // WRONG!
      ints.map { value->value.toString() }
      // Okay
      ints.map { value -> value.toString() }
    हालांकि, ऐसा नहीं है:
    • सदस्यता के रेफ़रंस में मौजूद दो कोलन (::).
      // WRONG!
      val toString = Any :: toString
      // Okay
      val toString = Any::toString
    • बिंदु सेपरेटर (.).
      // WRONG
      it . toString()
      // Okay
      it.toString()
    • रेंज ऑपरेटर (..) का इस्तेमाल करें.
      // WRONG
      for (i in 1 .. 4) {
        print(i)
      }
      // Okay
      for (i in 1..4) {
        print(i)
      }
  • कोलन (:) से पहले सिर्फ़ तब, जब इसका इस्तेमाल बेस क्लास या इंटरफ़ेस तय करने के लिए क्लास डिक्लेरेशन में किया गया हो या जब इसका इस्तेमाल where क्लॉज़ में जेनरिक कंस्ट्रेंट के लिए किया गया हो.
    // 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> {}
  • कॉमा (,) या कोलन (:) के बाद.
    // WRONG!
    val oneAndTwo = listOf(1,2)
    // Okay
    val oneAndTwo = listOf(1, 2)
    // WRONG!
    class Foo :Runnable
    // Okay
    class Foo : Runnable
  • लाइन के आखिर में की गई टिप्पणी की शुरुआत में मौजूद डबल स्लैश (//) के दोनों ओर. यहां एक से ज़्यादा स्पेस इस्तेमाल किए जा सकते हैं, लेकिन ऐसा करना ज़रूरी नहीं है.
    // WRONG!
    var debugging = false//disabled by default
    // Okay
    var debugging = false // disabled by default

इस नियम का मतलब यह नहीं है कि लाइन की शुरुआत या आखिर में अतिरिक्त स्पेस की ज़रूरत है या नहीं. यह सिर्फ़ बीच के स्पेस के बारे में बताता है.

खास कंस्ट्रक्ट

Enum क्लास

जिस enum में कोई फ़ंक्शन नहीं है और जिसके कॉन्स्टेंट के बारे में कोई दस्तावेज़ मौजूद नहीं है उसे एक लाइन में फ़ॉर्मैट किया जा सकता है.

enum class Answer { YES, NO, MAYBE }

जब किसी enum में मौजूद कॉन्स्टेंट को अलग-अलग लाइनों में रखा जाता है, तो उनके बीच एक खाली लाइन की ज़रूरत नहीं होती. हालांकि, अगर वे किसी बॉडी को तय करते हैं, तो उनके बीच एक खाली लाइन की ज़रूरत होती है.

enum class Answer {
    YES,
    NO,

    MAYBE {
        override fun toString() = """¯\_(ツ)_/¯"""
    }
}

इनम क्लास, क्लास होती हैं. इसलिए, क्लास को फ़ॉर्मैट करने के सभी नियम इन पर भी लागू होते हैं.

टिप्पणियां

सदस्य या टाइप के एनोटेशन, एनोटेट किए गए कंस्ट्रक्ट से ठीक पहले अलग-अलग लाइनों में रखे जाते हैं.

@Retention(SOURCE)
@Target(FUNCTION, PROPERTY_SETTER, FIELD)
annotation class Global

बिना किसी तर्क वाले एनोटेशन को एक ही लाइन में रखा जा सकता है.

@JvmField @Volatile
var disposable: Disposable? = null

जब बिना किसी तर्क के सिर्फ़ एक एनोटेशन मौजूद हो, तो उसे एलान वाली लाइन में ही रखा जा सकता है.

@Volatile var disposable: Disposable? = null

@Test fun selectAll() {
    // …
}

@[...] सिंटैक्स का इस्तेमाल सिर्फ़ उस साइट के टारगेट के साथ किया जा सकता है जिस पर इसका इस्तेमाल किया जाना है. साथ ही, इसका इस्तेमाल सिर्फ़ एक लाइन में दो या उससे ज़्यादा एनोटेशन को बिना किसी तर्क के जोड़ने के लिए किया जा सकता है.

@field:[JvmStatic Volatile]
var disposable: Disposable? = null

इंप्लिसिट रिटर्न/प्रॉपर्टी टाइप

अगर एक्सप्रेशन फ़ंक्शन का मुख्य हिस्सा या प्रॉपर्टी इनिशियलाइज़र, स्केलर वैल्यू है या रिटर्न टाइप को मुख्य हिस्से से साफ़ तौर पर समझा जा सकता है, तो इसे हटाया जा सकता है.

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")

लाइब्रेरी लिखते समय, टाइप के बारे में साफ़ तौर पर जानकारी दें. ऐसा तब करें, जब यह सार्वजनिक एपीआई का हिस्सा हो.

इन्हें

आइडेंटिफ़ायर में सिर्फ़ ASCII अक्षर और अंक इस्तेमाल किए जाते हैं. साथ ही, यहां दिए गए कुछ मामलों में अंडरस्कोर का इस्तेमाल किया जाता है. इसलिए, हर मान्य आइडेंटिफ़ायर का नाम, रेगुलर एक्सप्रेशन \w+ से मैच होता है.

उदाहरणों name_, mName, s_name, और kName में दिखाए गए खास प्रीफ़िक्स या सफ़िक्स का इस्तेमाल नहीं किया जाता. हालांकि, बैकिंग प्रॉपर्टी के मामले में इनका इस्तेमाल किया जाता है (बैकिंग प्रॉपर्टी देखें).

पैकेज के नाम

पैकेज के नाम में सभी अक्षर छोटे होते हैं. साथ ही, लगातार शब्दों को एक साथ जोड़ दिया जाता है (कोई अंडरस्कोर नहीं होता).

// Okay
package com.example.deepspace
// WRONG!
package com.example.deepSpace
// WRONG!
package com.example.deep_space

नाम टाइप करें

क्लास के नाम PascalCase में लिखे जाते हैं. ये आम तौर पर संज्ञा या संज्ञा वाक्यांश होते हैं. उदाहरण के लिए, Character या ImmutableList. इंटरफ़ेस के नाम, संज्ञा या संज्ञा वाक्यांश (उदाहरण के लिए, List) भी हो सकते हैं. हालांकि, कभी-कभी ये विशेषण या विशेषण वाक्यांश (उदाहरण के लिए, Readable) भी हो सकते हैं.

टेस्ट क्लास के नाम, उस क्लास के नाम से शुरू होते हैं जिसकी टेस्टिंग की जा रही है. साथ ही, इनके आखिर में Test होता है. उदाहरण के लिए, HashTest या HashIntegrationTest.

फ़ंक्शन के नाम

फ़ंक्शन के नाम, कैमल केस में लिखे जाते हैं. आम तौर पर, ये क्रिया या क्रिया वाक्यांश होते हैं. उदाहरण के लिए, sendMessage या stop.

टेस्ट फ़ंक्शन के नामों में अंडरस्कोर इस्तेमाल किए जा सकते हैं. इससे नाम के लॉजिकल कॉम्पोनेंट को अलग किया जा सकता है.

@Test fun pop_emptyStack() {
    // …
}

@Composable के साथ एनोटेट किए गए फ़ंक्शन, Unit दिखाते हैं. ये फ़ंक्शन, PascalCase में होते हैं और इनके नाम संज्ञा के तौर पर रखे जाते हैं. ऐसा लगता है कि ये टाइप हैं.

@Composable
fun NameTag(name: String) {
    // …
}

फ़ंक्शन के नाम में स्पेस (खाली जगह) नहीं होनी चाहिए, क्योंकि यह सुविधा हर प्लैटफ़ॉर्म पर काम नहीं करती. खास तौर पर, यह सुविधा Android पर पूरी तरह से काम नहीं करती.

// WRONG!
fun `test every possible case`() {}
// OK
fun testEveryPossibleCase() {}

कॉन्स्टेंट के नाम

स्थिर वैल्यू के नाम, UPPER_SNAKE_CASE का इस्तेमाल करते हैं: सभी बड़े अक्षर, जिनमें शब्दों को अंडरस्कोर से अलग किया जाता है. लेकिन कॉन्स्टेंट क्या होता है?

कॉन्स्टेंट, val प्रॉपर्टी होती हैं. इनमें कोई कस्टम get फ़ंक्शन नहीं होता. इनका कॉन्टेंट पूरी तरह से बदला नहीं जा सकता. साथ ही, इनके फ़ंक्शन के कोई साइड इफ़ेक्ट नहीं होते. इसमें ऐसे टाइप और ऐसे टाइप के कलेक्शन शामिल हैं जिनमें बदलाव नहीं किया जा सकता. साथ ही, अगर स्केलर और स्ट्रिंग को const के तौर पर मार्क किया गया है, तो उन्हें भी शामिल किया जाता है. अगर किसी इंस्टेंस की किसी भी ऑब्ज़र्वेबल स्थिति में बदलाव किया जा सकता है, तो वह कॉन्स्टेंट नहीं होता. सिर्फ़ ऑब्जेक्ट में कभी बदलाव न करने का इरादा रखना काफ़ी नहीं है.

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>()

ये नाम आम तौर पर संज्ञा या संज्ञा वाक्यांश होते हैं.

कॉन्सटेंट वैल्यू को सिर्फ़ object के अंदर या टॉप-लेवल डिक्लेरेशन के तौर पर तय किया जा सकता है. अगर कोई वैल्यू, कॉन्स्टेंट की ज़रूरी शर्तों को पूरा करती है, लेकिन उसे class के अंदर तय किया गया है, तो उसे कॉन्स्टेंट के नाम के तौर पर इस्तेमाल नहीं किया जा सकता.

स्केलर वैल्यू वाले कॉन्स्टेंट में const modifier का इस्तेमाल करना ज़रूरी है.

ऐसे नाम जो स्थिर नहीं हैं

नॉन-कॉन्स्टेंट के नाम camelCase में लिखे जाते हैं. ये इंस्टेंस प्रॉपर्टी, लोकल प्रॉपर्टी, और पैरामीटर के नामों पर लागू होते हैं.

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")

ये नाम आम तौर पर संज्ञा या संज्ञा वाक्यांश होते हैं.

बैकअप प्रॉपर्टी

जब किसी बैकिंग प्रॉपर्टी की ज़रूरत हो, तो उसका नाम असली प्रॉपर्टी के नाम से पूरी तरह मेल खाना चाहिए. हालांकि, इसके नाम से पहले अंडरस्कोर का प्रीफ़िक्स होना चाहिए.

private var _table: Map<String, Int>? = null

val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap()
        }
        return _table ?: throw AssertionError()
    }

वैरिएबल के नाम टाइप करें

हर टाइप वैरिएबल का नाम, इन दो स्टाइल में से किसी एक में रखा जाता है:

  • एक कैपिटल लेटर, जिसके बाद एक अंक हो सकता है (जैसे कि E, T, X, T2)
  • क्लास के लिए इस्तेमाल किया गया नाम, जिसके बाद कैपिटल लेटर T (जैसे कि RequestT, FooBarT)

कैमल केस

कभी-कभी, अंग्रेज़ी के किसी वाक्यांश को कैमल केस में बदलने के एक से ज़्यादा सही तरीके होते हैं. ऐसा तब होता है, जब वाक्यांश में एक्रोनियम या “IPv6” या “iOS” जैसे असामान्य कंस्ट्रक्ट मौजूद हों. अनुमान को बेहतर बनाने के लिए, इस स्कीम का इस्तेमाल करें.

नाम को गद्य के तौर पर लिखें:

  1. वाक्यांश को सामान्य ASCII में बदलें और सभी ऐस्ट्रॉफ़ी हटाएं. उदाहरण के लिए, “Müller’s algorithm” को “Muellers algorithm” में बदला जा सकता है.
  2. इस नतीजे को शब्दों में बांटें. इसके लिए, स्पेस और बचे हुए विराम चिह्न (आम तौर पर हाइफ़न) का इस्तेमाल करें. सुझाया गया: अगर किसी शब्द का इस्तेमाल आम तौर पर कैमल केस में किया जाता है, तो उसे अलग-अलग हिस्सों में बांटें. उदाहरण के लिए, “AdWords” को “ad words” में बदलें. ध्यान दें कि “iOS” जैसे शब्द को कैमल केस में नहीं लिखा जाता. यह किसी भी नियम का पालन नहीं करता. इसलिए, यह सुझाव इस पर लागू नहीं होता.
  3. अब सभी अक्षरों को छोटा करें (इसमें संक्षिप्त नाम भी शामिल हैं). इसके बाद, इनमें से कोई एक काम करें:
    • हर शब्द के पहले अक्षर को कैपिटल लेटर में बदलता है, ताकि पास्कल केस मिल सके.
    • कैमल केस बनाने के लिए, पहले शब्द को छोड़कर बाकी सभी शब्दों के पहले अक्षर को कैपिटल लेटर में बदलें.
  4. आखिर में, सभी शब्दों को एक आइडेंटिफ़ायर में जोड़ें.

ध्यान दें कि मूल शब्दों के केस को पूरी तरह से अनदेखा किया जाता है.

गद्य रूप सही गलत
"XML Http Request" XmlHttpRequest XMLHTTPRequest
"नया ग्राहक आईडी" newCustomerId newCustomerID
"इनर स्टॉपवॉच" innerStopwatch innerStopWatch
"iOS पर IPv6 के साथ काम करता है" supportsIpv6OnIos supportsIPv6OnIOS
"YouTube importer" YouTubeImporter YoutubeImporter*

(* स्वीकार किया जा सकता है, लेकिन इसका सुझाव नहीं दिया जाता.)

दस्तावेज़

फ़ॉर्मैटिंग

इस उदाहरण में, KDoc ब्लॉक की बुनियादी फ़ॉर्मैटिंग दिखाई गई है:

/**
 * Multiple lines of KDoc text are written here,
 * wrapped normally…
 */
fun method(arg: String) {
    // …
}

...या इस एक लाइन वाले उदाहरण में:

/** An especially short bit of KDoc. */

सामान्य फ़ॉर्म हमेशा स्वीकार किया जाता है. अगर पूरा KDoc ब्लॉक (टिप्पणी मार्कर भी शामिल हैं) एक लाइन में फ़िट हो सकता है, तो सिंगल-लाइन फ़ॉर्म का इस्तेमाल किया जा सकता है. ध्यान दें कि यह सिर्फ़ तब लागू होता है, जब @return जैसे कोई ब्लॉक टैग न हों.

पैराग्राफ़

पैराग्राफ़ के बीच में एक खाली लाइन होती है. इसका मतलब है कि लाइन में सिर्फ़ अलाइन किया गया लीडिंग ऐस्टरिक (*) होता है. अगर ब्लॉक टैग का ग्रुप मौजूद है, तो यह लाइन उसके पहले दिखती है.

टैग ब्लॉक करना

इस्तेमाल किए गए सभी स्टैंडर्ड “ब्लॉक टैग”, इस क्रम में दिखते हैं: @constructor, @receiver, @param, @property, @return, @throws, @see. साथ ही, ये कभी भी खाली ब्यौरे के साथ नहीं दिखते. जब कोई ब्लॉक टैग एक लाइन में नहीं आ पाता है, तो अगली लाइनें @ की जगह से चार स्पेस इंडेंट की जाती हैं.

खास जानकारी वाला फ़्रैगमेंट

हर KDoc ब्लॉक, कम शब्दों में दी गई जानकारी से शुरू होता है. यह फ़्रैगमेंट बहुत ज़रूरी है: यह टेक्स्ट का सिर्फ़ वही हिस्सा है जो कुछ संदर्भों में दिखता है. जैसे, क्लास और तरीके के इंडेक्स.

यह एक फ़्रैगमेंट है. यह संज्ञा या क्रिया वाक्यांश है, पूरा वाक्य नहीं. यह "A `Foo` is a..." या "This method returns..." से शुरू नहीं होता. साथ ही, इसे "Save the record." की तरह, पूरा आज्ञावाचक वाक्य बनाने की ज़रूरत नहीं है. हालांकि, फ़्रैगमेंट का पहला अक्षर कैपिटल होता है और इसमें विराम चिह्न का इस्तेमाल किया जाता है. ऐसा तब किया जाता है, जब यह पूरा वाक्य हो.

इस्तेमाल

कम से कम, हर public टाइप और हर public या protected सदस्य के लिए KDoc मौजूद होता है. हालांकि, कुछ अपवाद यहां दिए गए हैं.

अपवाद: ऐसे फ़ंक्शन जिनके नाम से ही उनके काम के बारे में पता चलता है

“आसान और साफ़ तौर पर समझ में आने वाले” फ़ंक्शन, जैसे कि getFoo और प्रॉपर्टी, जैसे कि foo के लिए KDoc लिखना ज़रूरी नहीं है. ऐसा तब होता है, जब “foo को दिखाता है” के अलावा और कुछ भी बताने लायक न हो.

इस अपवाद का हवाला देकर, ज़रूरी जानकारी को शामिल न करने का फ़ैसला सही नहीं है. यह ऐसी जानकारी है जिसके बारे में सामान्य तौर पर पढ़ने वाले व्यक्ति को पता होना चाहिए. उदाहरण के लिए, अगर किसी फ़ंक्शन का नाम getCanonicalName है या किसी प्रॉपर्टी का नाम canonicalName है, तो उसके दस्तावेज़ को न छोड़ें. ऐसा इसलिए, क्योंकि सामान्य तौर पर पढ़ने वाले व्यक्ति को "कैननिकल नाम" शब्द का मतलब नहीं पता होगा. भले ही, दस्तावेज़ में सिर्फ़ /** Returns the canonical name. */ लिखा हो!

अपवाद: बदली गई कीमतें

KDoc, सुपरटाइप के किसी तरीके को ओवरराइड करने वाले तरीके पर हमेशा मौजूद नहीं होता.