Skip to content

Instantly share code, notes, and snippets.

@petitviolet
Last active January 9, 2017 12:14
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 petitviolet/b67d63aad1a23350f5fa5266d077efca to your computer and use it in GitHub Desktop.
Save petitviolet/b67d63aad1a23350f5fa5266d077efca to your computer and use it in GitHub Desktop.
[Scala]constructing sequence instance byte-codes.

what is this article

Which way to construct Seq[T] instance is better?

  • Seq.apply
  • List.apply
  • :: Nil

summary

:: Nil is the fastest. Seq.apply is faster than List.apply.

compare in scala code

  • Seq.apply

    def apply[A](elems: A*): CC[A] = {
      if (elems.isEmpty) empty[A]
      else {
        val b = newBuilder[A]
        b ++= elems
        b.result()
      }
    }
  • List.apply

    override def apply[A](xs: A*): List[A] = xs.toList
    • xs.toList deligates to to[List]

      def to[Col[_]](implicit cbf: CanBuildFrom[Nothing, A, Col[A @uV]]): Col[A @uV] = {
        val b = cbf()
        b ++= seq
        b.result()
      }
  • :: Nil

    def ::[B >: A] (x: B): List[B] = new scala.collection.immutable.::(x, this)

    this is Nil.

These implementations show that :: Nil just creates new :: class instance with providing Nil as a tail and an argument to head.
Others, Seq.apply and List.apply delegate to ++= of Builder, to be accurate, Growable.
It runs pattern-match and invokes a function to add each element to a ListBuffer, therefore, it's a little slower than :: Nil.

compare in Java byte-code

These byte-code shows only :: Nil does not create NEWARRAY.

Seq.apply

// access flags 0x1
// signature ()Lscala/collection/Seq<Ljava/lang/Object;>;
// declaration: scala.collection.Seq<java.lang.Object> seq()
public seq()Lscala/collection/Seq;
@Lorg/openjdk/jmh/annotations/Benchmark;()
@Lorg/openjdk/jmh/annotations/BenchmarkMode;(value={Lorg/openjdk/jmh/annotations/Mode;.Throughput})
 L0
  LINENUMBER 27 L0
  GETSTATIC scala/collection/Seq$.MODULE$ : Lscala/collection/Seq$;
  GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
  ICONST_1
  NEWARRAY T_INT
  DUP
  ICONST_0
  ALOAD 0
  INVOKEVIRTUAL net/petitviolet/sandbox/perf/SeqOrList.NUM ()I
  IASTORE
  INVOKEVIRTUAL scala/Predef$.wrapIntArray ([I)Lscala/collection/mutable/WrappedArray;
  INVOKEVIRTUAL scala/collection/Seq$.apply (Lscala/collection/Seq;)Lscala/collection/GenTraversable;
  CHECKCAST scala/collection/Seq
  ARETURN
 L1
  LOCALVARIABLE this Lnet/petitviolet/sandbox/perf/SeqOrList; L0 L1 0
  MAXSTACK = 6
  MAXLOCALS = 1

List.apply

// access flags 0x1
// signature ()Lscala/collection/Seq<Ljava/lang/Object;>;
// declaration: scala.collection.Seq<java.lang.Object> listApply()
public listApply()Lscala/collection/Seq;
@Lorg/openjdk/jmh/annotations/Benchmark;()
@Lorg/openjdk/jmh/annotations/BenchmarkMode;(value={Lorg/openjdk/jmh/annotations/Mode;.Throughput})
 L0
  LINENUMBER 33 L0
  GETSTATIC scala/collection/immutable/List$.MODULE$ : Lscala/collection/immutable/List$;
  GETSTATIC scala/Predef$.MODULE$ : Lscala/Predef$;
  ICONST_1
  NEWARRAY T_INT
  DUP
  ICONST_0
  ALOAD 0
  INVOKEVIRTUAL net/petitviolet/sandbox/perf/SeqOrList.NUM ()I
  IASTORE
  INVOKEVIRTUAL scala/Predef$.wrapIntArray ([I)Lscala/collection/mutable/WrappedArray;
  INVOKEVIRTUAL scala/collection/immutable/List$.apply (Lscala/collection/Seq;)Lscala/collection/immutable/List;
  ARETURN
 L1
  LOCALVARIABLE this Lnet/petitviolet/sandbox/perf/SeqOrList; L0 L1 0
  MAXSTACK = 6
  MAXLOCALS = 1

:: Nil

// access flags 0x1
// signature ()Lscala/collection/Seq<Ljava/lang/Object;>;
// declaration: scala.collection.Seq<java.lang.Object> listColon()
public listColon()Lscala/collection/Seq;
@Lorg/openjdk/jmh/annotations/Benchmark;()
@Lorg/openjdk/jmh/annotations/BenchmarkMode;(value={Lorg/openjdk/jmh/annotations/Mode;.Throughput})
 L0
  LINENUMBER 39 L0
  ALOAD 0
  INVOKEVIRTUAL net/petitviolet/sandbox/perf/SeqOrList.NUM ()I
  ISTORE 1
  GETSTATIC scala/collection/immutable/Nil$.MODULE$ : Lscala/collection/immutable/Nil$;
  ILOAD 1
  INVOKESTATIC scala/runtime/BoxesRunTime.boxToInteger (I)Ljava/lang/Integer;
  INVOKEVIRTUAL scala/collection/immutable/Nil$.$colon$colon (Ljava/lang/Object;)Lscala/collection/immutable/List;
  ARETURN
 L1
  LOCALVARIABLE this Lnet/petitviolet/sandbox/perf/SeqOrList; L0 L1 0
  MAXSTACK = 2
  MAXLOCALS = 2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment