반공변성으로 입력 받은 속성은 왜 비공개 처리 해야할까?

정지원·2023년 10월 22일
0

코틀린 스터디 중 나온 질문을 정리한 포스팅입니다.

interface Consumer<in T> {
	fun consume(t: T)
}

class WriteOnlyBox<in T>(private var item: T) : Consumer<T> {
    override fun consume(t: T) {
        
    }
}

위 같은 코드가 있습니다.

위 코드에서 WriteOnlyBox의 생성자 프로퍼티의 private var item: T 에서 private 만 제거 후 IDE에서 본다면 다음과 같이 나옵니다.

type parameter T is declared as 'in' but occurs in 'invariant' position in type T

이게 무슨말일까요?

위 설명을 이해 하기전에 공변성과 반공변성의 특징 차이를 알아야 합니다.
in, out 키워드와 타입 파라미터의 관계는 해당 포스팅에서 설명하지 않습니다.

두 변성의 큰 특징은 다음과 같은데요,

  • 공변성 : Producer(생산자) : get으로만 사용이 가능하고, set은 불가능.
    - 데이터를 제공하는데 사용.
    • 사용자는 이 객체로부터 데이터를 가져와 읽을 수 있음.
      • 데이터를 생산해서 사용자가 읽음(get)
  • 반공변성 : Consumer(소비자) : get사용 불가능, set만 가능.
    - 데이터를 사용하거나 소비함.
    • 사용자는 이 객체에 데이터를 전달하여 저장하거나, 다른 작업을 수행.

위 설명이 조금 헷갈린다면 아래 예제를 봐볼까요?

// 반공변성(Consumer(소비자))
interface Consumer<in T> {
    fun consume(item: T)
}

class StringConsumer : Consumer<String> {
    override fun consume(item: String) { // 사용자가 데이터를 사용, 소비함.
        println("Consumed: $item")
    }
}

// 공변성(Producer(생산자))
interface Producer<out T> {
    fun produce(): T // 데이터를 제공, 생산
}

class StringProducer : Producer<String> {
    override fun produce(): String { // 생산한 데이터를 사용자가 읽음.
        return "Produced String"
    }
}

즉, 공변성으로 가지는 타입은 값을 생산(get)로만 사용이 가능하고,
반공변성을 가지는 타입은 값을 소비(set)만 가능합니다.

interface Consumer<in T> {
	fun consume(t: T)
}

class WriteOnlyBox<in T>(var item: T) : Consumer<T> {
    override fun consume(t: T) {
        
    }
}

그럼 다시 private이 제거된 코드로 돌아와서, 문제점이 보이실까요~?
제네릭 클래스인 WriteOnlyBox는 반공변성 타입을 가지고 있습니다.
즉, 소비만 가능해야겠죠? 하지만, var로 설정되어 있어, read/write 둘 다 가능한 상태입니다.

그래서 외부에선 get하지 못하게 private으로 설정하여 해결이 가능하겠죠?

profile
안드로이드 개발자 정지원입니다

0개의 댓글