달력

1

« 2025/1 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

 함수내에서, 값(Value)으로 전달받은 인자(Argument)는 참조(Reference)로 전달받는 인자와 차이가 있다. 참조로 전달받은 인자는 변경이 일어났을 때 본래의 객체도 같이 변경되지만 값으로 전달받은 인자는 그렇지 않다.

 

 

1
2
3
4
5
var integer = 5
func multiply(integer: Int, multiplier: Int) {
    //error, integer is defined as a let.
    integer = integer * multiplier
}
cs

 
 애초에 값으로 전달받은 인자는 상수라서 변경조차 불가능하다. 값으로 전달받은 인자를 함수 내에서 수정하려면, 함수의 매개변수(Parameter)에 'inout'이라는 키워드를 붙이면 가능하다.

 

 

1
2
3
4
5
6
7
var integer = 5
func multiply(integer: inout Int, multiplier: Int) {
    integer = integer * multiplier
}
multiply(integer: &integer, multiplier: 2)
print(integer) //10
 
cs



 매개변수에 inout 키워드가 붙었으니, multiply에는 integer의 참조가 전달된 것일까? 

inout Parameter에 대한 Apple의 설명을 보면 이야기가 좀 다르다.



In-Out Parameters: In-out parameters는 다음과 같이 전달됩니다.
1) 함수가 호출됬을 때, 값으로 전달받은 인자는 복사(Copy)됩니다.

2) 함수 내에서는 복사본이 변경됩니다.

3) 함수가 반환(Return)될 때, 복사본의 값이 본래의 값에 할당(Assign)됩니다.

 

 

 Apple의 설명을 확인하기 위해, 간단한 코드를 작성하면...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var number: Int = 2 {
    didSet {
        print("number was assigned.")
    }
}
 
func function(arg: inout Int) {
    print(number) //2
    arg = 5
    print(number) //2
    arg = 10
}
 
function(arg: &number) //"number was assigned."
 
cs

  

 function 내에서 전달받은 인자를 5로 바꾸어도, number는 변하지 않는다. function이 호출된 다음 number의 didSet이 호출되는 것을 볼 수 있는데, 이것을 통해 function 반환 후 본래의 값에 새 값이 할당된다는 것을 확인할 수 있다.

 

 이것은 참조가 전달된 Call-By-Reference와 다르며, Copy-In Copy-Out 또는 Call-By-Value Result라고 불려진다.

 

 

※ 2023.01.24에 추가된 내용

 Swift Docs에 적혀있는, In-Out Parameters의 Optimization에 따르면 Physical Address에 위치한 변수를 In-Out Parameter의 arg로 전달하면 Call-By-Reference로 동작한다고 적혀있다(Call-By-Reference는 Copy로 인한 Overhead는 없지만 Copy-In Copy-Out의 결과와 동일하다).

 

 Compilier의 Optimization Level도 바꾸어 보고, 코드도 이리저리 수정해가며 테스트를 해보았지만... In-Out Parameter를 정의한 함수에서 Call-By-Reference로 동작하는 것을 확인하는 데에 실패했다. Compiler Optimization 결과에 따라 In-Out Parameter의 동작이 달라질 수 있는 것 같으니, 인위적으로 상황을 재현하는 것은 어려울 것 같다.

 

 Swift Docs에 적힌대로, In-Out Parameter를 사용한 함수를 작성할 때, Call-By-Reference를 고려하지 말고 Copy-In Copy-Out로 동작한다고 생각하고 작성하자.

:
Posted by syjdev

 몇년전 코드 리뷰 날, 선배 개발자 한분이 새로운 것을 보여주셨었습니다.

Objective-C의 코드를 두 개 이상의 파일로 나누는 것이었는데요. 

지금은 Swift로만 개발해서 활용하고 있지 않지만, 기록 차원에서 글로 작성해보았습니다.



 샘플로 만든 프로젝트의 'Project Navigator'는 아래와 같습니다.



 특이하게도 ViewController+DiviedFile.m이라는 파일이 있는데요, ViewController.m에 

넣으려던 코드를 별도의 파일로 분리한 것입니다. 



어떤식으로 분리한 것인지 보기 위해 ViewController.m의 코드를 살펴보면 아래와 같습니다.



 FILE_DIVIDE_FLAG라는 상수가 선언되어 있고, 

마치 헤더 파일을 추가한 것처럼 ViewController+DiviedFile.m을 추가했습니다.



 ViewController+DiviedFile.m의 코드도 볼께요.



 매크로를 사용해서, 상수 존재 여부에 따라 @implementation과 @end를 해당위치에 삽입하는 코드가 있습니다. @implementation과 @end가 있어야 ViewController+DiviedFile.m을 정상적인 형태를 갖춘 코드로 인식하고, 컴파일이 될때는 @implementation과 @end가 없어야해서 지시자(Directive)를 저런 형태로 작성한 것입니다.


 여기까지 작업하고 빌드를 하면, 심볼이 중복된다는 에러를 볼 수 있습니다. 해결하려면 ViewController+DiviedFile.m를 컴파일 대상이 되지 않게 하면 됩니다(전처리 단계에서 ViewController.m에서 ViewController+DiviedFile.m의 내용을 해당 위치에 추가하기 

때문에 괜찮습니다.).



 Xcode에서는 Target -> Build Phases -> Compile Sources에서

ViewController+DiviedFile.m를 지워주면 됩니다.



:
Posted by syjdev
2017. 5. 23. 22:57

04. Evaluation Strategies CS ETC/Lambda Calculus2017. 5. 23. 22:57

1. Evaluation이란?

: 수학에서, 올바른 답을 얻기 위해 식(Expression)을 평가하는 방법은 중요한 이슈이다. λ Calculus에서도 마찬가지다.

 

 

2. 원칙과 전략

 

2-1. Evaluation Principle

: 식을 평가하기 위한 2가지 기본적인 원칙이 있는데, 각각 Eager Evaluation과 Lazy Evaluation이다.

 

Eager Evaluation

: 언제나 인자를 Evaluation하고, 함수를 인스턴스화(Instantiate) 한다.

 

Lazy Evaluation

: 인자가 필요한 시점에 Evaluation한다.

 

 

2-2. Evaluation Strategy

: 위의 기본적인 원칙에서 2개의 주요한 평가 전략(Evaluation Strategy)이 탄생하는데, 각각 Normal Order와 Applicative Order이다.

 

Normal Order(call by name으로도 알려져 있음)

: 언제나 맨 왼쪽의 것들부터 줄여나간다. 그리고 파라메터는 함수로 전달되기 전까지 평가하지 않는다.

 

Applicative Order(strict evaluation 또는 call by value로도 알려져 있음)

: 전달되었거나 대체된 파라메터를 먼저 평가한다.

 

 아래의 예제는, 각 Evaluation Strategy를 이해하는데에 도움이 될 것이다.

 

 

Example) 다음 식을 Normal Order, Applicative Order를 이용해서 평가(Evaluation)해보자.

 

(λ a.λ b.a)c((λ d.e)d)

 

 

Normal Order

: (λ a.λ b.a)c((λ d.e)d)  ->β  (λ b.a)[ac]c((λ d.e)d)  =  λ b.c((λ d.e)d)

->β  (c)[b((λ d.e)d)]  =  c

 

Applicative Order

: (λ a.λ b.a)c((λ d.e)d)  ->β  (λ a.λ b.a)c(e[d\d])  =  (λ a.λ b.a)c(e)

->β  (λ b.a)[a\c](e)  =  (λ b.c)(e)  ->β  c[be]  =  c

 

 

※ 어떤 평가 전략을 쓰더라도 결과는 항상 같을까? 그렇지 않다. 위의 예와 같이, 다음 식을 평가해보자.

 

(λ x.a)((λ x.x x)(λ y.y y))

 

Normal Order

: (λ x.a)((λ x.x x)(λ y.y y))  ->β  a[x\((λ x.x x)(λ y.y y))]  =  a

 

Applicative Order

: (λ x.a)((λ x.x x)(λ y.y y))  ->β  (λ x.a)(x x)[x\(λ y. yy)]  =  (λ x.a)((λ y. yy)(λ y. yy))

->β  (λ x.a)(yy)[y\(λ y. yy)]  =  (λ x.a)((λ y. yy)(λ y. yy)) - 무한 반복된다.

 

 

 각 평가 전략을 도입한 결과가 다르다. 따라서 어떤 평가 전략을 사용하느냐는 꽤 중요하다고 볼 수 있다. Church-Rosser 이론에 의하면, 식을 평가할 때 무한 반복되지 않고 끝날 수 있다면 Normal Order를 해당 식에 적용해도 끝날 수 있다. 그리고 똑같은 식에 두 평가 전략을 적용했을 때 모두 끝날 수 있다면, Alpha-conversion전까지 동일한 결과가 나온다.

 

 

3. Referrence

- λ Calculus tutorial

'CS ETC > Lambda Calculus' 카테고리의 다른 글

03. Reduction  (0) 2017.04.22
02. Lambda Calculus의 Syntax  (0) 2017.04.16
01. Lambda Calculus란?  (0) 2017.04.15
:
Posted by syjdev