Skip to content

Instantly share code, notes, and snippets.

@hmm-umm
Forked from curry-ing/types-and-manifests.md
Created April 6, 2021 08:39
Show Gist options
  • Save hmm-umm/e1c6226fd78138c08f00100c14038e54 to your computer and use it in GitHub Desktop.
Save hmm-umm/e1c6226fd78138c08f00100c14038e54 to your computer and use it in GitHub Desktop.
[Scala] Types And Manifests

Types and Manifests

  • Scala도 다른 JVM언어와 마찬가지로 런타임에 타입을 소거

    • 컴파일시에는 가능한 타입 정보에 대한 접근이 런타임에는 불가능
  • Scala.reflect.Manifest, TypeTags: 컴파일타임에 접근 가능한 타입 정보를 런타임에 전달

    • TypeTag[T]는 컴파일 타임의 타입T의 런타임 타입 표현을 캡슐화.
    • TypeTag는, 2.10 이하 버전에서 사용되었던, 더 많은 기능을 내포한 Manifest의 대안이며, Scala reflection에 통합됨

세 가지 타입의 TypeTags

  1. scala.reflect.api.TypeTags#TypeTag

    • 스칼라 타입의 완전한 타입 서술자
    • e.g. TypeTag[List[String]]scala.List[String]의 모든 타입 정보를 담고 있다
  2. scala.reflect.ClassTag

    • 스칼라 타입의 부분적인 타입 서술자
    • e.g. ClassTag[List[String]]은 소거되는 타입의 타입 정보만 담는다.
      • 여기서는 scala.collection.immutable.List
    • ClassTag는 타입의 런타임 클래스에만 접근을 허용
    • scala.reflect.ClassManifest와 유사함
  3. scala.reflect.api.TypeTags#WeakTypeTag

    • 추상 타입을 위한 타입 서술자

Obtaining a TypeTag

Manifest와 마찬가지로, TypeTag도 컴파일러에 의해 생성되며 세 가지 방법으로 얻을 수 있다

via the Methods, typeTag, classTag or weakTypeTag

  • Universe를 통해 사용가능한 typeTag 메서드를 사용하면, 특정 타입에 대한 TypeTag를 직접 획득 가능

Examples

Int를 표현하는 TypeTag를 얻는 예제
import scala.reflect.runtime.universe._
val tt = typeTag[Int]
String을 담는 TypeTag
import scala.reflect._
val ct = classTag[String]
  • 위 두 메서드(typeTag, classTag)는 각각 주어진 타입 아규먼트 T에 대하여 TypeTag[T]ClassTag[T]를 생성한다

TypeTag[T], ClassTag[T] 혹은 WeakTypeTag[T]의 Implicit Parameter를 사용

  • 컴파일러가 TypeTag를 생성하도록 요청할 수 있음
    • 이는 TypeTag[T] 타입에 implicit 을 표기하는 것으로 수행 가능
      • 컴파일러가 일치하는 타입의 implicit value를 찾지 못한다면 TypeTag[T]를 자동으로 생성한다
    • Note: 일반적으로 메서드나 클래스에 implicit parameter를 사용하여 수행

Examples

  • 임의의 object를 받아서 그 obj의 정보를 출혁하는 메서드를 TypeTag를 사용하여 작성하는 예제.
import scala.reflect.runtime.universe._

def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = {
  val targs = tag.tpe match {
    case TypeRef(_, _, args) => args
  }
  println(s"type of $x has type arguments $targs")
}
  • T라는 타입 매개변수를 받는 제네릭 메서드 paramInfo
  • implicit parameter인 (implicit tag: typeTag[T]) 적용
  • 그 후, TypeTagtpe메서드를 사용하여 tag가 나타내는 타입에 직접 접근 가능

Type Parameter의 Context bound 사용

  • 좀 덜 복잡한 방법
def myMethod[T: TypeTag] = ???

Examples

import scala.reflect.runtime.universe._

def paramInfo[T: TypeTag](x: T): Unit = {
  val targs = tag.tpe match {
    case TypeRef(_, _, args) => args
  }
  println(s"type of $x has type arguments $targs")
}
  • 주어진 context bound [T: TypeTag]를 통해
  • 컴파일러는 TypeTag[T]에 대한 implicit parameter를 생성 후
  • 윗 단락의 implicit parameter를 넘기는것과 같이 메서드를 수정

WeakTypeTags

  • WeakTypeTag[T]TypeTag[T]를 보편화한 것
  • 일반적인 TypeTag과 달리, 타입 표현을 위한 구성요소는, 타입 매개변수 혹은 추상 타입에 대한 참조일 수 있음
  • 하지만, WeakTypeTag[T]는 가능한 한 강건해지려고 노력함
    • i.e. 참조된 타입 매개변수나 추상 타입에 대해 type tag가 사용 가능할 때,
    • WeakTypeTag[T]에 구체적인 유형을 포함시킨다

Examples

def weakParamInfo[T](x: T)(implicit tag: WeakTypeTag[T]): Unit = {
  val targs = tag.tpe match {
    case TypeRef(_, _, args) => args
  }
  println(s"type of $x has type arguments $targs")
}
scala> def foo[T] = weakParamInfo(List[T]())
foo: [T]=> Unit

scala> foo[Int]
type of List() has type arguments List(T)

TypeTags and Manifests

  • TypeTag는 2.10 이하의 scala.reflect.Manifest 개념에 느슨하게 부합한다
  • scala.reflect.ClassTagscala.reflect.ClassManifest에 해당
  • scala.reflect.api.TypeTags#TypeTagscala.reflect.Manifest에 대부분 일치
  • 기타 2.10 이전 버전의 Manifest 타입은 2.10의 Tag에 직접적으로 구현된 구현체는 없음

Deprecations

  • scala.reflect.OptManifest는 더 이상 지원되지 않음

    • Tag가 임의의 타입도 구체화(reify) 할 수 있기 때문
  • scala.reflect.AnyValManifest와 같은 일을 하는것도 없다

    • 대신, 자신의 태그를 기본태그(동반 객체에 정의된)중 하나와 비교하여 그것이 primitive value 클래스인지 여부를 알 수 있음
    • 또한, <tag>.tpe.typeSymbol.isprimitiveValueClass를 통해 간단히 알 수 있음
  • Manifest의 동반 객체에 정의된 factory method들의 대체자도 없음

    • 대신, Java(for classes)나 Scala(for tyeps)에서 제공하는 reflection API를 통해 해당 유형을 생성 가능
  • <:<>:>같은 Manifest 관련 특정 연산자도 지원되지 않음

    • Java, Scala의 reflection API를 사용
  • Scala 2.10에서 scala.reflect.ClassManifest는 deprecate 됨

  • scala.reflect.Manifest대신 TypeTagClassTag를 사용 권장하며 향후 릴리즈에서 deprecate 예정

  • Manifest-based API를 Tag를 사용하도록 변경 권장


위 글은 Scala Documentation의 글을 일부 편집하여 한글로 정리한 것임

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment