복붙노트

[SCALA] 스칼라 : 제네릭 대 추상은 유형

SCALA

스칼라 : 제네릭 대 추상은 유형

나는 스칼라의 여행을 읽고 있었다 : 추상 유형. 때 그것은 추상적 인 형식을 사용하는 것이 좋습니다?

예를 들어,

abstract class Buffer {
  type T
  val element: T
}

오히려 그 제네릭, 예를 들어,

abstract class Buffer[T] {
  val element: T
}

해결법

  1. ==============================

    1.현재이 문제에 대한보기의 좋은 점을 가지고 :

    현재이 문제에 대한보기의 좋은 점을 가지고 :

    스칼라의 타입 시스템의 목적 마틴 오더 스키, 파트 III와 대화 빌 베너 스 프랭크 머스 (2009 5 월 18 일)에 의해

    업데이트 (2009 년 10 월) : 아래 실제로 빌 베너 스에 의해 새로운 문서에 설명 된 다음과 무엇을 : 스칼라에서 제네릭 형식 매개 변수 대 추상 형식의 멤버 (마지막에 요약 참조)

    (다음은 2009 년 5 강조 광산, 첫 번째 인터뷰의 관련 추출물)

    항상 추상화의 두 가지 개념이 계속있다 :

    자바에서는 당신은 또한 모두가, 그러나 당신이 이상 추출 무엇에 따라 달라집니다. 자바에서는 추상 메소드를 가지고,하지만 당신은 매개 변수로 방법을 전달할 수 없습니다. 당신은 추상적 인 분야가 없습니다,하지만 당신은 매개 변수로 값을 전달할 수 있습니다. 그리고 마찬가지로 당신은 추상 형식의 멤버가없는,하지만 당신은 매개 변수로 유형을 지정할 수 있습니다. 그래서 자바에서 당신은 또한 이러한 세 가지를 모두 가지고 있지만, 추상화 원리는 당신이 일의 종류에 사용할 수있는 작업에 대한 구별이있다. 그리고이 구분이 상당히 임의적이라고 주장 할 수있다.

    우리는 회원의 세 가지 종류에 대해 동일한 구성 원리를하기로 결정했다. 그래서 당신은 추상적 인 분야뿐만 아니라 값 매개 변수를 가질 수 있습니다. 당신은 매개 변수로 방법 (또는 "기능")을 전달할 수 있습니다, 또는 당신은 그들에 추상적 할 수 있습니다. 당신은 매개 변수로 유형을 지정할 수 있습니다, 또는 당신은 그들에 추상적 할 수 있습니다. 그리고 우리가 개념적으로 얻을 것은 우리가 다른 측면에서 하나를 모델링 할 수 있다는 것입니다. 원칙적으로 적어도, 우리는 객체 지향 추상화의 형태로 파라미터의 모든 종류를 표현할 수 있습니다. 그래서 의미에서 당신은 스칼라가 더 직교하고 완전한 언어입니다 말할 수 있습니다.

    무엇 특히, 추상적 인 유형을 구입하는 것은 우리가 지금까지 배웠던이 공분산 문제에 대한 좋은 치료입니다. 오랜 시간 동안 주변되었습니다 하나의 표준 문제는, 동물과 식품의 문제이다. 퍼즐은 음식을 먹는 방법, 식사와 클래스 동물을 가지고 있었다. 문제는 우리가 동물을 서브 클래스 및 암소와 같은 클래스가 있다면, 그들은 단지 잔디가 아닌 임의의 음식을 먹는 것입니다. 암소는 예를 들면, 생선을 먹을 수 없었다. 당신이 원하는 것은 암소는 잔디가 아닌 다른 일을 잡아 먹는 먹는 방법을 가지고 말할 수있을 것입니다. 당신이 나에 대해 이전 이야기 애플 변수에 과일을 할당하는 문제와 같은 불건전 한 상황을 만들 수 있습니다 밝혀 때문에 사실, 당신은 자바에서 그렇게 할 수 없습니다.

    대답은 당신이 동물 클래스에 추상 유형을 추가한다는 것입니다. 당신은 나의 새로운 동물 클래스는 모르겠어요 SuitableFood의 유형이, 말한다. 그래서 추상적 인 유형이다. 당신은 유형의 구현을 제공하지 않습니다. 그럼 당신은 단지 SuitableFood를 잡아 먹는 먹는 방법이있다. 그리고 암소 클래스에서 내가 말할 것이다, OK, I 클래스 동물을 확장하는 암소를 가지고 있고, 암소 형 SuitableFood에 대한 잔디와 같습니다. 그래서 추상적 인 유형은 그때 내가 아는 뭔가 서브 클래스에서 나중에 기입 내가 모르는 슈퍼 클래스의 유형의 개념을 제공합니다.

    실제로 수행 할 수 있습니다. 당신은 먹는 음식의 종류와 수준의 동물을 매개 변수화 할 수 있습니다. 그러나 당신이 많은 다른 것들을 할 때 실제로, 그것은 매개 변수의 폭발로 연결, 일반적으로, 어떤 매개 변수의 경계에서, 더. 1998 년 ECOOP에서, 김 브루스, 필 Wadler, 나는 우리는 당신이 당신이 모르는 것들의 수를 증가로, 일반적인 프로그램 차적으로 성장할 것으로 보여 논문을했다. 그래서 아주 좋은 이유는 매개 변수를해야하지만, 그들은 당신이 차 타격 위로를 제공하지 않기 때문에, 이러한 추상적 인 회원이하지 있습니다.

    thatismatt는 의견 요청 :

    나는 관계가 추상적 유형 또는 제네릭을 사용 사이의 차이가 없습니다 확신합니다. 어떤 다른 것은 :

    마틴이가 "폭발 매개 변수의, 일반적으로, 어떤 매개 변수의 경계에서, 더"오고, 추상 형식이 제네릭을 사용하여 모델링하는 경우 그 이후 차적으로 성장, 당신은 종이 "확장 가능한 구성 요소 추상화를 고려할 수있는 경우에 대해 말하는 것을 이해하기 "(2007 년 완료) 프로젝트 Palcom의 출판물에서 참조 OOPSLA 2005에 대한로 ... 마틴 오더 스키, 마티아스 Zenger 작성.

    관련 추출물

    (참고 : 가족 다형성은 재사용 아직 입력 안전한 상호 재귀 클래스를 지원하는 솔루션으로 객체 지향 언어에 대한 제안되었다. 가족 다형성의 핵심 아이디어는) 그룹 상호 재귀 클래스에 사용되는 가족의 개념이다

    abstract class MaxCell extends AbsCell {
    type T <: Ordered { type O = T }
    def setMax(x: T) = if (get < x) set(x)
    }
    

    (피터 캐닝, 윌리엄 쿡, 월터 힐, 월터 Olthoff 종이에서 참고 : 경계 부량은 주어진 유형의 모든 아형에 걸쳐 균일하게 작동 기능을 입력하는 수단으로서 Cardelli과 베 그너 도입 하였다. 그들은 단순한 "개체"모델을 정의하고 "속성"의 지정된 세트를 가진 모든 객체에 대한 이해가 기능 검사 유형에 경계 정량을 사용했다. 객체 지향 언어의보다 현실적인 표현이 반복적으로 정의 유형의 요소 객체를 허용합니다. 이러한 맥락에서, 경계 정량화는 더 이상 의도 된 목적을 제공하지 않습니다. 이 방법의 지정된 세트를 가진 모든 오브젝트에 의미가 기능을 쉽게 찾을 수 있지만, 어떤이 Cardelli - 웨 그너 시스템에 입력 할 수 없습니다. 객체 지향 언어에서 입력 다형성 기능에 대한 기초를 제공하기 위해, 우리는) ​​F-경계 정량화를 소개합니다

    프로그래밍 언어의 추상화의 두 가지 주요 형태가있다 :

    두 번째 형태는 일반적으로 객체 지향 언어를 사용하는 반면, 첫 번째 형태는, 기능적인 언어 전형적이다.

    전통적으로, 자바는 작업 값 파라미터 및 구성원 추상화를 지원합니다. 제네릭과의 최근 자바 5.0은 종류도 파라미터를 지원합니다.

    스칼라에서 제네릭을 포함한 인수는 두 가지이다 :

    경계 다형성을 가진 시스템에서 제네릭으로 추상 형식을 재 작성하는 형 경계의 차 확장을 수반 할 수 있습니다.

    스칼라에서 제네릭 형식 매개 변수 대 추상 형식의 회원 (빌 베너 스)

    (강조 광산)

    예:

    // Type parameter version
    class MySuite extends FixtureSuite3[StringBuilder, ListBuffer, Stack] with MyHandyFixture {
      // ...
    }
    
    // Type member version
    class MySuite extends FixtureSuite3 with MyHandyFixture {
      // ...
    }
    
    // Type parameter version
    class MySuite extends FixtureSuite[StringBuilder] with StringBuilderFixture {
      // ...
    }
    
    // Type member version
    class MySuite extends FixtureSuite with StringBuilderFixture {
      type FixtureParam = StringBuilder
      // ...
    }
    
  2. ==============================

    2.내가 스칼라에 대한 책을 읽은 때 나는 같은 질문을했다.

    내가 스칼라에 대한 책을 읽은 때 나는 같은 질문을했다.

    제네릭을 사용하는 장점은 유형의 가족을 만드는 것입니다. 아무도 버퍼 - 그들은 단지 버퍼 [모든] 버퍼 [문자열] 등을 사용할 수있는 서브 클래 싱 할 필요가 없습니다

    당신은 추상 형식을 사용하는 경우, 사람들은 서브 클래스를 작성하도록 강요 될 것이다. 사람들은 등 AnyBuffer, StringBuffer와 같은 클래스가 필요합니다

    당신은 당신의 특정한 필요를위한 더 나은 결정해야합니다.

  3. ==============================

    3.사용자 정의 템플릿을 설정하는 형식 매개 변수와 함께 추상적 인 유형을 사용할 수 있습니다.

    사용자 정의 템플릿을 설정하는 형식 매개 변수와 함께 추상적 인 유형을 사용할 수 있습니다.

    이제 세 연결된 특성과 패턴을 설정해야 가정 해 봅시다 :

    trait AA[B,C]
    trait BB[C,A]
    trait CC[A,B]
    

    인수 유형 매개 변수에 언급 된 방법으로 AA, BB, CC 정중하게 그 자체입니다

    당신은 코드의 일종으로 올 수 있습니다 :

    trait AA[B<:BB[C,AA[B,C]],C<:CC[AA[B,C],B]]
    trait BB[C<:CC[A,BB[C,A]],A<:AA[BB[C,A],C]]
    trait CC[A<:AA[B,CC[A,B]],B<:BB[CC[A,B],A]]
    

    어떤 때문에 형식 매개 변수 채권의 간단한 방법으로 작동하지 않을 것입니다. 당신은 제대로 상속 공변하게 할 필요가

    trait AA[+B<:BB[C,AA[B,C]],+C<:CC[AA[B,C],B]]
    trait BB[+C<:CC[A,BB[C,A]],+A<:AA[BB[C,A],C]]
    trait CC[+A<:AA[B,CC[A,B]],+B<:BB[CC[A,B],A]]
    

    이 하나 개의 샘플 컴파일 것이다 그러나 분산 규칙에 강력한 요구 사항을 설정하고 어떤 경우에 사용할 수 없습니다

    trait AA[+B<:BB[C,AA[B,C]],+C<:CC[AA[B,C],B]] {
      def forth(x:B):C
      def back(x:C):B
    }
    trait BB[+C<:CC[A,BB[C,A]],+A<:AA[BB[C,A],C]] {
      def forth(x:C):A
      def back(x:A):C
    }
    trait CC[+A<:AA[B,CC[A,B]],+B<:BB[CC[A,B],A]] {
      def forth(x:A):B
      def back(x:B):A
    }
    

    컴파일러는 분산 검사 오류의 무리와 함께 반대합니다

    이 경우는 추가 특성의 모든 종류의 요구 사항을 수집 할 수 있으며 그 위에 다른 특성을 변수화

    //one trait to rule them all
    trait OO[O <: OO[O]] { this : O =>
      type A <: AA[O]
      type B <: BB[O]
      type C <: CC[O]
    }
    trait AA[O <: OO[O]] { this : O#A =>
      type A = O#A
      type B = O#B
      type C = O#C
      def left(l:B):C
      def right(r:C):B = r.left(this)
      def join(l:B, r:C):A
      def double(l:B, r:C):A = this.join( l.join(r,this), r.join(this,l) )
    }
    trait BB[O <: OO[O]] { this : O#B =>
      type A = O#A
      type B = O#B
      type C = O#C
      def left(l:C):A
      def right(r:A):C = r.left(this)
      def join(l:C, r:A):B
      def double(l:C, r:A):B = this.join( l.join(r,this), r.join(this,l) )
    }
    trait CC[O <: OO[O]] { this : O#C =>
      type A = O#A
      type B = O#B
      type C = O#C
      def left(l:A):B
      def right(r:B):A = r.left(this)
      def join(l:A, r:B):C
      def double(l:A, r:B):C = this.join( l.join(r,this), r.join(this,l) )
    }
    

    이제 우리는, 설명 된 패턴에 대한 구체적인 표현을 쓰기 왼쪽 정의하고 모든 클래스의 메소드를 가입하고 제대로 무료로 두배로 할 수있다

    class ReprO extends OO[ReprO] {
      override type A = ReprA
      override type B = ReprB
      override type C = ReprC
    }
    case class ReprA(data : Int) extends AA[ReprO] {
      override def left(l:B):C = ReprC(data - l.data)
      override def join(l:B, r:C) = ReprA(l.data + r.data)
    }
    case class ReprB(data : Int) extends BB[ReprO] {
      override def left(l:C):A = ReprA(data - l.data)
      override def join(l:C, r:A):B = ReprB(l.data + r.data)
    }
    case class ReprC(data : Int) extends CC[ReprO] {
      override def left(l:A):B = ReprB(data - l.data)
      override def join(l:A, r:B):C = ReprC(l.data + r.data)
    }
    

    그래서, 추상적 인 형태와 유형 매개 변수 모두 추상화를 만드는 데 사용된다. 그들은 모두 나약하고 장점을 가지고있다. 추상 형식은 모든 유형의 구조를 설명하는 것이 더 구체적이고 할 수 있지만 장황 지정된 명시 적으로 필요합니다. 입력 매개 변수는 즉시 유형의 무리를 작성하지만, 당신에게 상속 입력 범위에 대한 자세한 걱정을 제공 할 수 있습니다.

    이들은 서로 상승 작용을 제공하고 그 중 하나를 표현할 수없는 복잡한 추상화를 만들기 위해 함께 사용될 수있다.

  4. from https://stackoverflow.com/questions/1154571/scala-abstract-types-vs-generics by cc-by-sa and MIT license