Oczywiście popieprzyły mi się tygodnie. Długi weekend jest w kolejnym, nie w tym. Jednak bez paniki. Mamy co robić. Wracamy do Kotlina. Dziś krótko o widoczności elementów.

Kotlin ma trochę inne podejście do spraw widoczności elementów.

Domyślnie – publiczne

Zasada działania domyślnej widoczności w Javie jest ogólnie znana. Motywacja takiego, a nie innego rozwiązania tego problemu już nie. Domyślną widocznością w Javie jest widoczność pakietowa. Ma to związek z założeniem, że Java ma być bezpieczna w użyciu. Inaczej mówiąc język zmusza do pisania kodu choć trochę idioto-odpornego. Jedną z cech takiego kodu jest komunikacja po interfejsach. Stąd domyślna widoczność w interfejsach to public. Wniosek nasuwa się sam – pakiet powinien wystawiać API oparte o interfejsy, a klasy powinny być widoczne tylko w pakiecie. Teoria, teorią, ale życie to nie je bajka i obecnie zakłada się, że najwygodniej jest, gdy domyślnie wszystko jest publiczne.

Tak też jest w Kotlinie. Domyślna widoczność to public:

Listing 1. Wszystko publiczne

package pl.koziolekweb.visibility

fun doSomething(){}

class IMSomething{

    fun doSomething(){}

}

var question:String = "Universal question of life?";
val answer = 42;

Jak widać, możemy doprowadzić w ten sposób, do powstania zmiennych globalnych. Fajna mina, na którą łatwo wdepnąć.

Modyfikator protected działa co do zasady tak samo, jak w Javie. Nie można go zastosować do funkcji i zmiennych swobodnych. Nuuudaaa…

Prywatne jest prywatne

Przyjrzyjmy się kodowi napisanemu w Javie:

Listing 2. Czy metoda jest prywatna?

public class SomeClass {
	
	public void doSomething(){
		
		Inner inner = new Inner();
		inner.innerMethod();
		
	}
	
	
	class Inner{
		
		private void innerMethod(){}
	}
}

Ten kod skompiluje się i będzie działać. Problem polega jednak na tym, że prywatność metody innerMethod jest „antyterrorystyczna”. Czyli formalnie jest, ale jednak można ją wywołać spoza obiektu tej klasy. Ten sam kod w Kotlinie:

Listing 3. To samo w Kotlinie

class IMSomething{

    fun doSomething(){

        val inn = Inner();
        inn.innerFun()

    }

    class Inner{

        private fun innerFun(){}
    }
}

W tym przypadku kod nie skompiluje się, ponieważ innerFun jest niewidoczna. Ogólna zasada brzmi – elementy prywatne klasy zawsze są niewidoczne na zewnątrz klasy. Trochę inaczej brzmi ta reguła w odniesieniu do funkcji i zmiennych swobodnych.

Listing 4. Funkcje prywatne

private fun IMPrivate(){}

var dontSetMeNow = "You cannot set me"
    private set

Funkcja IMPrivate oraz setter dla dontSetMeNow będą widoczne tylko w pliku, w którym zostały zdefiniowane.

Widoczność modułowa

To jest ten mały smaczek, który odróżnia Kotlina od Javy. Kod w większych projektach zazwyczaj zorganizowany jest w moduły. Mogą to być podprojekty mavena, gradle, moduły IntelliJ, albo też kompilacje anta (pliki kompilowane w ramach jednego wywołania kompilatora).

Jeżeli chcemy by nasza klasa albo funkcja były widoczne tylko w ramach modułu to używamy modyfikatora internal.

Listing 5. Widoczność modułowa

internal fun IMModuleFunction(){}

internal class OnlyInThisModule{

   internal fun notForOtherModules(){}

}

internal val version=1.0

Zmienne swobodne też mogą być widoczne tylko w ramach modułu.

Widoczność taka jest kompromisem pomiędzy publiczną a pakietową. Ma dość duży potencjał. Szczególnie w projektach wielomodułowych, gdzie zależy nam na odseparowaniu część kodu od użytkownika, a jednocześnie chcemy go swobodnie wykorzystywać w naszym module.

Podsumowanie

Kotlin różni się od Javy w zakresie modyfikatorów dostępu. Niektóre różnice są niewielkie jak w przypadku private. Inne, jak internal, są nową jakością. Otwiera to nam nowe możliwości przy projektowaniu naszego kodu. Łatwość współpracy pomiędzy Kotlinem a Javą przyprawiona drobnostkami jak widoczność modułowa jest bardzo cenna. Naprawdę warto zastanowić się nad wdrożeniem Kotlina w swoim projekcie.