Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert sequence of AnyVal case class (Seq[T <: AnyVal]) to its runtime representation efficiently

Assuming I have a value case class

case class Id(i:Int) extends AnyVal

and a sequence containing this value case class

Seq(Id(1), Id(2), Id(3))

is there a way of converting those values into Int without that there is a need of iteration over the sequence (e.g. by doing Seq(Id(1), Id(2), Id(3)).map(_.i)?

The reason I ask is that I think that the nice thing about value case classes is that you can use value classes that have native types as representation during runtime and are thus extremely efficient. But not all libraries in use do support an automatic "conversions" of those classes. Thus one has to pass the native type what is no big deal when it is a simple attribute since the compiler can optimize it. But when having a sequence I have to explicitly map it, which means that there happens an unnecessary iteration over all values, because it is actually doing nothing but mapping to the same values at runtime. Is there any way to avoid that and use some optimizations of the compiler in such cases?

like image 433
Big_Foot1989 Avatar asked Jan 14 '19 17:01

Big_Foot1989


People also ask

How to generate a sequence of numbers in R using seq ()?

The seq () is a standard general with a default method to generate the sequence of numbers. To generate a sequence of numbers in R, use the seq () method. The seq () is an inbuilt R generic method that generates the regular sequences.

What is the difference between by and along in SEQ method?

The (…) parameter in the seq (…) method is arguments passed to or from methods. The from and the end is the starting point and ending point of the sequence. The by parameter is a number: It is an increment of a sequence. The along.with parameter takes from the length of this argument.

How to create a new seq with initial elements?

To create a new Seq with initial elements: val nums = Seq(1, 2, 3) case class Person(name: String) val people = Seq(Person("Emily"), Person("Hannah"), Person("Mercedes")) When you need to be clear about what’s in the seq:

What is AnyVal in Scala?

AnyVal is the root class of all value types, which describe values not implemented as objects in the underlying host system. Value classes are specified in Scala Language Specification, section 12.2. The standard implementation includes nine AnyVal subtypes:


1 Answers

As conjectured by Alexey Romanov in the comments, value classes actually box when stored in a Seq. Here's the output of javap -c for def bar = Seq(Id(1)):

  public scala.collection.Seq<Id> bar();
    Code:
       0: getstatic     #25                 // Field scala/collection/Seq$.MODULE$:Lscala/collection/Seq$;
       3: getstatic     #30                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
       6: iconst_1
       7: anewarray     #32                 // class Id
      10: dup
      11: iconst_0
      12: new           #32                 // class Id
      15: dup
      16: iconst_1
      17: invokespecial #35                 // Method Id."<init>":(I)V
      20: aastore
      21: invokevirtual #39                 // Method scala/Predef$.genericWrapArray:(Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
      24: invokevirtual #43                 // Method scala/collection/Seq$.apply:(Lscala/collection/Seq;)Lscala/collection/GenTraversable;
      27: checkcast     #45                 // class scala/collection/Seq
      30: areturn

Notice that the return type is Seq<Id> and that Id."<init>" is called at line 17. Given this, unboxing without mapping is impossible.

The solution to this boxing will be Opaque Types in Scala 3, if that proposal is accepted. I'm not sure if they will solve your problem, though.

like image 58
Brian McCutchon Avatar answered Oct 17 '22 19:10

Brian McCutchon