🍎 아이-였-μ—μŠ€/🐀 μŠ€μœ„ν”„νŠΈ

[Swift] Method Dispatch (1): Static Dispatch vs. Dynamic Dispatch

κ°œλ°œν•˜λŠ” ν›ˆμ΄ 2021. 12. 26. 16:46

Method Dispatch

글을 μ‹œμž‘ν•˜κΈ° 전에, Method Dispatchκ°€ 무엇인지에 λŒ€ν•΄ 정리할 ν•„μš”κ°€ μžˆκ² λ„€μš”. 곡식적인 λ¬Έμ„œλŠ” μ•„λ‹ˆμ§€λ§Œ ꡬ글에 Method Dispatch의 μ •μ˜μ— λŒ€ν•΄ 검색을 해보면,

πŸ’‘ how a program selects which instructions to execute when invoking a method

μ΄λ ‡κ²Œ ν•œ λ¬Έμž₯으둜 된 μ •μ˜κ°€ κ°€μž₯ 상단에 λ‚˜μ˜΅λ‹ˆλ‹€. 해석해보면 μ–΄λ–€ λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ—ˆμ„ λ•Œ, ν”„λ‘œκ·Έλž¨μ΄ μ–΄λ–€ λͺ…λ Ήμ–΄λ₯Ό 싀행할지 μ„ νƒν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ΄λΌκ³  ν•©λ‹ˆλ‹€.

 

더 μ‰½κ²Œ 이야기해보면 λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν–ˆμ„ λ•Œ μ‹€μ œλ‘œ μ–΄λ–€ λ©”μ„œλ“œκ°€ μ‹€ν–‰λ˜λŠ”μ§€ κ²°μ •ν•˜λŠ” 것이라고 봐도 되겠죠? 

 

Static Dispatch

그럼 이제 κ°„λ‹¨ν•œ 상황을 μƒκ°ν•΄λ΄…μ‹œλ‹€.

struct Test {
    func printTest() {
        print("test")
    }
}

let test = Test()
test.printTest()

μ΄λ ‡κ²Œ κ°„λ‹¨ν•œ ꡬ쑰체λ₯Ό ν•˜λ‚˜ λ§Œλ“€κ³ , λ©”μ„œλ“œλ„ ν•˜λ‚˜ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€. 

 

이 ꡬ쑰체의 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€κ³  λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ μ–΄λ–€ λ©”μ„œλ“œκ°€ μ‹€ν–‰λ μ§€λŠ” λ„ˆλ¬΄λ‚˜ 자λͺ…ν•˜κ² μ£ ? Testμ•ˆμ— μžˆλŠ” printTestκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€. 그리고 이런 결정은 컴파일 νƒ€μž„μ—λ„ κ°€λŠ₯ν•˜κ² μ£ .

 

μš°λ¦¬κ°€ μ‚΄νŽ΄λ³Έ μ •μ˜μ— λ”°λ₯΄λ©΄ Method DispatchλŠ” μ–΄λ–€ μ½”λ“œλ₯Ό 싀행할지 μ„ νƒν•˜λŠ” 것인데, μ§€κΈˆμ€ 선택지가 ν•˜λ‚˜λ°–μ— μ—†μœΌλ‹ˆκΉŒμš”.

 

κ·Έλž˜μ„œ μ΄λ ‡κ²Œ 컴파일 νƒ€μž„μ— μ–΄λ–€ λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν• μ§€ κ²°μ •ν•  수 μžˆλŠ” 경우λ₯Ό Static Dispatch라고 ν•©λ‹ˆλ‹€. 말 κ·ΈλŒ€λ‘œ λ™μ μœΌλ‘œ κ²°μ •ν•  ν•„μš”κ°€ μ—†λŠ” κ±°μ£ .

 

Static DispatchλŠ” 기본적으둜 λͺ¨λ“  κ°’νƒ€μž…μ— μ μš©λ©λ‹ˆλ‹€. μ‹€ν–‰ν•  λ©”μ„œλ“œκ°€ 항상 λͺ…ν™•ν•˜λ‹ˆκΉŒμš”.

Dynamic Dispatch

그럼 선택지가 μ—¬λŸ¬ κ°œκ°€ λ˜λŠ” 상황이 μžˆμœΌλ‹ˆ 이런 κ°œλ…μ΄ λ‚˜μ™”μ„ 텐데 μ–΄λ–€ μƒν™©μΌκΉŒμš”?

class Test {
    func printTest() {
        print("test")
    }
}

class TestA: Test {
    override func printTest() {
        print("testA")
    }
}

class TestB: Test {
    override func printTest() {
        print("testB")
    }
}

let tests = [Test(), TestA(), TestB()]

for test in tests {
    test.printTest()
}

μ΄λ²ˆμ—” κΈ°μ‘΄ Test ꡬ쑰체λ₯Ό 클래둜 λ§Œλ“€κ³  이λ₯Ό μƒμ†ν•˜λŠ” 두 클래슀 TestA, TestBλ₯Ό μ„ μ–Έν–ˆμŠ΅λ‹ˆλ‹€.

 

그리고 μ„Έ 개의 λ‹€λ₯Έ 클래슀 μΈμŠ€ν„΄μŠ€λ₯Ό 배열에 λ„£μ–΄μ£Όκ³  배열을 μˆœνšŒν•˜λ©΄μ„œ printTestλ₯Ό μ‹€ν–‰ν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€.

 

즉, λ‹€ν˜•μ„±μ„ λ§Œλ“€μ–΄μ€€ 것이죠. 

 

μ—¬κΈ°μ„œ tests λ°°μ—΄μ˜ νƒ€μž…μ€ λ¬΄μ—‡μΌκΉŒμš”?

TestA와 TestBλŠ” Testλ₯Ό μƒμ†ν•˜κΈ° λ•Œλ¬Έμ— 제일 μƒμœ„ 클래슀인 Testκ°€ λ°°μ—΄μ˜ μš”μ†Œ νƒ€μž…μœΌλ‘œ μ •μ˜λ©λ‹ˆλ‹€. 

for test in tests {
    test.printTest()
}

그럼 이 μ½”λ“œμ—μ„œλŠ” Test νƒ€μž…μ˜ λ©”μ„œλ“œμΈ printTestκ°€ μ„Έ 번 μ‹€ν–‰λ˜μ–΄μ„œ λ‹€μŒκ³Ό 같은 κ²°κ³Όκ°€ λ‚˜μ˜¨λ‹€κ³  생각할 수 있겠죠..!

test
test
test

ν•˜μ§€λ§Œ μš°λ¦¬κ°€ κΈ°λŒ€ν–ˆλ˜ λŒ€λ‘œ, 그리고 잘 μ•Œκ³  μžˆλŠ” λŒ€λ‘œ μ‹€μ œ 좜λ ₯은 μ΄λ ‡μŠ΅λ‹ˆλ‹€.

test
testA
testB

μŠ€μœ„ν”„νŠΈλŠ” λ°°μ—΄ μš”μ†Œλ“€μ˜ νƒ€μž…μ΄ Test인데 μ–΄λ–»κ²Œ μžμ‹ ν΄λž˜μŠ€λ“€μΈ TestA와 TestBλ₯Ό ꡬ뢄할 수 μžˆμ—ˆμ„κΉŒμš”?

 

컴파일 νƒ€μž„μ—λŠ” μ•Œ 수 μ—†μŠ΅λ‹ˆλ‹€. λ°°μ—΄ μš”μ†Œμ€‘ μ–΄λ–€ μš”μ†Œκ°€ μ–΄λ–€ ν•˜μœ„ 클래슀의 μΈμŠ€ν„΄μŠ€μΈμ§€ μ•Œ 수 μ—†μœΌλ‹ˆκΉŒμš”.. κ·Έλž˜μ„œ μŠ€μœ„ν”„νŠΈλŠ” 이 μΈμŠ€ν„΄μŠ€μ—λŠ” 이 λ©”μ„œλ“œ κ΅¬ν˜„μ„ 써!라고 μ ν˜€μžˆλŠ” ν…Œμ΄λΈ”μ„ μ‚¬μš©ν•©λ‹ˆλ‹€. 

 

이 ν…Œμ΄λΈ”μ„ vTable(virtual dispatch table) 이라고 ν•˜λŠ”λ°μš”, vTable을 μ°Έμ‘°ν•  수 μžˆλŠ” ν¬μΈν„°λŠ” 각 μΈμŠ€ν„΄μŠ€λ§ˆλ‹€ ν•˜λ‚˜μ”© μ‘΄μž¬ν•˜κ³ , μŠ€μœ„ν”„νŠΈλŠ” λŸ°νƒ€μž„μ— μ–΄λ–€ μΈμŠ€ν„΄μŠ€μ—μ„œ λ©”μ„œλ“œκ°€ 호좜되면 이 ν…Œμ΄λΈ”μ—μ„œ ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜κ³  μžˆλŠ” μ½”λ“œλ₯Ό μ°Ύμ•„ μ‹€ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€.

 

과정을 κ°„λ‹¨νžˆ κ·Έλ €λ³ΌκΉŒμš”?

클래슀 μΈμŠ€ν„΄μŠ€μ˜ λ©”μ„œλ“œκ°€ μ‹€ν–‰λ˜λ©΄, 1) λ¨Όμ € μΈμŠ€ν„΄μŠ€μ˜ 메타 νƒ€μž…μ„ μ–»κ³ , 2) ν•΄λ‹Ή νƒ€μž…μ΄ 가진 vtableμ—μ„œ ν˜ΈμΆœν•˜κ³ μž ν•˜λŠ” λ©”μ„œλ“œμ˜ μ£Όμ†Œλ₯Ό μ°Ύμ•„, 3) ν•΄λ‹Ή μ£Όμ†Œλ₯Ό μ°Ύμ•„κ°€ λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

 

μ΄λ ‡κ²Œ λŸ°νƒ€μž„에 λ©”μ„œλ“œκ°€ 호좜되면 ν…Œμ΄λΈ”μ„ 확인해 μ–΄λ–€ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν• μ§€ κ²°μ •ν•˜λŠ” 것을 Dynamic Dispatch라고 ν•©λ‹ˆλ‹€. 

 

λ‹€μ΄λ‚˜λ―Ή λ””μŠ€νŒ¨μΉ˜ 덕뢄에 μš°λ¦¬λŠ” μ˜€λ²„ 라이딩을 ν†΅ν•œ λ‹€ν˜•μ„±μ„ μ‰½κ²Œ λ§Œλ“€ 수 μžˆμ§€λ§Œ, λ°˜λ©΄μ— λͺ¨λ“  ν΄λž˜μŠ€λ“€μ„ λ‹€ν˜•μ„±μ„ κ°€μ§ˆ 수 있기 λ•Œλ¬Έμ— 클래슀의 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ ν…Œμ΄λΈ”μ„ ν•œ λ²ˆμ”© λ‹€ 확인해야 ν•˜λŠ” μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•˜κ²Œλ©λ‹ˆλ‹€.

 

μ•žμ„œ λ³Έ κ²ƒμ²˜λŸΌ μƒμ†μ˜ 여지가 μžˆμ–΄ λ™μΌν•œ μΈν„°νŽ˜μ΄μŠ€μ— λŒ€ν•œ λ©”μ„œλ“œκ°€ μ—¬λŸ¬ 개 μ •μ˜λ  수 μžˆλ‹€λ©΄ Dynamic Dispatchκ°€ λ©λ‹ˆλ‹€. λ”°λΌμ„œ ν΄λž˜μŠ€λŠ” λ”°λ‘œ μ΅œμ ν™”λ₯Ό 해주지 μ•ŠλŠ”λ‹€λ©΄ Dynamic Dispatch둜 λ™μž‘ν•©λ‹ˆλ‹€. μ΅œμ ν™”μ— λŒ€ν•œ μ΄μ•ΌκΈ°λŠ” λ‹€λ₯Έ ν¬μŠ€νŠΈμ—μ„œ 더 깊게 ν•΄ λ³Όκ²Œμš”!

정리

 

 

μ΄λ ‡κ²Œ κ°„λ‹¨ν•˜κ²Œ Satic Dispatch와 Dynamic Dispatch에 λŒ€ν•΄μ„œ μ •λ¦¬ν•΄λ³΄μ•˜λŠ”λ°μš”,

 

μ—¬κΈ°μ„œ λ“œλŠ” 의문.. 그럼 Protocol을 μ±„νƒν•΄μ„œ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•œ κ΅¬μ‘°μ²΄λŠ”..? 

 

이런 κ²½μš°λ„ 같은 μΈν„°νŽ˜μ΄μŠ€μ— λŒ€ν•΄ λ©”μ„œλ“œ μ •μ˜κ°€ μ—¬λŸ¬ μ’…λ₯˜μΌ 수 μžˆλŠ”λ° Dynamic Dispatch이지 μ•Šμ„κΉŒμš”? 이 μ˜λ¬Έμ μ€ λ‹€μŒ ν¬μŠ€νŠΈμ—μ„œ 해결해보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€!