Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2장 서브타입에 의한 다형성 #345

Closed
Tracked by #343
fkdl0048 opened this issue Jan 10, 2025 · 0 comments
Closed
Tracked by #343

2장 서브타입에 의한 다형성 #345

fkdl0048 opened this issue Jan 10, 2025 · 0 comments

Comments

@fkdl0048
Copy link
Owner

fkdl0048 commented Jan 10, 2025

서브타입에 의한 다형성

객체와 서브타입

객체라는 개념이 있는 정적 타입 언어라면 대개 서브타입에 의한 다형성도 제공한다. 타입 검사에서 서브타입에 의한 다형성은 실제로 같은 타입이 아니더라도 코드에서 이를 인식할 수 있게 해준다.

서브타입에 의한 다형성은 서브타입이라는 개념을 통해 실현한다. 그러므로 서브타입에 의한 다형성을 이해하려면 서브타입부터 이해해야 한다. 서브타입은 A is a B라는 관계를 의미한다. 이 관계는 A는 B의 서브타입이라는 것을 의미한다. 서브타입에 의한 다형성은 A가 B의 서브타입일 때 A 타입의 부품을 B 타입의 부품으로도 간주할 수 있게 하는 기능이 서브타입에 의한 다형성이다.

문제는 A가 B의 서브타입이다라는 사실을 사람은 그렇다고 할 수 있지만 타입 검사기는 이를 인정하지 않아 통과하지 못하는 경우가 생길 수 있다는 것이다. 따라서 A는 B다가 사실이면 A가 B의 서브타입이다라는 설명을 통해 서브타입이라는 개념을 직관적으로 이해하되, 실제 코드를 작성할 때는 타입 검사기가 사용하는 규칙을 고려하여 서브 타입의 관계를 파악해야 한다.

타입 검사기가 객체 타입의 서브타입 관계를 판단할 때 사용하는 규칙에는 이름에 의한 서브 타입 관계와 구조에 의한 서브타입이 있다.

이름에 의한 서브 타입 관계

이름에 의한 서브타입을 사용하는 경우, 타입 검사기는 타입이 보여주는 클래스 이름과 클래스 사이의 상속 관계만 고려한다. 해당 클래스가 어떻게 생겼는지, 그 클래스에 어떤 필드와 메서드가 있는지는 전혀 신경 쓰지 않는다.

class Person { public string email; }
class Student : Person { public int grade; }
void sendEmail(Person person) 
{
    string email = person.email;
    ...
}
Student student = new Student();
sendEmail(student);

구조에 의한 서브 타입 관계

이미 정의된 클래스를 수정할 수 없는 경우에는 이름에 의한 서브타입으로는 부족할 수 있다. 그럴 때는 구저에 의한 서브타입이 필요하다. 사용중인 라이브러리에 동일한 이름을 가진 클래스가 존재한다면 코드는 오류를 발생시킨다. 이러한 불편을 해소시켜주는 개념이 구조에 의한 서브타입이다.

구조에 의한 서브타입을 사용하는 경우 타입 검사기는 클래스 사이의 상속 관계 대신 클래스의 구조(각 클래스가 어떤 필드와 메서드가 있는지 고려한다.) 만약 클래스 A가 클래스 B에 정의된 필드와 메서드를 모두 정의한다면 A는 B의 서브타입이다.

추상 메서드

추상메서드는 메서드를 정의하지 않되 이 클래스를 상속하려면 특정 메서드를 반드시 정의해야 한다는 사실을 표현하는 것이 추상 메서드의 용도다. 또한 추상 메서드를 가지는 대신 객체를 직접 만들 수 없는 클래스를 추상 클래스라고 부른다. 언어에 따라 추상 클래스 대신 인터페이스, 트레이드등의 용어로 사용한다.

집합론적 타입

집합론적 타입이란 수학 집합론에서 나오는 전체 집합, 공집합, 합집합, 교집합으로부터 유래되었다.

최대 타입

'아무 값이나 가능하다'라는 표현이 없는 것은 여러 불편함을 가져온다. true ? 1 : false이와 같은 코드는 아무런 오류가 없음에도 타입 검사를 통과하지 못한다. 이는 '결과값이 아무 값이나 될 수 있다'를 표현하는 타입이 있다면 검사를 통과할 수 있을 것이다. print함수의 경우

최대 타입은 결국 '가장 큰' 타입이다. 즉, 모든 값을 포함하는 타입을 말하며 어느 값이든 최대 타입에 속한다. 가장 큰 부모, C#으론 object

최소 타입

최소 타입은 예외를 다루는 데 유용한 타입이다. error함수는 어디서든 호출할 수 있다. 그 이유는 error가 계싼이 끝나지 않는 함수이기 때문이다. error를 호출하면 값을 반환하지 못한 채 예외가 발생해 실행이 종료된다. 따라서 어떤 타입의 값이 필요한 곳이든 항상 괜찮다.

계산을 끝마치지 못한다를 표현한느 타입이 바로 최소 타입이다. 최소 타입의 특징은 모든 타입의 서브타입이라는 점이다.

최대 타입과 최소 타입은 정반대의 개념이면서 비슷한 면이 있다. 최대 타입이 '아무 값이나 될 수 있다'를 의미한다면 최소 타입은 '아무 곳에나 사용될 수 있다'를 의미한다. 하지만 둘은 전혀 다른 뜻이고 다른 역할을 한다.

이거나 타입

프로그래밍을 하다 보면 한 함수가 받는 인자의 타입이 여러 가지가 되어야 하는 경우가 생긴다. 이거나 타입은 이러한 경우 유용한 개념이다. 같은 기능을 하는 함수를 사용할 때, 매개변수의 타입에 따라 함수를 분리하는 경우가 있는데 이때 사용하면 유용한 개념이다.

이거나 타입을 사용할 때는 민감한 타입 검사라는 개념을 이해해야 한다. 실제로는 문제 없지만 코드상으로 직관적인 오류가 있을 때, 정의된 곳의 타입만 보는 것이 아닌 그 변수의 사용 위치도 고려하는 것 하지만 민감함 타입 검사도 프로그램이 복잡해지면 위치로부터 정보를 얻을 수 없게 된다.

따라서 이거나 타입을 사용할 때는 민감한 타입 검사가 잘 작동하도록 프로그램 구조를 단순하게 만들어야 한다.

이면서 타입

이면서 타입은 다중 상속을 다룰 때 유용하다. 학생과 선생의 클래스를 상속받아 조교의 역할을 할 때 이면서 타입은 이거나 타입과 비슷하면서도 반대되는 역할을 한다. 이거나 타입처럼 이면서 타입도 두 개이 타입으로부터 만들어진다.

함수와 서브타입

여러 언어에서 함수를 값으로 사용할 수 있다. 함수를 값으로 사용한다는 말은 함수를 변수에 저장하거나 다른 함수에 인자로 전달하는, 다른 함수에서 반환한다는 뜻이다. Delegate 함수의 타입은 매개변수 타입과 결과 타입을 차례대로 쓴 것이다. int -> string

함수 타입은 그 자체만으로는 서브타입에 의한 다형성을 필요로 하지 않는다. 하지만 언어에 객체와 서브타입에 의한 다형성이 존재하면 함수 타입 사이의 서브타입 관계를 따질 필요가 생긴다.

함수 타입 사이의 서브타입 관계가 없으면 당연히 타입 검사를 통과해야 할 것 같은 코드가 그러지 못하는 불편함이 생긴다. 일급 함수를 사용하는 경우에는 함수 타입 사이의 서브타입 관계를 타입 검사기가 잘 판단하는 게 필수다. 함수 타입 사이의 서브타입 관계는 "함수 타입은 매개변수 타입의 서브타입 관계를 뒤집고 결과 타입의 서브타입 관계를 유지한다"라고 정리할 수 있다.

정리

실제 내가 사용하는 언어에서는 서브타입에 의한 다형성이 어떻게 나타나는지를 고민해보면서 읽어봤다. 델리게이트나 인터페이스, 최대/최소 등 어느정도 이해가 되고 당연하다는 생각도 드는 한편 처음 접한 타입도 있어서 찾아본 내용도 있다.

좋았던 점은 내가 알고 있는 다형성의 개념들을 타입이라는 틀로 다시 한 번 정확하게 짚어가며 타입 검사기의 과정 당연한게 왜 당연한지 A 와 B 그리고 C와 D의 관계들로 풀어준 부분이 나에게 도움이 된 것 같다.

논의사항

이름에 의한 서브 타입은 익숙한 반면 구조에 의한 서브 타입은 낮설게 느껴졌습니다. 두 서브타입 모두 목적은 결국 다형성을 제공한다는 것이지만 구조에 의한 서브 타입은 지나치게 유연한게 아닌가 라는 생각도 듭니다. 한편으로는 직관적이고 더 단순하고 명확하다는 생각도 듭니다

제가 사용하는 언어는 C#이면서 이름에 의한 서브 타입 관계를 사용합니다. 또한, 인터페이스라는 개념으로도 서브타입을 나타낼 수 있는데 인터페이스는 어떠한 행위를 추상적으로 정의하여 다형성을 나타냅니다. C#의 관점으로 책에서 보여지는 구조에 의한 서브 타입이 가능한가? 라는 생각이 듭니다.

책에서 보여주는 예제는 필드에 해당되기에 속성만 같으면 같은 타입으로 인정한다 라는 개념이 이해는 되지만, 그것이 메서드나 행위에 해당될 때는 다르지 않을까? 궁금합니다. 같은 메서드를 시그니처로 판단하는지, 함수 내부 구현부가 다르다는 점으로 다형성을 나타내는건지? 저와 같은 생각을 하신 분이나 생각이 있으시다면 같이 이야기해보면 좋을 것 같습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

No branches or pull requests

1 participant