ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SE-0502] Exclude private initialized properties from memberwise initializer
    Swift 2026. 1. 11. 09:51

    안녕하세요. 그린입니다 🍏

    이번 포스팅에서는 SE-0502 Exclude private initialized properties from memberwise initializer에 대해 정리해보겠습니다 🙋🏻


    Intro

    Swift에서 struct를 사용하다 보면, 의식하지 않아도 자연스럽게 활용하게 되는 기능 중 하나가 바로 memberwise initializer입니다.

    저장 프로퍼티를 선언하기만 하면, 컴파일러가 알아서 이니셜라이저를 만들어 주는 기능이죠.

    하지만 이 편리한 기능은, 접근 제어자(private, fileprivate)와 엮이기 시작하면 생각보다 많은 불편함과 함정을 드러냅니다.

     

    이번 글에서는 Swift Evolution Proposal SE-0502 – Exclude private initialized properties from memberwise initializer의 내용을 그대로 따라가며, 왜 이런 제안이 나왔고, 무엇을 바꾸려 하는지, 그리고 이 변화가 실제 개발에서 어떤 의미를 가지는지를 한번 알아보겠습니다 🚀

     

     

    swift-evolution/proposals/0502-exclude-private-from-memberwise-init.md at main · swiftlang/swift-evolution

    This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution

    github.com

     

     


    memberwise initializer의 기본 동작

    Swift에서 struct를 선언하면, 컴파일러는 저장 프로퍼티들을 기반으로 자동으로 memberwise initializer를 생성합니다.

    struct Point {
        let x: Int
        let y: Int
    }
    

     

    위 코드는 아래와 같은 이니셜라이저가 자동으로 생성됩니다.

     

    init(x: Int, y: Int)
    

     

    여기까지는 모두가 익숙한 동작입니다. 문제는 접근 수준(access level) 이 개입되기 시작할 때 발생합니다.

     


    접근 수준이 memberwise initializer에 미치는 영향

    Swift의 규칙은 단순합니다.

     

     

    memberwise initializer의 접근 수준은, 모든 저장 프로퍼티의 접근 수준 중 가장 제한적인 수준을 따른다.

     

    즉, 저장 프로퍼티 중 하나라도 private이면, memberwise initializer 전체가 private이 됩니다.

    struct Example {
        var a: Int
        var b: Int
        private var c: Int = 0
    }

     

    이 경우 컴파일러가 생성하는 이니셜라이저는 다음과 같습니다.

     

    private init(a: Int, b: Int, c: Int)
    

     

    여기서 핵심은 c가 이미 초기값을 가지고 있음에도 불구하고, 이니셜라이저의 파라미터로 포함된다는 점입니다.

    그리고 그 결과, 전체 이니셜라이저가 private이 되어 버립니다.

     

    즉, 외부에서는 Example(a:b:)조차 사용할 수 없게 됩니다.

     


    실제로 이게 왜 문제일까?

    이 동작은 문법적으로는 일관성이 있지만, 실무에서는 상당히 불편합니다.

    • 외부에서 설정할 필요가 없는 내부 상태를 private으로 감췄을 뿐인데
    • 그로 인해 타입 전체를 생성할 수 없게 되는 상황이 발생합니다

    그래서 개발자들은 보통 아래와 같은 선택을 강요받습니다.

    • 불필요하게 internal이나 public으로 접근 수준을 올리거나
    • 명시적으로 이니셜라이저를 직접 작성하거나
    memberwise initializer의 장점을 스스로 포기하게 되는 것이죠.

     


    SE-0502 제안의 요점

    SE-0502는 바로 이 지점에서 출발합니다.

     

     

    초기값을 이미 가지고 있고, 외부에서 설정할 필요가 없는 private 프로퍼티 때문에
    memberwise initializer 전체가 제한되는 것이 과연 합리적인가?

     

     

    이 제안은 기존 규칙을 완전히 뒤엎으려는 것이 아닙니다.

    대신, "이미 초기값이 있는 private 프로퍼티" 라는 굉장히 구체적인 조건에만 변화를 주려 합니다.

     


    제안되는 새로운 규칙

    SE-0502가 제안하는 동작은 다음과 같습니다.
    1. 먼저, memberwise initializer가 가질 수 있는 최대 접근 수준을 계산한다
    2. 그 접근 수준보다 더 제한적인 접근 수준을 가진 저장 프로퍼티 중에서
    3. 초기값이 이미 있는 프로퍼티는 memberwise initializer에서 제외한다

    즉, 이런 프로퍼티들은 아예 이니셜라이저의 파라미터 목록에 포함되지 않습니다.

     


    변경 후 동작 예시

    다시 앞의 예제를 보겠습니다.

    struct Example {
        var a: Int
        var b: Int
        private var c: Int = 0
    }

     

    SE-0502가 적용되면, 컴파일러는 다음과 같은 이니셜라이저를 생성합니다.

    init(a: Int, b: Int)
    
    • c는 이미 기본값을 가지고 있고
    • 접근 수준이 더 제한적이며
    • 외부에서 설정할 필요가 없기 때문에

    memberwise initializer에서 완전히 제외됩니다.

     

    그 결과, 타입을 사용하는 쪽에서는 아무 불편 없이 Example(a:b:)를 사용할 수 있고, 내부 구현 세부 사항은 깔끔하게 감춰집니다.

     


    property wrapper, macro와의 일관성

    이 제안은 단순히 불편함을 줄이기 위한 것만은 아닙니다.

    이미 Swift에는 비슷한 사례가 존재합니다.

     

    Property wrapper는 내부적으로 backing storage를 생성합니다.

    이 backing storage는 대부분 private이며, memberwise initializer에 노출되지 않습니다.

     

    매크로 역시 내부 구현을 위해 private 저장 프로퍼티를 생성할 수 있습니다.

    이 경우에도, 그 프로퍼티가 memberwise initializer에 노출된다면 매크로 사용성이 크게 떨어집니다.

     

    SE-0502는 이런 기존 언어 기능들과 memberwise initializer의 동작을 일관되게 맞추려는 목적도 가지고 있습니다.

     


    ABI와 소스 호환성

    • 이 변경은 ABI에 영향을 주지 않습니다
      • memberwise initializer는 컴파일러가 합성하는 구현 세부사항이기 때문입니다
    • 다만 소스 호환성 측면에서는 일부 영향이 있을 수 있습니다
      • 기존에 private memberwise initializer를 의도적으로 사용하던 코드라면
      • 명시적인 이니셜라이저 선언이 필요해질 수 있습니다
    하지만 제안서에서는, 이런 경우가 매우 제한적일 것이라고 판단하고 있습니다.

     


    이 제안의 의미

    SE-0502는 아주 작은 규칙 변경처럼 보이지만, Swift가 지향하는 방향을 잘 보여줍니다.

    • 내부 구현 디테일은 내부에 감추고
    • 외부 API는 최대한 단순하고 명확하게 유지하며
    • 컴파일러가 개발자의 의도를 더 잘 추론하도록 돕는 방향
    memberwise initializer를 다시 "편하게 써도 되는 기능"으로 돌려놓기 위한, 꽤 합리적인 개선이라고 볼 수 있습니다.


    Conclusion

    현재 시점에서 swift lang에 머지는 된것 같아 곧 다음 버전에서 같이 릴리즈 되지 않을까 기대합니다.

    그래도 아직 논의와 리뷰가 계속 이어지고 있긴 한것 같은데 어떤 방향으로 결론이 날지 궁금하네요 😃

     


    References

     

    swift-evolution/proposals/0502-exclude-private-from-memberwise-init.md at main · swiftlang/swift-evolution

    This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution

    github.com

     

     

    Swift.org

    Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns.

    www.swift.org

Designed by Tistory.