프로그래밍 언어에서 상속 생략


10

내 프로그래밍 언어를 개발 중입니다. 그것은 int x = 1;클라우드를위한 것이 아닌 범용 언어입니다 (바탕 화면에 정적 유형의 파이썬을 생각하십시오 ).

상속이나 믹스 인을 허용하지 않는 것이 좋다고 생각합니까? (사용자가 최소한 인터페이스를 갖도록 주어진 경우)

예 : 상속을 허용하지 않아 프로그래밍 커뮤니티에 충격을 준 시스템 언어 인 Google Go .

답변:


4

실제로 상속을 사용하는 것이 차선책이라는 사실이 점점 더 많이 발견됩니다.

구현 상속은 항상 인터페이스 상속과 컴포지션으로 대체 될 수 있으며,보다 현대적인 소프트웨어 디자인은 컴포지션에 유리하게 상속을 사용하는 방향으로 가고 있습니다.

그래서 , 특히 상속을 제공하지 않는 것은 완전히 유효하고, 매우이다 의 유행 디자인 결정.

유지 mixin, 다른 한편으로는,도 (아직) 주류 언어 기능하지 않고, 언어 않는다 "믹스 인"기능을 제공 종종에 의해 매우 다른 것을 이해합니다. 부담없이 제공하십시오. 개인적으로 나는 그것이 매우 유용하다고 생각하지만 올바르게 구현하는 것은 매우 어려울 수 있습니다.


13

언어의 나머지 의미를 고려하지 않고 상속 (또는 실제로 하나의 기능)이 필요한지 아닌지에 대한 추론은 의미가 없습니다. 당신은 진공 상태에서 주장하고 있습니다.

필요한 것은 일관된 언어 디자인 철학입니다. 언어는 의도 된 문제를 우아하게 해결할 수 있어야합니다. 이것을 달성하기위한 모델은 상속을 요구하거나 요구하지 않을 수 있지만, 큰 그림이 없다면 이것을 판단하기는 어렵다.

예를 들어, 언어에 일급 함수, 부분 함수 응용 프로그램, 다형성 데이터 형식, 형식 변수 및 제네릭 형식이있는 경우 기존 OOP 상속에서와 동일한 기반을 사용하지만 다른 패러다임을 사용합니다.

늦은 바인딩, 동적 타이핑, 속성으로서의 메소드, 유연한 함수 인수 및 최고급 함수가있는 경우에도 동일한 패러다임을 사용하여 동일한 근거를 다룹니다.

(개요 된 두 가지 패러다임의 예를 읽는 것은 독자를위한 연습으로 남겨둔다.)

그래서 당신이 원하는 의미론에 대해 생각하고, 그것들을 가지고 놀며 상속없이 충분한 지 확인하십시오. 그렇지 않은 경우, 상속에 믹스를 던지거나 다른 것이 누락되었다고 결정할 수 있습니다.


9

예.

특히 언어가 동적으로 입력되는 경우 상속을 허용하지 않는 것이 좋습니다. 예를 들어 위임 또는 구성을 통해 유사한 코드 재사용을 달성 할 수 있습니다. 예를 들어, 좀 적당히 복잡한 프로그램을 작성했습니다 - 좋아,하지 것을 복잡 :) - 자바 스크립트의 모든 상속하지 않고. 기본적으로 객체를 대수 데이터 구조로 사용하여 일부 함수를 메소드로 첨부했습니다. 또한 이러한 객체에서 작동하는 방법 이 아닌 많은 기능이있었습니다 .

동적 타이핑을 사용하고 있고 가정한다면 상속없이 다형성을 가질 수 있습니다. 또한 런타임에 객체에 임의의 메소드를 추가하도록 허용하면 실제로 믹스 인과 같은 것이 필요하지 않습니다.

좋은 옵션이라고 생각되는 또 다른 옵션은 JavaScript를 에뮬레이트하고 프로토 타입을 사용하는 것입니다. 이것들은 클래스보다 간단하지만 매우 유연합니다. 고려해야 할 것.

그래서 모든 사람들이 말했습니다.


2
상속으로 일반적으로 처리되는 작업을 수행 할 수있는 합리적인 방법이 있다면 계속 진행하십시오. 몇 가지 유스 케이스를 시도하여 확인 할 수 있습니다 (아마도 다른 사람들의 예제 문제를 제기하고 자체 바이어스를 피하기 위해 ...)
comingstorm

아니요 정적이고 강력하게 입력되었으므로 맨 위에서 언급하겠습니다.
Christopher

정적으로 유형이 지정되었으므로 런타임에 객체에 임의의 메서드를 추가 할 수 없습니다. 그러나 여전히 오리 타이핑을 할 수 있습니다 . 예를 들어 Gosu 프로토콜 을 확인하십시오 . 여름에 프로토콜을 조금 사용했는데 정말 유용했습니다. Gosu에는 또한 사실 이후 클래스에 메소드를 추가하는 방법 인 "향상된 기능"이 있습니다. 그런 것을 추가하는 것도 고려할 수 있습니다.
Tikhon Jelvis

2
상속 및 코드 재사용과 관련하여 중지하십시오. 상속은 실제로 코드 재사용에 나쁜 도구라고 알려져 있습니다.
Jan Hudec

3
상속은 코드 재사용을위한 도구 중 하나 일뿐입니다. 종종 매우 좋은 도구이며 다른 경우에는 끔찍합니다. 상속보다 구성을 선호한다고해서 상속을 전혀 사용하지 않는 것은 아닙니다.
Michael K

8

예, 상속을 생략하는 것은 완전히 합리적인 디자인 결정입니다.

실제로 구현 상속을 제거해야하는 매우 좋은 이유가 있습니다. 코드를 작성하기가 매우 복잡하고 유지하기가 어렵 기 때문입니다. 상속 (일반적으로 대부분의 OOP 언어로 구현 됨)을 잘못된 것으로 간주하기까지합니다.

예를 들어 Clojure는 구현 상속을 제공하지 않으며 동일한 결과를 훨씬 더 명확하게 달성하는 데 사용할 수있는 일련의 직교 기능 (프로토콜, 데이터, 함수, 매크로)을 제공하는 것을 선호합니다.

Rich Hickey가 프로그래밍 언어의 복잡한 복잡성 (상속 포함)을 식별하고 각각에 대한 대안을 제시하는이 일반적인 주제에 대해 매우 깨달은 비디오가 있습니다.


대부분의 경우 인터페이스 상속이 더 적합합니다. 그러나 중재와 함께 사용하면, 상속 상속은 많은 상용구 코드를 제거 할 수 있으며 가장 우아한 솔루션입니다. 일반적인 Python / JavaScript 원숭이보다 더 지능적이고 더 신중한 프로그래머가 필요합니다.
Erik Alapää

4

VB6 클래스가 상속을 지원하지 않는다는 사실 (인터페이스 만)을 처음 접했을 때 실제로 저를 화나게했습니다.

그러나 그렇게 나쁜 이유 는 생성자 매개 변수가 없기 때문에 정상적인 종속성 주입 (DI)을 수행 할 수 없었기 때문입니다. DI를 가지고 있다면 상속보다 구성을 선호하는 원칙을 따를 수 있기 때문에 상속보다 중요합니다. 어쨌든 코드를 재사용하는 더 좋은 방법입니다.

그래도 믹스 인이 없습니까? 인터페이스를 구현하고 해당 인터페이스의 모든 작업을 종속성 주입을 통해 객체 세트에 위임하려면 Mixins가 이상적입니다. 그렇지 않으면 모든 메소드 및 / 또는 속성을 자식 객체에 위임하기 위해 모든 상용구 코드를 작성해야합니다. 나는 그것을 많이한다 (C # 덕분에) 그리고 내가 할 필요가없는 한 가지 일이다.


이 질문을 제기 한 것은 코드 재사용이 매우 유용한 SVG DOM의 구현입니다.
Christopher

2

다른 답변에 동의하지 않으려면 : 아니요, 더 원하는 기능과 호환되지 않는 기능은 버립니다. Java (및 기타 GC 언어)는 유형 안전성을 원했기 때문에 명시 적 메모리 관리를 중단했습니다. 하스켈은 방정식 추론과 공상 유형을 더 원했기 때문에 돌연변이를 버렸다. C조차도 컴파일러 최적화를 더 원했기 때문에 특정 종류의 앨리어싱 및 기타 동작을 버렸습니다 (또는 불법으로 선언).

질문은 상속보다 무엇을 원하십니까?


1
명시 적 메모리 관리 및 형식 안전성 만 완전히 관련이 없으며 확실히 호환되지 않습니다. 돌연변이 및 "팬시 유형"에도 동일하게 적용됩니다. 나는 일반적인 추론에 동의하지만 귀하의 예는 다소 잘못 선택되었습니다.
Konrad Rudolph

@ KonradRudolph, 메모리 관리 및 유형 안전은 밀접한 관련이 있습니다. A는 free/ delete동작은 당신에게 무효화 참조 할 수있는 기능을 제공합니다; 유형 시스템이 영향을받는 모든 참조를 추적 할 수 없으면 언어가 안전하지 않습니다. 특히 C 나 C ++은 모두 타입이 안전하지 않습니다. 동의하도록 서로간에 타협 할 수있는 것은 사실입니다 (예 : 선형 유형 또는 할당 제한). 정확히 말하면 Java가 특정 단순 유형 시스템과 무제한 할당을 통해 유형 안전 원한다고 말 했어야합니다 .
Ryan Culpepper 2012 년

오히려 유형 안전을 정의하는 방법에 달려 있습니다. 당신은 컴파일시 타입 안전 (전적으로 합리적인) 정의를 가지고, 예를 들어, 만약 귀하의 형식 시스템의 일부가 참조 무결성을하려면, 다음 자바는 안전 하나 (가 수 있기 때문에 입력되지 않은 null참조). 금지 free는 상당히 임의의 추가 제한 사항입니다. 요약하면, 언어가 안전한 유형인지 여부는 언어보다는 유형 안전에 대한 정의에 더 의존합니다.
Konrad Rudolph

1
@Ryan : 포인터는 완벽하게 타입이 안전합니다. 그들은 항상 그들의 정의에 따라 행동합니다. 그것은 당신이 좋아하는 방식이 아닐 수도 있지만, 그것들이 어떻게 정의되어 있는지에 따라 항상 다릅니다. 당신은 그들이 아닌 무언가가되도록 스트레칭하려고합니다. 스마트 포인터는 C ++에서 메모리 안전을 아주 간단하게 보장 할 수 있습니다.
DeadMG

@KonradRudolph : Java에서 모든 T참조는 null클래스 확장 중 하나 또는 객체를 나타냅니다 T. null추악하지만 null위의 불변 유형을 손상시키지 않고 잘 정의 된 예외를 처리하는 작업이 발생합니다. C ++와 대비 :를 호출 후 delete하는 T*포인터는 더 이상은 보유하는 메모리를 가리 수 없다 T개체를. 더 나쁜 것은 할당에서 해당 포인터를 사용하여 필드 할당을 수행하는 경우 다른 클래스의 객체 필드가 ​​근처 주소에 배치 된 경우 완전히 업데이트 할 수 있습니다. 그것은 용어의 유용한 정의에 의한 유형 안전이 아닙니다.
Ryan Culpepper

1

아니.

기본 언어 기능을 제거하려면 해당 기능이 결코 필요하지 않다는 것을 보편적으로 선언하고 있습니다 (또는 여기에 적용되지 않는 구현하기에는 부적합합니다). 그리고 "never"는 소프트웨어 엔지니어링에서 강력한 단어입니다. 그러한 진술을하려면 매우 강력한 근거가 필요합니다.


8
Java의 전체 디자인은 연산자 오버로드, 다중 상속 및 수동 메모리 관리와 같은 기능을 제거하는 것이 었습니다. 또한 모든 언어 기능을 "신성한"것으로 취급하는 것은 잘못이라고 생각합니다. 기능 제거 를 정당화 하는 대신 기능 추가 를 정당화 해야합니다. 모든 언어에 필요한 기능은 생각할 수 없습니다 .
Tikhon Jelvis

6
@TikhonJelvis : Java가 끔찍한 언어 인 이유는 "GARBAGE-COLLECTED INHERITANCE 사용"이 가장 중요한 이유입니다. 언어 기능을 정당화해야하지만 동의합니다. 이것은 기본 언어 기능입니다. 유용한 응용 프로그램이 많이 있으며 DRY를 위반하지 않으면 프로그래머가 복제 할 수 없습니다.
DeadMG

1
@DeadMG 와우! 꽤 강한 언어.
Christopher

@DeadMG : 의견으로 반박을 시작했지만 답변 (qv)으로 바꿨습니다.
Ryan Culpepper

1
"추가 할 항목이 없을 때가 아니라 제거 할 항목이 없을 때 완벽 함을 얻습니다"(q)
9000

1

엄격하게 C ++ 관점에서 말하면 상속은 두 가지 주요 목적에 유용합니다.

  1. 코드 재사용 가능성
  2. 자식 클래스의 재정의와 함께 기본 클래스 포인터를 사용하여 자식 클래스 개체의 유형을 모른 채 처리 할 수 ​​있습니다.

너무 많은 곡예에 빠지지 않고 코드를 공유 할 수있는 방법이 있다면 포인트 1의 경우 상속을 피할 수 있습니다. 포인트 2의 경우 자바 방식으로 가서이 기능을 구현하기 위해 인터페이스를 요구할 수 있습니다.

상속 제거의 이점은

  1. 긴 계층 구조 및 관련 문제를 방지합니다. 코드 공유 메커니즘이 충분해야합니다.
  2. 부모 클래스의 변경이 자식 클래스를 손상시키지 않도록하십시오.

이러한 상충 관계는 대개 "반복하지 말 것"과 한쪽의 유연성과 다른 쪽의 문제 방지 사이에 있습니다. 개인적으로 나는 C ++에서 상속이 단순히 다른 개발자가 문제를 볼만큼 똑똑하지 않을 수 있기 때문에 싫어하는 것을 싫어합니다.


1

상속이나 믹스 인을 허용하지 않는 것이 좋다고 생각합니까? (사용자가 최소한 인터페이스를 갖도록 주어진 경우)

구현 상속이나 믹스 인 없이 많은 유용한 작업을 수행 할 수 있지만 객체가 인터페이스 A를 구현하면 B 인터페이스 (예 : A는 B를 전문으로하므로 유형 관계가 있습니다. 반면에 결과 객체는 두 인터페이스를 모두 구현한다는 기록 만 있으면되므로 복잡성이 그리 크지 않습니다. 모두 완벽하게 할 수 있습니다.

구현 상속이 부족하다는 한 가지 단점이 있습니다. 클래스에 대해 숫자 인덱스 vtable을 생성 할 수 없으므로 모든 메소드 호출에 대해 해시 조회를 수행해야합니다 (또는 피할 수있는 영리한 방법을 찾아야 함). 이 메커니즘을 통해 기본 값 (예 : 숫자)까지 라우팅하는 경우이 작업이 어려울 수 있습니다. 모든 내부 루프에서 여러 번 적중하면 아주 좋은 해시 구현조차도 비쌀 수 있습니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.