Почему так мало вещей @specialized в стандартной библиотеке Scala?

Я искал использование @specialized в исходном коде стандартной библиотеки Scala 2.8.1. Похоже, что только несколько черт и классов используют эту аннотацию: Function0, Function1, Function2, Tuple1, Tuple2, Product1, Product2, AbstractFunction0, AbstractFunction1, AbstractFunction2.

Ни один из классов коллекции не является @specialized. Почему нет? Будет ли это генерировать слишком много классов?

Это означает, что использование классов коллекции с примитивными типами очень неэффективно, потому что будет много ненужного бокса и распаковки.

Каков наиболее эффективный способ иметь неизменный список или последовательность (с IndexedSeq характеристиками) Int s, избегая бокса и распаковки?

Ответ 1

Специализация имеет высокую стоимость по размеру классов, поэтому ее необходимо добавить с тщательным рассмотрением. В конкретном случае коллекций я полагаю, что воздействие будет огромным.

Тем не менее, это постоянное усилие - библиотека Scala едва ли начала специализироваться.

Ответ 2

Специализированный может быть дорогим (экспоненциальным) как по размеру классов, так и по времени компиляции. Это говорит не только размер, как принятый ответ.

Откройте свой scala REPL и введите это.

import scala.{specialized => sp}
trait S1[@sp A, @sp B, @sp C, @sp D] { def f(p1:A): Unit }

Извините:-). Это похоже на компиляторную бомбу.

Теперь давайте рассмотрим простой признак

trait Foo[Int]{ }

Приведенное выше приведет к созданию двух скомпилированных классов. Foo, чистый интерфейс и Foo $1, реализация класса.

Теперь

trait Foo[@specialized A] { }

Специальный параметр шаблона здесь расширяется/перезаписывается для 9 различных примитивных типов (void, boolean, byte, char, int, long, short, double, float). Итак, в основном вы получаете 20 классов вместо 2.

Возвращаясь к признаку с 5 специализированными параметрами шаблона, классы генерируются для каждой комбинации возможных примитивных типов. т.е. его экспоненциальность по сложности.

2 * 10 ^ (нет специализированных параметров)

Если вы определяете класс для определенного примитивного типа, вы должны быть более явным в нем, например

trait Foo[@specialized(Int) A, @specialized(Int,Double) B] { }

Понятно, что нужно быть экономным, используя специализированные при создании библиотек общего назначения.

Здесь рассказывает Пол Филлипс.

Ответ 3

Частичный ответ на мой собственный вопрос: я могу обернуть массив в IndexedSeq следующим образом:

import scala.collection.immutable.IndexedSeq

def arrayToIndexedSeq[@specialized(Int) T](array: Array[T]): IndexedSeq[T] = new IndexedSeq[T] {
  def apply(idx: Int): T = array(idx)
  def length: Int = array.length
}

(Конечно, вы все равно можете изменить содержимое, если у вас есть доступ к базовому массиву, но я бы удостоверился, что массив не передан в другие части моей программы).