about-objects.md

Ruby koans의 about_objects.rb를 정리한 내용


is_a

 

인수의 클래스가 오브젝트의 클래스이거나 부모 클래스의 오브젝트 중 하나 혹은 모듈이 오브젝트에 속해 있으면 true를 반환한다.

=> 위의 예제는 Integer, Float, String, nil, Object 모두 Object 클래스를 부모 클래스로 가지고 있으므로 true를 반환한다.

 

to_s

 

to_s는 어떤 오브젝트든 문자열로 표현할 수 있는 메서드이다.

=> 위의 예제는 숫자 123(Integer)을 문자열 "123"로, nil("아무것도 없음"을 의미, nothing)을 문자열 ""로 변환한다.

 

inspect

 

inspect는 to_s처럼 오브젝트를 문자열로 변환한다. 하지만 차이점이 있다.

to_s는 오브젝트의 내용 자체를 문자열 변환하며, 객체 클래스의 경우 obejct_id를 문자열로 변환한다.

반면, inspect는 객체에 기록된 내용을 지정된 형식의 문자열 형태로 변환한다. 즉, 개발자가 디버깅하는데에 좀 더 친숙한 문자열 형태로 반환해준다.

ex) inspect user obj

 

=> 위의 예제에서 nil.inspect의 경우는 개발자가 읽기 쉬운 형태로 값을 변환해주기 때문에 nil을 문자열 형태로 변환하여 표현한다.

 

obj.object_id.class ==? Fixnum

 

Ruby의 Fixnum은 'Lisp'에서 온 것으로 32bit(in VM)의 고정된 정수 값을 나타낸다. 정수 값의 범위는 -((2^30)-1)에서 (2^30)-1로 -1073741824에서 1073741824의 정수를 표현한다. (그 외의 작고 큰 정수 값은 Bignum으로 표현한다.)

ex)

 

=> 위의 예제에서 object_id는 일반적으로 Fixnum이 표현할 수 있는 범위 내의 정수 값을 할당받게 되므로 object_id의 클래스명은 Fixnum이다.

 

object has different id

 

모든 객체 인스턴스는 자신을 유일하게 식별할 수 있는 고유한 object_id를 갖는다. 여기서 object_id는 정수(Interger) 값으로 표현한다. 고유한 정수 값이기 때문에 메모리 주소 값을 할당 받는다고 생각할 수 있다.

=> 위의 예제에서 obj와 another_obj 객체 인스턴스는 생성될 때 서로 다른 object_id를 갖기 때문에 not 비교문에서 true를 반환한다.

 

object_id pattern for small integers

 

위의 몇 가지 예제를 통해 객체 인스턴스는 고유한 obejct_id를 갖고 Fixnum을 통한 정수 값을 할당받는다고 설명했다. 그렇다면 true, false, nil과 같이 항상 같은 값을 갖는 오브젝트들은 어떻게 object_id 값을 설정할까? 또한 Fixnum 범위 내에서 정수(Integer)의 object_id 값은 어떻게 설정할까?

이렇게 객체 인스턴스뿐만 아니라 고정 오브젝트 타입의 obejct_id 값들을 설정하기 위해 bit pattern을 사용했다. (여러 참고 문서를 통한 추측일뿐 확실한 정보는 아님)

object_id는 "(Fixnum * 2) + 1"의 연산 결과값이 할당된다.

아래의 예제를 보면, Ruby에서 false는 값을 0으로 하드코딩한 것이 아니라 상단의 비트패턴 연산을 사용하여 값을 구한 것을 알 수 있다.

ex)

 

그러면 (Fixnum * 2) + 1의 비트 연산 과정을 자세히 살펴보자.

먼저 Fixnum은 32bit를 사용한다고 했다. 여기서 흥미로운 점은 만약 Fixnum의 마지막 비트가 0인 경우에는 31bit만을 사용하고, Fixnum의 마지막 비트가 1인 경우 32bit 모두를 사용한다.

아래는 정수 4와 5의 비트연산 예제이다.

ex) object_id of 4

 

ex) object_id of 5

 

이러한 계산 방식에는 2 가지의 부작용이 있다.

첫 번째로 위의 Fixnum 연산은 마지막에 1을 추가하므로 모든 Fixnum object_id는 홀수이다. 이를 통해 시스템에 다른 모든 객체의 object_id는 짝수라는 것을 알 수 있다.

두 번째로 홀수 Fixnum만이 Fixnum object_id로 사용된다. Fixnum 절반이 Fixnum object_id로 채워져 있고 나머지 절반에 다른 object_id를 채워넣어야 하는데, 다른 모든 obejct_id가 너무 커서 31비트에 들어가지 않는다는 것이다. 만약 시스템이 짝수 Fixnum 공간에 충분한 객체들을 인스턴스화 하는데에 써버린다면, 일반 객체의 object_id는 Bignum을 얻게 된다.

 

clone object

 

obj.clone을 사용하면 인스턴스 객체의 복사본을 생성할 수 있다.

일반적으로 객체는 주소값을 참조하기 때문에 코드 범위내에서 값을 공유한다. 객체의 값을 수정하면 같은 변수명을 가진 객체의 값 또한 변경된다.

하지만 객체의 복사본을 생성하면 서로 다른 주소값(object_id)을 할당 받기 때문에 값이 공유될 수 없으며 서로 다른 객체로 인식한다.

=> 그러므로 위의 예제의 비교문들은 true를 반환한다.


참고 자료

+ Recent posts