Skip to content

Instantly share code, notes, and snippets.

@jeremyrsmith
Last active October 18, 2016 03:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremyrsmith/17bc2b1bd937d65c113d659c47c7c65f to your computer and use it in GitHub Desktop.
Save jeremyrsmith/17bc2b1bd937d65c113d659c47c7c65f to your computer and use it in GitHub Desktop.
Shapeless typeclass with erasure trick
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]]
}
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