Last active
October 18, 2016 03:10
-
-
Save jeremyrsmith/17bc2b1bd937d65c113d659c47c7c65f to your computer and use it in GitHub Desktop.
Shapeless typeclass with erasure trick
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import shapeless._ | |
trait TestTypeclassRecursive[T] { | |
def doFoo(t: T): String | |
} | |
object TestTypeclassRecursive { | |
implicit val hnil: TestTypeclassRecursive[HNil] = new TestTypeclassRecursive[HNil] { | |
def doFoo(t: HNil): String = "HNil" | |
} | |
implicit def hcons[H, T <: HList](implicit tailTC: TestTypeclassRecursive[T]) = new TestTypeclassRecursive[H :: T] { | |
def doFoo(t: H :: T) = t.head.toString + tailTC.doFoo(t.tail) | |
} | |
} | |
trait TestTypeclassErasure[T] { | |
def doFoo(t: T): String | |
} | |
object TestTypeclassErasure { | |
// can't use @tailrec here due to changing type arguments; oh well | |
def anyTR[T <: HList](l: T, current: String): String = { | |
l match { | |
case h :: t => anyTR(t, current + h.toString) | |
case HNil => current + "HNil" | |
} | |
} | |
object All extends TestTypeclassErasure[HList] { | |
def doFoo(t: HList) = anyTR(t, "") | |
} | |
implicit def all[T <: HList] = All.asInstanceOf[TestTypeclassErasure[T]] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import shapeless._ | |
// import shapeless._ | |
type Example = Int :: String :: Boolean :: Double :: HNil | |
// defined type alias Example | |
val recursive = implicitly[TestTypeclassRecursive[Example]] | |
// recursive: TestTypeclassRecursive[Example] = TestTypeclassRecursive$$anon$2@6c4fc9ed | |
:javap recursive | |
// Size 1541 bytes | |
// MD5 checksum de536c0dc29de13f7cbae7d2c7ba89e6 | |
// Compiled from "<console>" | |
// public class | |
// minor version: 0 | |
// major version: 50 | |
// flags: ACC_PUBLIC, ACC_SUPER | |
// Constant pool: | |
// #1 = Utf8 | |
// #2 = Class #1 // | |
// #3 = Utf8 java/lang/Object | |
// #4 = Class #3 // java/lang/Object | |
// #5 = Utf8 <console> | |
// #6 = Utf8 MODULE$ | |
// #7 = Utf8 L; | |
// #8 = Utf8 <clinit> | |
// #9 = Utf8 ()V | |
// #10 = Utf8 <init> | |
// #11 = NameAndType #10:#9 // "<init>":()V | |
// #12 = Methodref #2.#11 // ."<init>":()V | |
// #13 = Utf8 recursive | |
// #14 = Utf8 LTestTypeclassRecursive; | |
// #15 = Utf8 LTestTypeclassRecursive<Lshapeless/$colon$colon<Ljava/lang/Object; | |
// Lshapeless/$colon$colon<Ljava/lang/String;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/HNil;>;>;>;>;>; | |
// #16 = Utf8 ()LTestTypeclassRecursive; | |
// #17 = NameAndType #13:#14 // recursive:LTestTypeclassRecursive; | |
// #18 = Fieldref #2.#17 // .recursive:LTestTypeclassRecursive; | |
// #19 = Utf8 this | |
// #20 = Methodref #4.#11 // java/lang/Object."<init>":()V | |
// #21 = NameAndType #6:#7 // MODULE$:L; | |
// #22 = Fieldref #2.#21 // .MODULE$:L; | |
// #23 = Utf8 scala/Predef$ | |
// #24 = Class #23 // scala/Predef$ | |
// #25 = Utf8 Lscala/Predef$; | |
// #26 = NameAndType #6:#25 // MODULE$:Lscala/Predef$; | |
// #27 = Fieldref #24.#26 // scala/Predef$.MODULE$:Lscala/Predef$; | |
// #28 = Utf8 TestTypeclassRecursive$ | |
// #29 = Class #28 // TestTypeclassRecursive$ | |
// #30 = Utf8 LTestTypeclassRecursive$; | |
// #31 = NameAndType #6:#30 // MODULE$:LTestTypeclassRecursive$; | |
// #32 = Fieldref #29.#31 // TestTypeclassRecursive$.MODULE$:LTestTypeclassRecursive$; | |
// #33 = Utf8 hnil | |
// #34 = NameAndType #33:#16 // hnil:()LTestTypeclassRecursive; | |
// #35 = Methodref #29.#34 // TestTypeclassRecursive$.hnil:()LTestTypeclassRecursive; | |
// #36 = Utf8 hcons | |
// #37 = Utf8 (LTestTypeclassRecursive;)LTestTypeclassRecursive; | |
// #38 = NameAndType #36:#37 // hcons:(LTestTypeclassRecursive;)LTestTypeclassRecursive; | |
// #39 = Methodref #29.#38 // TestTypeclassRecursive$.hcons:(LTestTypeclassRecursive;) | |
// LTestTypeclassRecursive; | |
// #40 = Utf8 implicitly | |
// #41 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object; | |
// #42 = NameAndType #40:#41 // implicitly:(Ljava/lang/Object;)Ljava/lang/Object; | |
// #43 = Methodref #24.#42 // scala/Predef$.implicitly:(Ljava/lang/Object;)Ljava/lang/Object; | |
// #44 = Utf8 TestTypeclassRecursive | |
// #45 = Class #44 // TestTypeclassRecursive | |
// #46 = Utf8 | |
// #47 = Class #46 // | |
// #48 = Utf8 $line5/$read | |
// #49 = Class #48 // $line5/$read | |
// #50 = Utf8 | |
// #51 = Utf8 | |
// #52 = Class #51 // | |
// #53 = Utf8 | |
// #54 = Class #53 // | |
// #55 = Utf8 Signature | |
// #56 = Utf8 Code | |
// #57 = Utf8 LocalVariableTable | |
// #58 = Utf8 LineNumberTable | |
// #59 = Utf8 ()LTestTypeclassRecursive<Lshapeless/$colon$colon<Ljava/lang/Object; | |
// Lshapeless/$colon$colon<Ljava/lang/String;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/HNil;>;>;>;>;>; | |
// #60 = Utf8 SourceFile | |
// #61 = Utf8 InnerClasses | |
// #62 = Utf8 ScalaInlineInfo | |
// #63 = Utf8 Scala | |
// { | |
// public static final MODULE$; | |
// descriptor: L; | |
// flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL | |
// | |
// public static {}; | |
// descriptor: ()V | |
// flags: ACC_PUBLIC, ACC_STATIC | |
// Code: | |
// stack=1, locals=0, args_size=0 | |
// 0: new #2 // class | |
// 3: invokespecial #12 // Method "<init>":()V | |
// 6: return | |
// | |
// public TestTypeclassRecursive<shapeless.$colon$colon<java.lang.Object, shapeless.$colon$colon<java.lang.String, | |
// shapeless.$colon$colon<java.lang.Object, shapeless.$colon$colon<java.lang.Object, shapeless.HNil>>>>> recursive(); | |
// descriptor: ()LTestTypeclassRecursive; | |
// flags: ACC_PUBLIC | |
// Code: | |
// stack=1, locals=1, args_size=1 | |
// 0: aload_0 | |
// 1: getfield #18 // Field recursive:LTestTypeclassRecursive; | |
// 4: areturn | |
// LocalVariableTable: | |
// Start Length Slot Name Signature | |
// 0 5 0 this L; | |
// LineNumberTable: | |
// line 15: 0 | |
// Signature: #59 // () | |
// LTestTypeclassRecursive<Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/String;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/HNil;>;>;>;>;>; | |
// | |
// public (); | |
// descriptor: ()V | |
// flags: ACC_PUBLIC | |
// Code: | |
// stack=7, locals=1, args_size=1 | |
// 0: aload_0 | |
// 1: invokespecial #20 // Method java/lang/Object."<init>":()V | |
// 4: aload_0 | |
// 5: putstatic #22 // Field MODULE$:L; | |
// 8: aload_0 | |
// 9: getstatic #27 // Field scala/Predef$.MODULE$:Lscala/Predef$; | |
// 12: getstatic #32 // Field TestTypeclassRecursive$.MODULE$:LTestTypeclassRecursive$; | |
// 15: getstatic #32 // Field TestTypeclassRecursive$.MODULE$:LTestTypeclassRecursive$; | |
// 18: getstatic #32 // Field TestTypeclassRecursive$.MODULE$:LTestTypeclassRecursive$; | |
// 21: getstatic #32 // Field TestTypeclassRecursive$.MODULE$:LTestTypeclassRecursive$; | |
// 24: getstatic #32 // Field TestTypeclassRecursive$.MODULE$:LTestTypeclassRecursive$; | |
// 27: invokevirtual #35 // Method TestTypeclassRecursive$.hnil:()LTestTypeclassRecursive; | |
// 30: invokevirtual #39 // Method TestTypeclassRecursive$.hcons:(LTestTypeclassRecursive;) | |
// LTestTypeclassRecursive; | |
// 33: invokevirtual #39 // Method TestTypeclassRecursive$.hcons:(LTestTypeclassRecursive;) | |
// LTestTypeclassRecursive; | |
// 36: invokevirtual #39 // Method TestTypeclassRecursive$.hcons:(LTestTypeclassRecursive;) | |
// LTestTypeclassRecursive; | |
// 39: invokevirtual #39 // Method TestTypeclassRecursive$.hcons:(LTestTypeclassRecursive;) | |
// LTestTypeclassRecursive; | |
// 42: invokevirtual #43 // Method scala/Predef$.implicitly:(Ljava/lang/Object;) | |
// Ljava/lang/Object; | |
// 45: checkcast #45 // class TestTypeclassRecursive | |
// 48: putfield #18 // Field recursive:LTestTypeclassRecursive; | |
// 51: return | |
// LocalVariableTable: | |
// Start Length Slot Name Signature | |
// 0 52 0 this L; | |
// LineNumberTable: | |
// line 19: 0 | |
// line 15: 8 | |
// } | |
// SourceFile: "<console>" | |
// InnerClasses: | |
// public static #50= #47 of #49; //=class of class $line5/$read | |
// public static #50= #52 of #47; //=class of class | |
// public static #50= #54 of #52; //=class of class | |
// public static #50= #2 of #54; //=class of class | |
// Error: unknown attribute | |
// ScalaInlineInfo: length = 0xE | |
// 01 01 00 02 00 0A 00 09 01 00 0D 00 10 01 | |
// Error: unknown attribute | |
// Scala: length = 0x0 | |
// | |
val erasure = implicitly[TestTypeclassErasure[Example]] | |
// erasure: TestTypeclassErasure[Example] = TestTypeclassErasure$All$@7fbe31fb | |
:javap erasure | |
// Size 1429 bytes | |
// MD5 checksum d448e1c20f6171f763757f59b1ceece3 | |
// Compiled from "<console>" | |
//public class | |
// minor version: 0 | |
// major version: 50 | |
// flags: ACC_PUBLIC, ACC_SUPER | |
//Constant pool: | |
// #1 = Utf8 | |
// #2 = Class #1 // | |
// #3 = Utf8 java/lang/Object | |
// #4 = Class #3 // java/lang/Object | |
// #5 = Utf8 <console> | |
// #6 = Utf8 MODULE$ | |
// #7 = Utf8 L; | |
// #8 = Utf8 <clinit> | |
// #9 = Utf8 ()V | |
// #10 = Utf8 <init> | |
// #11 = NameAndType #10:#9 // "<init>":()V | |
// #12 = Methodref #2.#11 // ."<init>":()V | |
// #13 = Utf8 erasure | |
// #14 = Utf8 LTestTypeclassErasure; | |
// #15 = Utf8 LTestTypeclassErasure<Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/String;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/HNil;>;>;>;>;>; | |
// #16 = Utf8 ()LTestTypeclassErasure; | |
// #17 = NameAndType #13:#14 // erasure:LTestTypeclassErasure; | |
// #18 = Fieldref #2.#17 // .erasure:LTestTypeclassErasure; | |
// #19 = Utf8 this | |
// #20 = Methodref #4.#11 // java/lang/Object."<init>":()V | |
// #21 = NameAndType #6:#7 // MODULE$:L; | |
// #22 = Fieldref #2.#21 // .MODULE$:L; | |
// #23 = Utf8 scala/Predef$ | |
// #24 = Class #23 // scala/Predef$ | |
// #25 = Utf8 Lscala/Predef$; | |
// #26 = NameAndType #6:#25 // MODULE$:Lscala/Predef$; | |
// #27 = Fieldref #24.#26 // scala/Predef$.MODULE$:Lscala/Predef$; | |
// #28 = Utf8 TestTypeclassErasure$ | |
// #29 = Class #28 // TestTypeclassErasure$ | |
// #30 = Utf8 LTestTypeclassErasure$; | |
// #31 = NameAndType #6:#30 // MODULE$:LTestTypeclassErasure$; | |
// #32 = Fieldref #29.#31 // TestTypeclassErasure$.MODULE$:LTestTypeclassErasure$; | |
// #33 = Utf8 all | |
// #34 = NameAndType #33:#16 // all:()LTestTypeclassErasure; | |
// #35 = Methodref #29.#34 // TestTypeclassErasure$.all:()LTestTypeclassErasure; | |
// #36 = Utf8 implicitly | |
// #37 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object; | |
// #38 = NameAndType #36:#37 // implicitly:(Ljava/lang/Object;)Ljava/lang/Object; | |
// #39 = Methodref #24.#38 // scala/Predef$.implicitly:(Ljava/lang/Object;)Ljava/lang/Object; | |
// #40 = Utf8 TestTypeclassErasure | |
// #41 = Class #40 // TestTypeclassErasure | |
// #42 = Utf8 | |
// #43 = Class #42 // | |
// #44 = Utf8 $line6/$read | |
// #45 = Class #44 // $line6/$read | |
// #46 = Utf8 | |
// #47 = Utf8 | |
// #48 = Class #47 // | |
// #49 = Utf8 | |
// #50 = Class #49 // | |
// #51 = Utf8 Signature | |
// #52 = Utf8 Code | |
// #53 = Utf8 LocalVariableTable | |
// #54 = Utf8 LineNumberTable | |
// #55 = Utf8 ()LTestTypeclassErasure<Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/String;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/HNil;>;>;>;>;>; | |
// #56 = Utf8 SourceFile | |
// #57 = Utf8 InnerClasses | |
// #58 = Utf8 ScalaInlineInfo | |
// #59 = Utf8 Scala | |
//{ | |
// public static final MODULE$; | |
// descriptor: L; | |
// flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL | |
// | |
// public static {}; | |
// descriptor: ()V | |
// flags: ACC_PUBLIC, ACC_STATIC | |
// Code: | |
// stack=1, locals=0, args_size=0 | |
// 0: new #2 // class | |
// 3: invokespecial #12 // Method "<init>":()V | |
// 6: return | |
// | |
// public TestTypeclassErasure<shapeless.$colon$colon<java.lang.Object, shapeless.$colon$colon<java.lang.String, shapeless.$colon$colon<java.lang.Object, shapeless.$colon$colon<java.lang.Object, shapeless.HNil>>>>> erasure(); | |
// descriptor: ()LTestTypeclassErasure; | |
// flags: ACC_PUBLIC | |
// Code: | |
// stack=1, locals=1, args_size=1 | |
// 0: aload_0 | |
// 1: getfield #18 // Field erasure:LTestTypeclassErasure; | |
// 4: areturn | |
// LocalVariableTable: | |
// Start Length Slot Name Signature | |
// 0 5 0 this L; | |
// LineNumberTable: | |
// line 15: 0 | |
// Signature: #55 // ()LTestTypeclassErasure<Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/String;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/$colon$colon<Ljava/lang/Object;Lshapeless/HNil;>;>;>;>;>; | |
// | |
// public (); | |
// descriptor: ()V | |
// flags: ACC_PUBLIC | |
// Code: | |
// stack=3, locals=1, args_size=1 | |
// 0: aload_0 | |
// 1: invokespecial #20 // Method java/lang/Object."<init>":()V | |
// 4: aload_0 | |
// 5: putstatic #22 // Field MODULE$:L; | |
// 8: aload_0 | |
// 9: getstatic #27 // Field scala/Predef$.MODULE$:Lscala/Predef$; | |
// 12: getstatic #32 // Field TestTypeclassErasure$.MODULE$:LTestTypeclassErasure$; | |
// 15: invokevirtual #35 // Method TestTypeclassErasure$.all:()LTestTypeclassErasure; | |
// 18: invokevirtual #39 // Method scala/Predef$.implicitly:(Ljava/lang/Object;)Ljava/lang/Object; | |
// 21: checkcast #41 // class TestTypeclassErasure | |
// 24: putfield #18 // Field erasure:LTestTypeclassErasure; | |
// 27: return | |
// LocalVariableTable: | |
// Start Length Slot Name Signature | |
// 0 28 0 this L; | |
// LineNumberTable: | |
// line 19: 0 | |
// line 15: 8 | |
//} | |
//SourceFile: "<console>" | |
//InnerClasses: | |
// public static #46= #43 of #45; //=class of class $line6/$read | |
// public static #46= #48 of #43; //=class of class | |
// public static #46= #50 of #48; //=class of class | |
// public static #46= #2 of #50; //=class of class | |
//Error: unknown attribute | |
// ScalaInlineInfo: length = 0xE | |
// 01 01 00 02 00 0A 00 09 01 00 0D 00 10 01 | |
//Error: unknown attribute | |
// Scala: length = 0x0 | |
recursive.doFoo(22 :: "Twenty Two" :: true :: 22.22 :: HNil) | |
// res0: String = 22Twenty Twotrue22.22HNil | |
erasure.doFoo(22 :: "Twenty Two" :: true :: 22.22 :: HNil) | |
// res1: String = 22Twenty Twotrue22.22HNil |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment