동등성(equality)이란 두 대상이 같다는 것을 의미합니다. Ruby에서는 객체와 그 값을 비교하여 두 객체가 같은지 판단할 수 있습니다.
그렇다면 질문은 이것입니다.
Ruby에서 두 객체는 어떻게 비교할까요?
답은 간단합니다.
1 == 1 # true
아마 이미 익숙하게 사용하고 계실 겁니다.
하지만 ==가 단순한 문법이 아니라 하나의 메서드라는 사실을 알고 계셨나요?
이것의 의미는 상당히 큽니다.
자신만의 클래스에서 이 메서드를 직접 구현하면 클래스를 훨씬 더 강력하게 만들 수 있습니다. 지금부터 그 방법을 자세히 알아보겠습니다!
두 객체가 '같다'는 것은 무엇을 의미할까?
문자열은 다음과 같이 비교할 수 있습니다.
"foo" == "foo"
단어와 문자가 모두 같다면 두 문자열은 동등하며, 표현식은 true를 반환합니다.
이것이 가능한 이유는 String 클래스가 문자열을 비교하는 방법을 아는 ==(등호 두 개) 메서드를 내부적으로 구현하고 있기 때문입니다.
그런데 만약 String 클래스에 == 메서드가 없다면 어떻게 될까요?
그 경우 Ruby는 Object 클래스의 == 구현을 사용하게 되는데, 이 기본 구현은 객체의 내용이 아니라 객체의 정체성(object identity), 즉 동일한 객체인지 여부를 검사합니다.
예시:
Object.new == Object.new # false String.new == String.new # true
Object가 false를 반환하는 이유는 새로 생성된 두 객체는 서로 다른 object id를 가지기 때문입니다.
반면 String은 내용을 기준으로 비교하기 때문에, 새로 생성된 두 빈 문자열은 내용이 같으므로(둘 다 비어 있음) true를 반환합니다.
동등성 직접 구현하기
이제 배운 내용을 활용해, 객체끼리 비교할 수 있는 강력한 나만의 클래스를 만들어 보겠습니다.
== 메서드를 덕분에...
여러분의 클래스 인스턴스 두 개가 '같다'는 것이 정확히 무엇을 의미하는지 직접 정의할 수 있습니다.
예시:
class Product
attr_reader :name, :price
def initialize(name, price)
@name, @price = name, price
end
def ==(other)
self.name == other.name &&
self.price == other.price
end
end
p1 = Product.new('book', 49)
p2 = Product.new('book', 49)
p1 == p2 # true
위 코드의 == 메서드는 이름과 가격이 모두 같아야 두 Product 객체를 동등하다고 판단한다는 규칙을 정의합니다.
기억하세요:
이 메서드를 직접 구현하지 않으면(또는 제 책에서 설명하는 Comparable 모듈을 사용하지 않으면) 두 객체는 값이 아니라 object id를 기준으로 비교됩니다.
또 한 가지 참고할 점은, Struct를 사용하면 == 메서드가 이미 내장되어 있다는 것입니다.
삼중 등호(===)는 어떨까?
==가 메서드라면 ===도 메서드일까요? 답은 그렇습니다 🙂
그렇다면 둘의 차이점은 무엇일까요?
Javascript에서는 차이가 명확합니다. ==는 타입이 다를 경우(1 vs '1') 타입 변환을 시도하고, ===는 '엄격한(strict)' 동등성 검사를 수행합니다.
하지만 Ruby에는 그런 구분이 없습니다. ===의 의미는 이를 구현하는 클래스에 따라 달라집니다.
많은 경우 ===는 단순히 ==의 별칭(alias)입니다.
String과 Object가 그 예입니다.
반면 ===에 특별한 의미를 부여하는 내장 클래스들은 다음과 같습니다:
| 클래스 | 의미 |
|---|---|
| Range | 객체가 해당 범위(range)에 포함되어 있으면 true, 아니면 false를 반환합니다. |
| Regexp | 정규표현식을 문자열과 매칭합니다. |
| Module | 객체가 해당 모듈 또는 그 하위 클래스의 인스턴스이면 true를 반환합니다. |
| Proc | Proc#call처럼 객체를 인수로 블록을 실행합니다. case 문의 when 절에서 proc 객체를 대상으로 사용할 수 있도록 하기 위함입니다. |
마무리
이 글에서는 == 메서드를 직접 구현하여 클래스를 더 강력하게 만드는 방법을 배웠고, ==와 ===의 차이점도 함께 살펴보았습니다.
더 많은 사람들이 볼 수 있도록 이 글을 공유하는 것도 잊지 마세요 🙂