본인쟝은 자바로 헬로월드도 찍을줄 모르니까 한귀로 듣고 한귀로 흘려도 댐
1. 상속 = 데이터 + 다형성 + 코드 재사용
상속이 데이터와 동작(메서드)를 함께 다룬다는 말은 흔히 있는데, 좀 더 세분화가 가능하다고 생각함. (위키피디아에서도 언급되는것 같음)
내가 볼 때 상속은 적어도
- 데이터
- Subtyping polymorphism (업캐스팅)
- Ad hoc polymorphism (인터페이스. 오버라이딩이 되면 클래스 자체가 인터페이스로서의 기능도 한다고 생각함)
- 코드 재사용
이렇게 4개가 섞여있음.
문제는 이 4가지가 한번에 일어나기 때문에 한가지씩 개별적으로 제어하기가 힘듬. 인터페이스가 더 나은 해결책으로 제시되는것도 이 4가지에서 Ad hoc polymorphism만을 분리했기 때문이라고 생각함.
2. 확장을 닫는 방법이 없음
Subtyping 관계 S <: T 는 forall x. (x : S) -> (x : T) 가 만족됨을 이야기함.
Liskov식으로 이야기 하면
forall φ. (forall x:T. φ(x)) -> (forall x:S. φ(x))
집합으로 보면 S가 T의 subset이라고 생각할 수 있는거고.
그런데 프로그래밍 언어에서 쓰이는 상속 관계를 보면 미묘하게 느낌이 다름.
A : extends B 를 봅시다.
이건 기존에 정의된 B의 부분집합인 A를 정의한다는 말이 아니라, 기존의 B를 A까지 포함하는 새로운 집합으로 확장한다에 가까움.
그러니까 상속이 일어날때마다 모든 superclass들의 범주가 늘어나고, 상속을 완전히 막지 않는 이상 확장을 제어할 수 없음.
이 점에 있어서 클래스는 데이터보다도 인터페이스(타입클래스)와 유사함. 하스켈의 경우를 보면, 데이터는 닫혀있고 타입클래스는 열려있음. 즉, 데이터 타입의 element가 될 수 있는것들은 데이터를 정의하는 순간 결정되고, 타입클래스의 instance는 언제든 추가할 수 있음.
문제는 객체지향의 클래스는 데이터를 다루는데도 열려있다는 점임. 이건 꽤나 심각한 문제라고 생각함.
예를 들어서 집합이 닫혀있으면 case analysis를 통해서 어떤 함수가 항상 옳바르게 작동함을 검증할 수 있음.
OOP 클래스에서는 상속이 일어날때마다 집합이 늘어나기 때문에 비슷한 검증을 하려면 모든 자식클래스들에 대해 전부 검증해야하고, 그마저도 언제든지 새로운 자식클래스를 만들 수 있기 때문에 결국 검증책임을 자식클래스 쪽에 부과하는 수밖에 없음. 이건 결국 superclass가 interface와 비슷한 역할을 한다는 말임.
그런데 이건 클래스를 정보 은닉, 모듈화에 사용하는거랑은 정반대의 개념임. 흔히 생각하는 private를 사용하는 정보은닉의 주체는 superclass인데, interface에서 정보은닉의 주체는 각각의 instance들이니까.
그렇지 않으면 부모 자식 클래스간에 서로의 정보를 은닉한다는 소린데, 이게 OOP에서 지향하는 바인지는(혹시 그럼?) 잘 모르겠지만 적어도 하스켈에서 의존성의 방향은 항상 일방적임.
내 결론은 :
정보 은닉과 모듈화의 대상은 데이터와 메서드임. 그런데 클래스가 인터페이스와 비슷한 역할을 하면 이에 모순됨. 그러니 코드 재사용, 데이터 구조, 다형성을 전부 분리해야함.
그리고 바람직한 Subtyping의 형태는, 확장이 아니라 구체화라고 생각함.
subtyping이 일어날 때 범주가 넓어지는게 아니라, 기존의 클래스의 일부분으로 제한된 새로운 범주를 만드는 식으로. 물론 이건 subtyping이라는 것만 빼면 상속이랑은 전혀 다르다고 봄.
- dc official App
머래는거야
기본적으로 프로그래머가 잘 짜는게 중요하다고 생각함. 2번 문제의 경우 제네릭을 이용하면 될 것 같네 - dc Cpp
왠지 집합의 관점에서 객체지향의 상속을 해석하려는 느낌이 드는데, 내 생각엔 그건 함수형의 개념을 객체지향에 끼워 맞춰서 이해하려면 꼬이는 것과 비슷한 위험이 있는 문제 같다. 예컨대 2 같은 경우 객체지향의 상속은 어떤 이미 정의된 집합이 있는데 그 중 일부를 뜯어서 부분 집합을 만드는 것이 아니라, 예를들면 워드 프로세서를 만들어서 팔았는데 처음엔 고려 하지 않았던 다른 문서 양식에 대한 처리를 구현하기 위해 관련 클래스를 확장해서 구현을 넣는 개념이다. 애초에 '세상에 존재할 수 있는 모든 문서 형식을 파싱하는 클래스의 집합' 같은 건 최소한 실용적인 관점에선 의미가 없잖아? 그래서 내 생각엔 단순이 맥락의 혼동 때문에 생긴 오해인 것 같다.
집합은 단순히 설명을 위해 빌린 표현일 뿐이고, 여기서 중요한 논리는 확장은 클래스를 인터페이스처럼 쓰는일이고, 이게 superclass의 정보를 은닉하는것과 모순된다는 말임. 님은 상속관계에서 어느쪽의 정보가 은닉되는것이 맞다고 생각하는거임? - dc App
정보 은닉의 관점이라면 접근 제어자가 충분히 제 기능을 한다고 본다. 부모 입장에서 하위 구현의 내부 정보를 따지는 거야 보통은 설계 잘못이니 논외로 하고, 반대 경우라면 설계한 사람이 명확하게 어느 부분을 접근할 수 있는지 접근 제어자로 정의할 수 있잖아? 객체지향에서 정보 은닉이 중요하다는 건 설계자의 의도를 벗어나서 불필요한 정보를 노출하지 말라는 거지 의도한 것도 하지 말라는 건 아니니 상속의 근본적인 문제 같은 건 모르겠다.
참고로 굳이 확장을 '닫아야'하는 요구 조건이 있는 경우 언어에 따라 final이나 sealed 같은 키워드를 통해서 해당 파일이나 모듈 범위 밖에서 추가 상속을 막는 경우는 있다.
허벌창 시스템이 주는 자유가 실용을 낳는다
해당 댓글은 삭제되었습니다.
다중 상속은 금기아님?
상속을 좆같게 만드는 키워드만 주렁주렁 써놨네
talk is cheap show me the codes
code 어디
C++ 안하는데 뭔소리냐 제정신인가
하다가 저 키워드때문에 좆같아서 때려쳤는데 딴지걸면안됨?
미친놈이네;; 역시미친언어
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
헤더엔 선언만 있고, 상세한 정의는 공개 안되어 있는거 아님?
IDE마다 다를걸
이건 나도 조금 생각이 정리되지 않은 부분이긴 한데, 경험적으로 주로 함수형과 객체지향의 관심사는 대략 서로 겹치지 않는(tangential)한 것 같다. 물론 함수형의 개념들도 타입으로 표현하지만, 그런 타입과 객체지향의 비즈니스 인터페이스를 섞어 쓰는 건 거의 못 본 것 같고, 스칼라 같이 두 패러다임을 섞을 수 있는 언어에서 애드혹 폴리모피즘 같은 게 필요한 부분은 보통 별도 유형으로 분리해서 객체지향의 큰 틀 안에서 (그러니까 비즈니스를 표현한 계층 구조) 주로 메서드의 구현 수준에서 해당 함수형 타입 등을 이용하게 되서 어느 정도 분리는 되는 것 같다.
예시는 하스켈로 들었지만 함수형하고는 별 관계없는 이야기임. 타입클래스 = 인터페이스라고 생각해도 좋음. 그리고 ad hoc polymorphsim이 인터페이스 말하는거 - dc App
그러니까 타입 클래스와 객체지향의 비즈니스 인터페이스가 같은 레벨에서 엮이는 상황 자체가 거의 안나온다는 거야.
반대로 이야기하면, 객체지향의 비즈니스 인터페이스를 타입 클래스 같은 개념으로 이해하려 할 이유도 없고.
역할은 다르지만 원리는 같은데? 애초에 내가 쓴 글에서 타입클래스에 대해 전제한건 인스턴스가 언제든지 추가될 수 있다는 말이고, 이건 인터페이스에서도 성립하잖아. 난 딱히 함수형의 관점을 투영해서 설명하고 싶은건 아님 (그렇게 보이는지는 모르겠지만) - dc App
단적으로 말해서 모나드이면서 UI의 툴킷의 버튼이라는 개념을 상상할 수 있어? 스칼라 같이 대놓고 패러다임 섞어 쓰라고 만든 언어에서도 그렇게는 안해. 물론 스칼라 API의 모나드 타입도 trait으로 구현하고 버튼 같은 것도 trait으로 할 수 있지. 그걸 니가 말한 '원리'라고 굳이 말하자면 할 수는 있는데, 그건 설계 개념적으로 호환될 수 있는 게 아니라, 단지 그런 개념을 해당 언어에서 표현하는 방식이 동일하게 trait이기 때문에 그런 관계가 된 것 뿐이라고 본다. 내가 느끼기엔 너가 워낙 함수형을 잘 이해하고 익숙해서 객체지향 패러다임도 비슷한 틀에서 보는 과정에서 혼동이 되는 게 아닌가 싶다. 아마 내가 함수형을 깊게 파다보면 반대로 혼동을 하는 경우도 있을지 모르지만 말이야.
먼지모르겠고 개추
Subtyping 과 Inheritance는 완전히 독립적인 관계에 있다고 본다. 애초에 방향성이 완전히 다름 - dc App
언어 따라 다르긴 하지만, upcasting만 해도 subtyping 때문에 가능한건데? 무슨 방향성이 다르다는 말임? - dc App
너무 단정했나? 위키에서도 그렇고 Independent 하면서 Orthogonal 하다고 본다. 그러니까 Inheritance가 Subtyping일 수도 있지만, 항상 그렇지는 않는다는 뜻임.
https://www.cs.utexas.edu/users/wcook/papers/InheritanceSubtyping90/CookPOPL90.pdf
이런 자료도 많이 나오는듯. 특히 대학쪽에서
그래서 겜렌진은 컴포넌트 방식으로 프로그래밍하자너
타입클래스 만세