Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 9. WWDC2023 정리 - (1) Swift Macro의 expansion (Macro의 목적, Macro 모델, 본문

WWDC 정리/WWDC 2023 정리

[iOS - swift] 9. WWDC2023 정리 - (1) Swift Macro의 expansion (Macro의 목적, Macro 모델,

jake-kim 2023. 6. 15. 01:54

(1). Swift Macro의 expansion (Macro의 목적, Macro 모델, Macro Role 이해하기, @freestanding, @attached)

(2). Swift Macro의 expansion (Macro 구현 방법, 올바른 Macro 작성 방법)

(3). Swift Macro의 expansion (Syntax를 이용하여 매크로 구현방법, literal interpolation, TokenSyntax, ExprSyntax, MacroExpansionContext, 이름 충돌)

Swift Macro의 목적

  • 반복되는 코드 부분의 Boilerplate를 줄이기
  • 컴파일러를 수정하지 않고 Swift 패키지에 배포할 수 있는 방식

Swift Macro 4가지 목적

  • 일반적으로 C Macro를 사용할 때, side effect, 디버깅 정보 제한 등과 같은 단점들이 존재하는데, Swift Macro에서는 이를 보완하여 장점을 많이 살림
  • Swift Macro는 다른 언어에서의 매크로와 다른 방법으로 4가지 목적을 가지고 탄생
  • 1) 매크로를 사용할 때 매우 명확해야 한다는 점 (#기호와 @기호를 이용하여 사용)
    • # 기호나 @ 기호를 사용 각각 다른 의미를 지니는데 이처럼 여러가지 역할에 따라 기호를 다르게 사용

Freestanding macro: 독립형 매크로 (코드에서 다른 항목을 대신함)
attach macro: @키워드를 사용 (속성으로 사용)

  • 2) macro를 사용할때 실수를 했다면, 컴파일 에러를 보여주어 실수를 쉽게 확인할 수 있어야함

실수를 확인하기 쉬움

  • 3) macro 확장이 예측 가능하고 부가적인 방식으로 프로그램에 통합되어야함
    • ex) 아래 코드에서 #someUnknownMacro()는 무엇을 하는지 모른다고해도 아래 finishDoingThingy() 호출을 멈추거나, 중간에 return과 같은 행위를 하여 중간에 block을 탈출하는 일이 없음
    • 즉, 매크로를 사용하면 예측 가능한 코드 유지가 가능

  • 4) macro 구현부를 Xcode에서 바로 확인할 수 있어야함 (생산성)
    • 오른쪽 마우스 > expand macro 클릭 > dimmed 영역과 함께 구현보가 노출됨
    • break point도 단계별로 실행이 가능

매크로가 수행되는 방법

  • 한 예로 Swift 패키지 플렛폼의 #stringify 매크로가 호출되면, Swift Compiler는 해당 매크로에 대한 구현이 있는 Compiler plugin으로 해당 매크로를 달라는 형태로 요청
    • Compiler plugin은 보안 sandbox 별도의 프로세스로 실행

  • Compiler plugin은 매크로 사용을 처리하고 매크로에 의해 생성된 새로운 코드 조각인 "expansion"을 반환

  • Swift compiler에서 expansion을 받으면 Swift compiler가 expansion을 프로그램에 추가하고 코드의 확장을 함께 컴파일

Macro roles

  • 매크로에 대한 일련의 규칙
  • 독릭형 매크로 2가지 - expression, decleration
    • @freestending(expression): 표현식(실행하고 결과를 생성하는 코드 단위)

  • 첨부된 매크로를 생성 5가지 - peer, accessor, memberAttribute, member, conformance

  • 두 개의 독립 역할을(@freestanding) 제외한 모든 역할 조합이 가능

freestanding(expression) 개념

  • 코드의 '조각'을 리턴하는 독립형 매크로
  • 독립으로 사용하는 *표현식
    • *표현식: 실행하고 결과를 생성하는 코드 단위
    • 아래 코드에서 (x + width)도 하나의 표현식이고, x +, width도 각각 표현식 

표현식 예시

  • 예시) unwrap이 필요할 때 guard를 사용하면, 코드가 단순해지지 않고 긴 내용의 메시지가 들어가는 상황이라 macro를 사용하여 해결

  • 값을 계산하고 반환하기를 원하므로 freestanding(expression)를 생성

  • 사용하는쪽에서는 #unwrap으로 심플하게 접근

@freestanding(declaration) 개념

  • 하나 이상의 프로퍼티나 함수를 붙이는 독립형 매크로
  • ex) 2D 배열 유형이 필요한 일종의 통계 분석을 작성할 때, 1차원 배열로 바꾸고 다시 1차원 인덱스를 계산하려고 하는 요구사항에서 사용

(macro없이 사용된 경우)

(3D 배열에서 동일한 요구사항이 나온 경우 위 처리와 비슷한 코드가 생성)

(4D, 5D, ... ND 모두 비슷한 식이 필요)

  • makeArrayND라는 macro를 사용
    • makeIndex라는 메소드, subscript라는 메소드등을 확장하기 위해서 @freestanding(declaration)을 선언

  • 아래와같이 확장성있게 사용할 수 있는 형태

(macro expansion)

@attached(peer) 개념

  • 특정 선언에 첨부되는 매크로
    • declaration을 검사하고 내부 이름, 타입, 기타 정보에 접근이 가능
    • method나 property에서 사용하면 해당 유형의 멤버가 생성

ex) concurrency를 안쓰는곳에 concurrency 지원을 하는 경우, onCompletion 파라미터를 받고 콜백에서 await를 호출해주는 방식으로 구현된 형태

  • 사용하는쪽에서 이러한 작업을 많이 수행하고 있기 때문에 macro로 전환하면 편리

  • @attached(peer) 매크로를 사용하고 이 매크로 안에서 async, await 버전의 메소드를 연결

  • 사용하는쪽에서 메소드 위에 매크로를 선언하여 간편하게 사용 가능

(구현부)

@attached(accessor)

  • property에 get, set, willSet, didSet과 같은 접근자를 추가하는 매크로

ex) Person안에는 Dictionary가 있고 이 값은 name, height, birthDate값만 보관하며 나머지 값은 보존만 되는 형태

  • 이 코드에서는 getter, setter가 중복으로 여러곳에서 사용되고 있는 형태

  • @attached(accessor) 매크로 생성

  • 사용하는쪽

(expand macro)

@attached(memberAttribute) 개념

  • 새로운 type이나 extension을 추가하는 것

ex) Person 구조체 안에 특정 프토토콜을 준수하도록 하고 싶은 경우

  • cf) macro를 여러개 동시에 사용이 가능 - 두 개의 독립 역할을(@freestanding) 제외한 모든 역할 조합이 가능

구현부) @attached(memberAttribute)를 사용하여 Person 구조체에 DictionaryRepresentable을 준수하도록 선언

  • @attached(memberAttribute)에 의해 Person의 property는 암묵적으로 @DictionaryStorage가 붙게됨

  • @attached(memberAttribute) 프로퍼티 위에 매번 선언하는 DictionaryRepresentable 생략 가능

@attached(member) 개념

  • 기존에는 기존의 멤버에 새로운 특성을 추가했지만, @attached(member)는 완전히 새로운 멤버를 추가
    • * 멤버: method, property, initializer

ex) @attached(member)매크로로 dictionary, init 추가

  • 사용하는 쪽에서는 init과 dictionary 프로퍼티를 따로 선언해주지 않아도되는 간결한 코드가 탄생

@attached(conformance) 개념

  • type이나 extension에 conformance (적합성)을 추가하는 매크로

ex) @attached(conformance)를 추가하여 Person 구조체에 일일이 DictionaryRepresentable을 준수하도록 해주지 않아도 됨 

결과) DictionaryRepresentable을 선언해주지 않아도 됨 (@attached(conformance)에 의해서 자동으로 암시적으로 추가)

정리

  • swift macro를 사용하면 코드를 중복 코드를 줄이면서 간결하게 표현이 가능
    • @freestanding은 조합해서 사용 불가 
    • @attached는 조합해서 사용가능
before after

(간결해진 코드)

  • 만약 DictinoaryStorage가 10개, 20개가 있고 macro를 안 쓴 경우 이 코드가 모두 중복될텐데 macro로 중복코드를 제거하고 간결하게 표현을 해주는 강력한 도구

(다음 포스팅 글에서 Macro 구현 방법, 올바른 Macro 작성 방법 계속)
 
* 참고
https://developer.apple.com/videos/play/wwdc2023/10167/

Comments