[Swift] pass-by-value vs pass-by-reference

정유진·2023년 7월 31일
0

swift

목록 보기
23/24

들어가며

Swift는 몇 가지의 예외를 가지고 있는 pass-by-value 언어이다. pass-by-value 언어는 함수의 argument로 전달될 때의 값을 복사하여 전달한다. 따라서 호출한 함수에 argument로 값을 전달하고 함수 블록 안에서 값의 변화가 생기더라도 original value에는 영향을 미치지 않는다. 하지만 argument가 class 일 경우에는 주의가 필요하며 inout parameter를 통해 함수 안에서의 변화가 original value에도 영향을 미칠 수 있다.

개념 정리

1) pass-by-value

pass-by-value 하는 언어의 경우 SomeObject thing = new SomeObject() 해도 thing에 담기는 것은 주소 값이지 original 객체가 아니고 (이것은 pass-by-value이기 때문이 아니라 class가 reference type 이기 때문) 함수에 argument로 넘길 때 주소값의 copy가 넘어가기 때문에 method를 통해 객체의 property에 접근하는게 아닌 이상 original value인 객체 자체를 바꿀 방법은 없다. (달리 말하면 객체 자체를 갈아치울 수는 없으나 method를 통해 object에 접근하여 property 값은 바꿀 수 있다는 뜻이다.)

class Person {
  String name;
  int age;

  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
}

public class PassByValue {
  public static void main(String[] args) {
    Person person = new Person("John Doe", 30);
    System.out.println("The age of person before calling pass_by_value is:", person.age);
    pass_by_value(person);
    System.out.println("The age of person after calling pass_by_value is:", person.age);
  }

  public static void pass_by_value(Person person) {
    // This will not change the age of the original person object
    person = new Person("Jane Doe", 31);
  }
}

따라서 값 변경을 위해서는 method를 사용하거나 field 값에 직접 접근하여야 한다.

 public static void pass_by_value(Person person) {
    person.setName("my_new_name");
    person.age = 100;
  }
}

2) pass-by-reference

pass-by-reference로 분류될 수 있는 언어는 아래와 같다.

  • C++
  • C#
  • Pascal
  • Python
  • Ruby
  • Scala

이들 언어는 argument로 주소값을 전달하며 직접적으로 original value를 바꿀 수 있다. 따라서 함수 내부에서 직접적인 방법으로 객체 값을 변경할 수 있고 변수의 copy를 만들 필요가 없다. 하지만 이러한 특성 때문에 변경 사항을 추적하기가 어렵고 개발자가 부주의한 경우 오류 발생 확률을 높이게 된다.

Swift에 접목하기

1) value type과 reference type 분류를 의미하는 것이 아니다.

https://stackoverflow.com/questions/27364117/is-swift-pass-by-value-or-pass-by-reference

Swift에서 흔히 value-type으로는 struct, enum 을 말하고 reference-type으로는 class를 말한다. 이 글에서 말하고자 하는 것은 class가 value-type이라고 하는 것이 아니라 어떻게 전달되느냐의 문제이다. 이에 대한 논쟁이 위에 첨부한 stackOverFlow의 첫 번째 코멘트에 나와있다. 위 게시글에서 기억할 만한 두 가지를 추려보았다.

  • Swift는 기본적으로 copy를 넘긴다. value-type의 경우 값의 copy를 넘기고 reference-type의 경우 주소의 copy를 넘긴다.
  • copy라는 표현은 조심스럽게 사용될 필요가 있다. Swift에서는 optimization이 되어 있어 실제로 객체에 mutation이 발생하지 않는 이상 실상 copy는 이루어지지 않는다.

2) inout

func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
    value1 = "new Value";
    value2 = 1;
}

var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);

위의 코드를 보면 return으로 값을 받지 않아도 함수에서 inout param에 직접 할당했기 때문에 val1, val2는 각각 "new Value", 1로 변경된다. 주목할 점은 값을 주입할 때에 & 기호를 붙였다는 것이다. 전통적인 pass-by-reference일 경우 variable을 직접적으로 넘기는 것으로 충분하지만 Swift는 inout으로 넘길 값에 대해 & operator를 붙이도록 했다. 따라서 엄밀히 말하면 pass-by-reference라고 할 수는 없고 같은 효과를 낼 수 있다고 말할 수 있겠다. 한 편 이런 방법이 있다는 것을 알아두긴 하되 사용하지 않는 것이 좋겠다. 아래와 같은 단점이 명백하다.

  • 코드가 복잡해진다.
  • single value를 return 하도록 명시하는 것이 클린하다.

의의

Swift 언어의 특징을 짚어보며 값 타입을 사용하도록권장하는 것을 느낀다. 실제로 Swift는 objc에 비해 정적인 면모가 넘친다. 이는 data-race를 피하기 위한 전략 중 하나인 것으로 보인다.

profile
느려도 한 걸음 씩 끝까지

0개의 댓글