인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

보키님의 프로필 이미지
보키

작성한 질문수

코틀린 고급편

15강. inline 함수 자세히 살펴보기

지식공유자님 inline에 대해서의 질문과 추가적인 질문 1가지가 있습니다!

해결된 질문

작성

·

28

·

수정됨

1

먼저 강의 정말 감사합니다.. 질문 폭탄을 드려서 매번 죄송할따름입니다..

  • 1번 질문

// inline 프로퍼티
class InLinePropertyPerson(val name: String) {
    inline val uppercaseName: String
        get() = this.name.uppercase() // 가능
        // get() = field.uppercase() // 불가능
}

위의 코드처럼 inline 프로퍼티의 경우 this로의 접근은 가능한 반면, backing field 사용시에는 불가능하더라구요!

이렇게 되는 이유or원리가 궁금합니다

 

  • 2번 질문

inline 사용의 경우 디버깅이 어렵다는 말을 어느 컨퍼런스의 코틀린 주제 네트워킹 세션때 들은 것 같습니다

그런 경우 강의에서 나온 대로 invoke를 유발할 수 있는 함수 파라미터의 경우 noinline을 붙이면 해결되는 부분일지, 아니면 inline을 제외한 일반 함수로 만들어서 디버깅으로 문제점을 찾고 다시 inline fun으로 만드는게 나은지 궁금합니다

(어떤 경우 차라리 메서드 콜스택을 만드는 편이 진입점을 파악하기 좋으니깐요!)

 

  • 3번 질문

inline 키워드와는 관계 없는 질문이긴하지만..!

// 1번
listOf(1, 2, 3)
    .map { num ->
        val result = num + 1
        result
    }

// 2번
listOf(1, 2, 3)
    .map { num ->
        val result = num + 1
        return@map result
    }

위와 같은 코드에서 보면 map의 중간연산에 최종적으로 result가 반환될거야 라고 명시적으로 나타내는 2번 방식과

kotlin의 특징인 scope { } 의 최종 line 값을 반환하는 자동기능이 쓰인 1번 방식이 있는데

코틀린을 처음 접하거나 모르는 사람이 보면 저기 왜 뜬금없이 쓰이지도 않는 변수인 result가 있지? 이상하군! 이렇게 생각할수도있을것같아요(그냥 예시 중 하나.. 아마 이렇게 생각하시는 분은 없다고 예상)

오히려 2번 방식에서 아 여기 map에서의 최종연산 결과는 result구나 하고 map라벨링을 달고 리턴하는게 좀 더 가독성이 있어보이는데요!

2번 방식은 라벨링을 해서 jump를 하는 방식이라 안티패턴으로 봐야하는지? 아니면 그렇지 않은지?가 궁금합니다

 


 

강의 잘 보고있습니다! 감사합니다 :)

답변 1

0

최태현님의 프로필 이미지
최태현
지식공유자

아이고 아닙니다~ 열심히 들어주시는데 제가 더 감사드리죠! 🙏 하나씩 답변 드려 보겠습니다.

 

[1. inline 프로퍼티 + backing field]

우선 사용해주신 inline 프로퍼티 안의 this.name 은 사실상 getter입니다.

그러니 inline 으로 작성한 코드가 실제 사용부에 옮겨 지더라도 InlinePropertyPerson.getName()과 동일한 효과를 보일테니 문제가 없죠!

하지만 backing field는 실제로 내부 필드가 생기고 이 필드에 접근하는 방식으로 구현됩니다! (디컴파일 해보시면 확인 가능하세요! 🙂) 그리고 inline이 컴파일 타임 때 외부로 옮겨지면 당연히 이 필드에 직접 접근할 수는 없으니 inline 안에서는 backing field를 사용할 수 없습니다.

 

[2. inline과 디버깅]

맞습니다! 어떤 tool 에서는 inline을 고려하지 않고 compile class를 기준으로 line 수 등을 출력하다 보니 inline이 특정 영역에 붙여 졌다고 가정하고 에러 로그가 나오는 경우가 있더라고요!

다만 개인적으로는 몇 년간 코틀린을 사용해 오며 inline 때문에 디버깅이 어려웠던 적은 없는 것 같습니다. inline을 사용하더라도 결국 문제가 될 만한 부분을 명확하게 특정할 수 있었기 때문인데요!

혹시나 앞으로 inline으로 불편했던 경험이 생기면 이 글로 찾아 오겠습니다... 😊

(noinline은 결국 inline 함수의 매개변수로 쓰이는 함수를 인라이닝 하지 않는 것이다 보니 inline 함수 자체를 쓸 때는 비슷한 느낌으로 불편함을 겪을 수도 있을 것 같아, 근본적인 해결책은 아닌 것 같습니다!)

 

[3. 라벨에 대한 코드 스타일]

개인적인 생각으로.. 제일 좋은건!

listOf(1L, 2L, 3L).map { it + 1 }

이라고 생각합니다!

다만 it + 1 처럼 연산이 단순하지 않고 여기서 추가적인 로직이 필요한 경우는

listOf(1L, 2L, 3L).map { num ->
  val a = xxxService.handleA(num)
  val b = yyyRepository.handleB(a)
  b
}

처럼 라벨을 사용하지 않는 편이 깔끔하다고 생각하고, 더 좋은건...

private fun handleNum(num: Long): B {
  val a = xxxService.handleA(num)
  return yyyRepository.handleB(a)
}

처럼 아예

listOf(1L, 2L, 3L).map { handleNum(it) }

map 쪽 코드를 깔끔하게 만드는 거라 생각합니다!

물론 개인적인 선호 이고, 제가 지금 당장 생각하지 못하는 또 다른 상황에서는 다른 의견을 드릴 수도 있습니다!! 😅 도움이 되었으면 좋겠네요~!!

 

강의 열심히 들어 주셔서 항상 감사드리고~ 추가적인 질문 기다리겠습니다!! 감사합니다. 🙇

보키님의 프로필 이미지
보키
질문자

다 이해됐습니다!

감사합니다!! 🙇🏻‍♂️🙇

보키님의 프로필 이미지
보키

작성한 질문수

질문하기