Skip to content

Instantly share code, notes, and snippets.

@ktoso
Last active December 10, 2015 01:38
Show Gist options
  • Save ktoso/4360893 to your computer and use it in GitHub Desktop.
Save ktoso/4360893 to your computer and use it in GitHub Desktop.
Blogpost about value classes.
class Meter(val n: Int) extends AnyVal
def traveled(m: Meter) =
s"You traveled ${m.n} meters!"
val meters = new Meter(34)
traveled(meters) should equal ("You traveled 20 meters!")
class Meter(val n: Int) extends AnyVal {
def traveled = s"You traveled ${n} meters!"
}
val meters = new Meter(34)
meters.traveled should equal ("You traveled 20 meters!")
// [meters.traveled] was compiled into:
22: invokevirtual #37; //Method Meter$.traveled$extension:(I)Ljava/lang/String;
// so it's calling a method on the companion object, which takes an [int]
// still no Meter in sight here...
// :javap -v Meter
// does Meter even exist, if I'd want to use it explicitly?
public java.lang.String traveled();
7: invokevirtual #26; //Method Meter$.traveled$extension:(I)Ljava/lang/String;
// yes it exists, and is delegating all the work to the companion object
// :javap -v Meter$ // the [companion object]!
public final java.lang.String traveled$extension(int);
// which contains the actual implementation of traveled
// notice the $extension suffix marking that it's a generated method.
implicit class AwesomeString(val s: String) {
def awesome_! = s + "! Awesome!"
}
// an [implicit final def AwesomeString(String): AwesomeString] is generated for us automatically
"Scala".awesome_!
// 3: ldc #21; //String Scala vvvvvvvvvvvvvvvvvvvvvvvvvv
// 5: invokevirtual #25; //Method AwesomeString:(Ljava/lang/String;)LTesting$AwesomeString; << returns boxed!
// 8: invokevirtual #30; //Method AwesomeString.awesome_$bang:()Ljava/lang/String;
// Called: AwesomeString.awesome_$bang:()Ljava/lang/String;
// This impl. takes the `s` from the AwesomeString's instance!
implicit class AwesomeString2(val s: String) extends AnyVal {
def awesome_! = s + "! Awesome!"
}
"Scala".awesome_!
// 18: ldc #35; //String Scala vvvvvvvvvvvvvvvvvvvvv
// 20: invokevirtual #39; //Method AwesomeString2:(Ljava/lang/String;)Ljava/lang/String; << returns not boxed!
// 23: invokevirtual #42; //Method AwesomeString2$.awesome_$bang$extension:(Ljava/lang/String;)Ljava/lang/String;
// vvvvvvvvvvvvvvvvvvv
// Called: AwesomeString2.awesome_$bang:(Ljava/lang/String;)Ljava/lang/String;
// as you can see the method gets the string passed in right away
trait AwesomeStringImplicits {
// boilerplate...
implicit def asAwesomeString(s: String) =
new AwesomeString(s)
class AwesomeString(s: String) {
def awesome_! = s + "! Awesome!"
}
}
object Main extends App
with AwesomeStringImplicits {
"Scala".awesome_!
}
// def traveled(m: Meter) was compiled as:
public java.lang.String traveled(int); // where's my Meter?!
// val meters = new Meter(34)
0: bipush 34 // ok that's the int...
2: istore_1 // that's all, no Meter in sight!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment