Specialization with `Complex`

13 views
Skip to first unread message

Kevin Meredith

unread,
Apr 21, 2015, 11:22:25 AM4/21/15
to spire...@googlegroups.com
Looking at Complex.scala:

    final case class Complex[@spec(Float, Double) T](real: T, imag: T)
  
What's the meaning of the `T` with respect to `@spec(Float, Double)`?

In particular, I don't understand the signature here. But, that's not surprising since I've never used specialization.

Thanks

Erik Osheim

unread,
Apr 21, 2015, 11:31:50 AM4/21/15
to spire...@googlegroups.com
Hi Kevin,

If you google for specialization in Scala you'll find a number of
pages that explain it in detail.

The basic idea is that the part you are talking about is just an
annotation on T -- it should behave more of less the same as code
without that annotation. The difference is that specialization will
create variants of this class to handle the different primitive
types, to avoid boxing.

In Java (and so on the JVM), there is a distinction between "double"
(a primitive type), and "java.lang.Double" (a boxed type). The
primitive types are stack allocated, are not garbage-collected, and
can be operated on (e.g. added) directly. The boxed values are
allocated and freed by GC, and wrap an actual "double" value.

In Scala "Double" is a separate concept that encompasses both "double"
and "java.lang.Double". In the context of Scala generics, "Double"
usually means "java.lang.Double" but specialization is a way to create
a code path specific to "double" to avoid this boxing.

Hopefully this gives you enough context to learn more about the
feature. It is somewhat mysterious, buggy, and complicated, but right
now it's a very necessary part of getting the performance we need out
of Spire's type classes.

-- Erik

On Tue, Apr 21, 2015 at 08:22:24AM -0700, Kevin Meredith wrote:
> Looking at Complex.scala
> <https://github.com/non/spire/blob/master/core/src/main/scala/spire/math/Complex.scala#L91>
> :

Kevin Meredith

unread,
Apr 21, 2015, 12:34:51 PM4/21/15
to spire...@googlegroups.com, er...@plastic-idolatry.com
Thank you, Erik, for that helpful summary.


Reaching a point of confusion on whether the parameterized type must be a primitive, I posted this SO question - .http://stackoverflow.com/questions/29777981/understanding-specialized-with-non-primitives

However, I'm confused that the following works:

scala>import spire.math.Complex

scala>scala> case class Foo(x: String)
defined class Foo

scala> Complex[Foo](Foo("5"), Foo("1234"))
res6: spire.math.Complex[Foo] = (Foo(5) + Foo(1234)i)

er...@plastic-idolatry.com

unread,
Apr 21, 2015, 12:46:46 PM4/21/15
to Kevin Meredith, spire...@googlegroups.com
On Tue, Apr 21, 2015 at 09:34:51AM -0700, Kevin Meredith wrote:
> Reaching a point of confusion on whether the parameterized type *must* be a
Any type can be substituted for a specialized type parameter.

The specialization just affects the underlying behavior when a
primitive is used. For non-primitives, the code should behave exactly
as if that annotation was absent.

> However, I'm confused that the following works:
>
> scala>import spire.math.Complex
>
> scala>scala> case class Foo(x: String)
> defined class Foo
>
> scala> Complex[Foo](Foo("5"), Foo("1234"))
> res6: spire.math.Complex[Foo] = (Foo(5) + Foo(1234)i)

Currently you can create Complex[A] values for any type A, since
dependence on things like Field[A] are on the operations, rather than
the data type. This allows us to use Complex to represent Gaussian
integers or interesting values.

-- Erik
Reply all
Reply to author
Forward
0 new messages