- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Scala generics where T is any of (Int,Long,Float,Double)
Wed, 2010-01-06, 23:00
Hi guys, I have a tricky type question for you :)
I would like to convert the following class to use generic types:
class Metrics { var min:Double = _ var max:Double = _ var mean:Double = _ var stddev:Double = _ var total:Double = _ var count:Double = 0 def register(value:Double):Double = { min = Math.min(min, value) min } }
so that it would look like this:
class Metrics[T] { var min:T = _ var max:T = _ var mean:T = _ var stddev:T = _ var total:T = _ var count:T = 0 def register(value:T):T = { min = Math.min(min, value) min } }
however, this doesn't work:
12: error: overloaded method value min with alternatives (x: Double,y: Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long <and> (x: Int,y: Int)Int cannot be applied to (T,T) min = Math.min(min, value)
What would be the-right-way-to-do-it ?
Thanks !
-- Sébastien
I would like to convert the following class to use generic types:
class Metrics { var min:Double = _ var max:Double = _ var mean:Double = _ var stddev:Double = _ var total:Double = _ var count:Double = 0 def register(value:Double):Double = { min = Math.min(min, value) min } }
so that it would look like this:
class Metrics[T] { var min:T = _ var max:T = _ var mean:T = _ var stddev:T = _ var total:T = _ var count:T = 0 def register(value:T):T = { min = Math.min(min, value) min } }
however, this doesn't work:
12: error: overloaded method value min with alternatives (x: Double,y: Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long <and> (x: Int,y: Int)Int cannot be applied to (T,T) min = Math.min(min, value)
What would be the-right-way-to-do-it ?
Thanks !
-- Sébastien
Wed, 2010-01-06, 23:17
#2
Re: Scala generics where T is any of (Int,Long,Float,Double)
If you're using 2.8, try:
class Metrics[T:Numeric] {
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _
var count:T = 0
def register(value:T):T = {
min = Math.min(min, value)
min
}
}
Outside of 2.8, you're out of luck.
Wed, 2010-01-06, 23:27
#3
Re: Scala generics where T is any of (Int,Long,Float,Double)
Hi Daniel,
I'm on 2.8 -- I kind of hoped Scala type system was on par with OCaml ;)
-- Sébastien
Le 6 janvier 2010 17:10, Daniel Sobral <dcsobral@gmail.com> a écrit :
I'm on 2.8 -- I kind of hoped Scala type system was on par with OCaml ;)
-- Sébastien
Le 6 janvier 2010 17:10, Daniel Sobral <dcsobral@gmail.com> a écrit :
Which Scala version? On Scala 2.7, you won't get very far...
2010/1/6 Sébastien Pierre <sebastien@type-z.org>
Hi guys, I have a tricky type question for you :)
I would like to convert the following class to use generic types:
class Metrics { var min:Double = _ var max:Double = _ var mean:Double = _ var stddev:Double = _ var total:Double = _ var count:Double = 0 def register(value:Double):Double = { min = Math.min(min, value) min } }
so that it would look like this:
class Metrics[T] { var min:T = _ var max:T = _ var mean:T = _ var stddev:T = _ var total:T = _ var count:T = 0 def register(value:T):T = { min = Math.min(min, value) min } }
however, this doesn't work:
12: error: overloaded method value min with alternatives (x: Double,y: Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long <and> (x: Int,y: Int)Int cannot be applied to (T,T) min = Math.min(min, value)
What would be the-right-way-to-do-it ?
Thanks !
-- Sébastien
--
Daniel C. Sobral
I travel to the future all the time.
Wed, 2010-01-06, 23:37
#4
Re: Scala generics where T is any of (Int,Long,Float,Double)
err copy and paste failure:
class Metrics[T:Numeric] {
private val numerics = implicitly[Numeric[T]];
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _
var count:T = numerics.zero;
def register(value:T):T = {
min = numerics.min(value,min);
min
}
}
2010/1/6 David Hall :
> If you're using 2.8, try:
>
> class Metrics[T:Numeric] {
> var min:T = _
> var max:T = _
> var mean:T = _
> var stddev:T = _
> var total:T = _
> var count:T = 0
> def register(value:T):T = {
> min = Math.min(min, value)
> min
> }
>
> }
>
> Outside of 2.8, you're out of luck.
>
Wed, 2010-01-06, 23:57
#5
Re: Scala generics where T is any of (Int,Long,Float,Double)
Thanks !
And just for the sake of example, would it be possible to express that instead of Numeric, we want a "either type Int, either type Long, either type Float, either type Double" (something like "T <=> Int|Long|Float|Double") ?
-- Sébastien
Le 6 janvier 2010 17:15, David Hall <dlwh@cs.berkeley.edu> a écrit :
And just for the sake of example, would it be possible to express that instead of Numeric, we want a "either type Int, either type Long, either type Float, either type Double" (something like "T <=> Int|Long|Float|Double") ?
-- Sébastien
Le 6 janvier 2010 17:15, David Hall <dlwh@cs.berkeley.edu> a écrit :
err copy and paste failure:
class Metrics[T:Numeric] {
private val numerics = implicitly[Numeric[T]];
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _
var count:T = numerics.zero;
def register(value:T):T = {
min = numerics.min(value,min);
min
}
}
2010/1/6 David Hall <dlwh@cs.berkeley.edu>:
> If you're using 2.8, try:
>
> class Metrics[T:Numeric] {
> var min:T = _
> var max:T = _
> var mean:T = _
> var stddev:T = _
> var total:T = _
> var count:T = 0
> def register(value:T):T = {
> min = Math.min(min, value)
> min
> }
>
> }
>
> Outside of 2.8, you're out of luck.
>
> -- David
>
> 2010/1/6 Sébastien Pierre <sebastien@type-z.org>:
>> Hi guys, I have a tricky type question for you :)
>> I would like to convert the following class to use generic types:
>> class Metrics {
>> var min:Double = _
>> var max:Double = _
>> var mean:Double = _
>> var stddev:Double = _
>> var total:Double = _
>> var count:Double = 0
>> def register(value:Double):Double = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> so that it would look like this:
>> class Metrics[T] {
>> var min:T = _
>> var max:T = _
>> var mean:T = _
>> var stddev:T = _
>> var total:T = _
>> var count:T = 0
>> def register(value:T):T = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> however, this doesn't work:
>> 12: error: overloaded method value min with alternatives (x: Double,y:
>> Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long
>> <and> (x: Int,y: Int)Int cannot be applied to (T,T)
>> min = Math.min(min, value)
>> What would be the-right-way-to-do-it ?
>> Thanks !
>> -- Sébastien
>>
>>
>>
>>
>
Thu, 2010-01-07, 00:07
#6
Re: Scala generics where T is any of (Int,Long,Float,Double)
On Wed, Jan 06, 2010 at 02:14:51PM -0800, David Hall said
> Outside of 2.8, you're out of luck.
Not entirely. You can do almost the same thing, you just have to create
your operations object manually. This should work on 2.7.x:
trait Numeric[T] {
def min(a: T, b: T): T
}
implicit object DoubleNumerics extends Numeric[Double] {
def min(a: Double, b: Double) = Math.min(a,b)
}
class Metrics[T](implicit num: Num[T]) {
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _
var count:Int = 0
def register(value:T):T = {
min = num.min(min,value)
min
}
}
Thu, 2010-01-07, 00:17
#7
Re: Scala generics where T is any of (Int,Long,Float,Double)
Sébastien Pierre wrote:
> Hi guys, I have a tricky type question for you :)
>
> I would like to convert the following class to use generic types:
>
> class Metrics {
> var min:Double = _
> var max:Double = _
> var mean:Double = _
> var stddev:Double = _
> var total:Double = _
> var count:Double = 0
> def register(value:Double):Double = {
> min = Math.min(min, value)
> min
> }
> }
>
> so that it would look like this:
>
> class Metrics[T] {
> var min:T = _
> var max:T = _
> var mean:T = _
> var stddev:T = _
> var total:T = _
> var count:T = 0
> def register(value:T):T = {
> min = Math.min(min, value)
> min
> }
> }
>
> however, this doesn't work:
>
> 12: error: overloaded method value min with alternatives (x: Double,y:
> Double)Double (x: Float,y: Float)Float (x: Long,y: Long)Long
> (x: Int,y: Int)Int cannot be applied to (T,T)
> min = Math.min(min, value)
>
> What would be the-right-way-to-do-it ?
>
> Thanks !
>
Thu, 2010-01-07, 00:27
#8
Re: Scala generics where T is any of (Int,Long,Float,Double)
You could add another implicit.
abstract class MyTypes[T]
implicit object MTInt extends MyTypes[Int]
implicit object MTLong extends MyTypes[Long]
implicit object MTFloat extends MyTypes[Float]
implicit object MTDouble extends MyTypes[Double]
then
class metrics[T](implicit num: Numeric[T], implicit mt: metrics.MyTypes[T]) {
import num._
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _ var count:T = zero def register(value:T):T = { min = num.min(min, value)
min
}
} If you want to ensure no one can add another MyTypes, then make it sealed. 2010/1/6 Sébastien Pierre <sebastien@type-z.org>
--
Daniel C. Sobral
I travel to the future all the time.
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _ var count:T = zero def register(value:T):T = { min = num.min(min, value)
min
}
} If you want to ensure no one can add another MyTypes, then make it sealed. 2010/1/6 Sébastien Pierre <sebastien@type-z.org>
Thanks !
And just for the sake of example, would it be possible to express that instead of Numeric, we want a "either type Int, either type Long, either type Float, either type Double" (something like "T <=> Int|Long|Float|Double") ?
-- Sébastien
Le 6 janvier 2010 17:15, David Hall <dlwh@cs.berkeley.edu> a écrit :
err copy and paste failure:
class Metrics[T:Numeric] {
private val numerics = implicitly[Numeric[T]];
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _
var count:T = numerics.zero;
def register(value:T):T = {
min = numerics.min(value,min);
min
}
}
2010/1/6 David Hall <dlwh@cs.berkeley.edu>:
> If you're using 2.8, try:
>
> class Metrics[T:Numeric] {
> var min:T = _
> var max:T = _
> var mean:T = _
> var stddev:T = _
> var total:T = _
> var count:T = 0
> def register(value:T):T = {
> min = Math.min(min, value)
> min
> }
>
> }
>
> Outside of 2.8, you're out of luck.
>
> -- David
>
> 2010/1/6 Sébastien Pierre <sebastien@type-z.org>:
>> Hi guys, I have a tricky type question for you :)
>> I would like to convert the following class to use generic types:
>> class Metrics {
>> var min:Double = _
>> var max:Double = _
>> var mean:Double = _
>> var stddev:Double = _
>> var total:Double = _
>> var count:Double = 0
>> def register(value:Double):Double = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> so that it would look like this:
>> class Metrics[T] {
>> var min:T = _
>> var max:T = _
>> var mean:T = _
>> var stddev:T = _
>> var total:T = _
>> var count:T = 0
>> def register(value:T):T = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> however, this doesn't work:
>> 12: error: overloaded method value min with alternatives (x: Double,y:
>> Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long
>> <and> (x: Int,y: Int)Int cannot be applied to (T,T)
>> min = Math.min(min, value)
>> What would be the-right-way-to-do-it ?
>> Thanks !
>> -- Sébastien
>>
>>
>>
>>
>
--
Daniel C. Sobral
I travel to the future all the time.
Thu, 2010-01-07, 00:37
#9
Re: Scala generics where T is any of (Int,Long,Float,Double)
Thanks,
This is elegant... but the Metric.register method will do more computation (like update min, max, mean, count and total) plus it is used by a heavy-duty web service (~2000 requests/second, all the time) where the copy-not-update may give too much job to the GC ;)
This is a nice Scala exercise :)
-- Sébastien
Le 6 janvier 2010 18:08, Tony Morris <tonymorris@gmail.com> a écrit :
This is elegant... but the Metric.register method will do more computation (like update min, max, mean, count and total) plus it is used by a heavy-duty web service (~2000 requests/second, all the time) where the copy-not-update may give too much job to the GC ;)
This is a nice Scala exercise :)
-- Sébastien
Le 6 janvier 2010 18:08, Tony Morris <tonymorris@gmail.com> a écrit :
Sébastien Pierre wrote:
> Hi guys, I have a tricky type question for you :)
>
> I would like to convert the following class to use generic types:
>
> class Metrics {
> var min:Double = _
> var max:Double = _
> var mean:Double = _
> var stddev:Double = _
> var total:Double = _
> var count:Double = 0
> def register(value:Double):Double = {
> min = Math.min(min, value)
> min
> }
> }
>
> so that it would look like this:
>
> class Metrics[T] {
> var min:T = _
> var max:T = _
> var mean:T = _
> var stddev:T = _
> var total:T = _
> var count:T = 0
> def register(value:T):T = {
> min = Math.min(min, value)
> min
> }
> }
>
> however, this doesn't work:
>
> 12: error: overloaded method value min with alternatives (x: Double,y:
> Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long
> <and> (x: Int,y: Int)Int cannot be applied to (T,T)
> min = Math.min(min, value)
>
> What would be the-right-way-to-do-it ?
>
> Thanks !
>
> -- Sébastien
>
>
Still not absolutely correct, but much closer.
sealed trait Ordering
case object LT extends Ordering
case object EQ extends Ordering
case object GT extends Ordering
trait Order[-A] {
def compare(a1: A, a2: A): Ordering
}
// Do not put type bounds (implicits) on functors.
// They belong on methods/functions.
class Metrics[T](min: T /* others */) {
// Do not use var except for extremely extreme circumstances.
def register(value:T)(implicit o: Order[T]):T =
if(o.compare(value, min) == LT) value
else min
}
--
Tony Morris
http://tmorris.net/
Thu, 2010-01-07, 00:47
#10
Re: Scala generics where T is any of (Int,Long,Float,Double)
Sébastien Pierre wrote:
> Thanks,
>
> This is elegant... but the Metric.register method will do more computation
> (like update min, max, mean, count and total) plus it is used by a
> heavy-duty web service (~2000 requests/second, all the time) where the
> copy-not-update may give too much job to the GC ;)
>
> This is a nice Scala exercise :)
>
Thu, 2010-01-07, 01:27
#11
Re: Scala generics where T is any of (Int,Long,Float,Double)
2010/1/7 Tony Morris :
> Sébastien Pierre wrote:
>> Thanks,
>>
>> This is elegant... but the Metric.register method will do more computation
>> (like update min, max, mean, count and total) plus it is used by a
>> heavy-duty web service (~2000 requests/second, all the time) where the
>> copy-not-update may give too much job to the GC ;)
>>
>> This is a nice Scala exercise :)
>>
>> -- Sébastien
>>
>> Le 6 janvier 2010 18:08, Tony Morris a écrit :
>>
>>
>>> Sébastien Pierre wrote:
>>>
>>>> Hi guys, I have a tricky type question for you :)
>>>>
>>>> I would like to convert the following class to use generic types:
>>>>
>>>> class Metrics {
>>>> var min:Double = _
>>>> var max:Double = _
>>>> var mean:Double = _
>>>> var stddev:Double = _
>>>> var total:Double = _
>>>> var count:Double = 0
>>>> def register(value:Double):Double = {
>>>> min = Math.min(min, value)
>>>> min
>>>> }
>>>> }
>>>>
>>>> so that it would look like this:
>>>>
>>>> class Metrics[T] {
>>>> var min:T = _
>>>> var max:T = _
>>>> var mean:T = _
>>>> var stddev:T = _
>>>> var total:T = _
>>>> var count:T = 0
>>>> def register(value:T):T = {
>>>> min = Math.min(min, value)
>>>> min
>>>> }
>>>> }
>>>>
>>>> however, this doesn't work:
>>>>
>>>> 12: error: overloaded method value min with alternatives (x: Double,y:
>>>> Double)Double (x: Float,y: Float)Float (x: Long,y: Long)Long
>>>> (x: Int,y: Int)Int cannot be applied to (T,T)
>>>> min = Math.min(min, value)
>>>>
>>>> What would be the-right-way-to-do-it ?
>>>>
>>>> Thanks !
>>>>
>>>> -- Sébastien
>>>>
>>>>
>>>>
>>> Still not absolutely correct, but much closer.
>>>
>>> sealed trait Ordering
>>> case object LT extends Ordering
>>> case object EQ extends Ordering
>>> case object GT extends Ordering
>>>
>>> trait Order[-A] {
>>> def compare(a1: A, a2: A): Ordering
>>> }
>>>
>>> // Do not put type bounds (implicits) on functors.
>>> // They belong on methods/functions.
>>> class Metrics[T](min: T /* others */) {
>>> // Do not use var except for extremely extreme circumstances.
>>>
>>> def register(value:T)(implicit o: Order[T]):T =
>>> if(o.compare(value, min) == LT) value
>>> else min
>>> }
>>>
>>>
>>> --
>>> Tony Morris
>>> http://tmorris.net/
>>>
>>>
>>>
>>>
>>
>>
> You may implement your new functions accordingly. Do you need help?
>
> I require evidence before accepting that "the copy-not-update is too
> much work for the GC" supposition is validated and advanced to a hypothesis.
Heh. You might be surprized to learn that supposition and hypothesis
are mere synonyms :)
"sup-" = "sub-" = "hypo-" = below, under
"-position" = "-thesis"
Hypothesis is the Greek word for supposition. Also, for example,
dissertations usually start by stating an (unproved yet) hypothesis,
which is then to be validated and defended as a thesis.
Dimitris
>
> --
> Tony Morris
> http://tmorris.net/
>
>
>
Thu, 2010-01-07, 10:17
#12
Re: Scala generics where T is any of (Int,Long,Float,Double)
(Slightly off-topic)
Sébastien,
I know that you are doing an exercise in scala, not in numerics. Nevertheless I want to mention that your class Metrics does not ask for generalization, at least nor over all numeric types.
The members min, max and count are w/o problems, but already the running total has quite different properties in lets say double and Int: A naive computation has no loss of accuracy when T=Int but might suffer overflow (depending on the scaling of the values) while the opposite holds if T=Double. The integer overflow can be healed by accumulating the running total as a BigInt (or a Long) while for a Double you shall use a BigDecimal and still consider rounding.
It gets worse for the [intermediate terms of] a variance calculation: the square of an Int (or the product of two Ints) is a sleeping bug in a general purpose code since e.g. 65536*65536 evaluates to zero. (Apply your class to price statistics in cents). A Long would help for T=Int but for T=Long it would fail (more rarely). And so on.
You have two possibilities to react in a class design: Ignore it and use mostly-working-and-sometimes-not formulae and leave it to the user to care for the numerics – beware 700 dollars. She, the user, has to consider the implementation of the abstraction. Uhh. Or you as implementer can dive into the numerics, formulate the numerical guaranties and dispatch to a proper set of implementation, e.g. one for Long-values which captures Short, Int and Long and one for Double-values which covers Double and Float. The trait Numeric then has no role anymore, except to provide a constraint for the type parameter T. Ironically, a good and fast compromise might be to use doubles all over plus some sound formulae and accept but guarantee the error bounds.
A nice example for a class design as well.
All this is well known but all too often ignored, maybe because generalization is so beautiful.
Even more off-topic: All this would be easier if integer overflow would raise an exception. At least it would trigger much more attention to the innocent looking integer product.
Sincerely yours,Burkhard
2010/1/6 Sébastien Pierre <sebastien@type-z.org>
Sébastien,
I know that you are doing an exercise in scala, not in numerics. Nevertheless I want to mention that your class Metrics does not ask for generalization, at least nor over all numeric types.
The members min, max and count are w/o problems, but already the running total has quite different properties in lets say double and Int: A naive computation has no loss of accuracy when T=Int but might suffer overflow (depending on the scaling of the values) while the opposite holds if T=Double. The integer overflow can be healed by accumulating the running total as a BigInt (or a Long) while for a Double you shall use a BigDecimal and still consider rounding.
It gets worse for the [intermediate terms of] a variance calculation: the square of an Int (or the product of two Ints) is a sleeping bug in a general purpose code since e.g. 65536*65536 evaluates to zero. (Apply your class to price statistics in cents). A Long would help for T=Int but for T=Long it would fail (more rarely). And so on.
You have two possibilities to react in a class design: Ignore it and use mostly-working-and-sometimes-not formulae and leave it to the user to care for the numerics – beware 700 dollars. She, the user, has to consider the implementation of the abstraction. Uhh. Or you as implementer can dive into the numerics, formulate the numerical guaranties and dispatch to a proper set of implementation, e.g. one for Long-values which captures Short, Int and Long and one for Double-values which covers Double and Float. The trait Numeric then has no role anymore, except to provide a constraint for the type parameter T. Ironically, a good and fast compromise might be to use doubles all over plus some sound formulae and accept but guarantee the error bounds.
A nice example for a class design as well.
All this is well known but all too often ignored, maybe because generalization is so beautiful.
Even more off-topic: All this would be easier if integer overflow would raise an exception. At least it would trigger much more attention to the innocent looking integer product.
Sincerely yours,Burkhard
2010/1/6 Sébastien Pierre <sebastien@type-z.org>
Thanks !
And just for the sake of example, would it be possible to express that instead of Numeric, we want a "either type Int, either type Long, either type Float, either type Double" (something like "T <=> Int|Long|Float|Double") ?
-- Sébastien
Le 6 janvier 2010 17:15, David Hall <dlwh@cs.berkeley.edu> a écrit :err copy and paste failure:
class Metrics[T:Numeric] {
private val numerics = implicitly[Numeric[T]];
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _
var count:T = numerics.zero;
def register(value:T):T = {
min = numerics.min(value,min);
min
}
}
2010/1/6 David Hall <dlwh@cs.berkeley.edu>:
> If you're using 2.8, try:
>
> class Metrics[T:Numeric] {
> var min:T = _
> var max:T = _
> var mean:T = _
> var stddev:T = _
> var total:T = _
> var count:T = 0
> def register(value:T):T = {
> min = Math.min(min, value)
> min
> }
>
> }
>
> Outside of 2.8, you're out of luck.
>
> -- David
>
> 2010/1/6 Sébastien Pierre <sebastien@type-z.org>:
>> Hi guys, I have a tricky type question for you :)
>> I would like to convert the following class to use generic types:
>> class Metrics {
>> var min:Double = _
>> var max:Double = _
>> var mean:Double = _
>> var stddev:Double = _
>> var total:Double = _
>> var count:Double = 0
>> def register(value:Double):Double = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> so that it would look like this:
>> class Metrics[T] {
>> var min:T = _
>> var max:T = _
>> var mean:T = _
>> var stddev:T = _
>> var total:T = _
>> var count:T = 0
>> def register(value:T):T = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> however, this doesn't work:
>> 12: error: overloaded method value min with alternatives (x: Double,y:
>> Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long
>> <and> (x: Int,y: Int)Int cannot be applied to (T,T)
>> min = Math.min(min, value)
>> What would be the-right-way-to-do-it ?
>> Thanks !
>> -- Sébastien
>>
>>
>>
>>
>
Thu, 2010-01-07, 14:37
#13
Re: Scala generics where T is any of (Int,Long,Float,Double)
Hi Tony,
Thanks for the help, but I should be OK with the feedback I got :) I will do some benchmarks of the purely-function vs mutable Metrics implementation and share the results :)
-- Sébastien
Le 6 janvier 2010 18:42, Tony Morris <tonymorris@gmail.com> a écrit :
Thanks for the help, but I should be OK with the feedback I got :) I will do some benchmarks of the purely-function vs mutable Metrics implementation and share the results :)
-- Sébastien
Le 6 janvier 2010 18:42, Tony Morris <tonymorris@gmail.com> a écrit :
You may implement your new functions accordingly. Do you need help?
I require evidence before accepting that "the copy-not-update is too
much work for the GC" supposition is validated and advanced to a hypothesis.
--
Tony Morris
http://tmorris.net/
Thu, 2010-01-07, 14:47
#14
Re: Scala generics where T is any of (Int,Long,Float,Double)
Hi Burkhard,
Very true, the actual implementation I use is based on Double so I should be relatively safe -- if I were to do precise arithmetics I would use BigNum, but for this Metrics class, performance is key :)
Anyway, I learned a lot about scala types, thanks everyone !
-- Sébastien
Le 7 janvier 2010 04:16, Burkhard Ludwig <ludwig.burkhard@googlemail.com> a écrit :
Very true, the actual implementation I use is based on Double so I should be relatively safe -- if I were to do precise arithmetics I would use BigNum, but for this Metrics class, performance is key :)
Anyway, I learned a lot about scala types, thanks everyone !
-- Sébastien
Le 7 janvier 2010 04:16, Burkhard Ludwig <ludwig.burkhard@googlemail.com> a écrit :
(Slightly off-topic)
Sébastien,
I know that you are doing an exercise in scala, not in numerics. Nevertheless I want to mention that your class Metrics does not ask for generalization, at least nor over all numeric types.
The members min, max and count are w/o problems, but already the running total has quite different properties in lets say double and Int: A naive computation has no loss of accuracy when T=Int but might suffer overflow (depending on the scaling of the values) while the opposite holds if T=Double. The integer overflow can be healed by accumulating the running total as a BigInt (or a Long) while for a Double you shall use a BigDecimal and still consider rounding.
It gets worse for the [intermediate terms of] a variance calculation: the square of an Int (or the product of two Ints) is a sleeping bug in a general purpose code since e.g. 65536*65536 evaluates to zero. (Apply your class to price statistics in cents). A Long would help for T=Int but for T=Long it would fail (more rarely). And so on.
You have two possibilities to react in a class design: Ignore it and use mostly-working-and-sometimes-not formulae and leave it to the user to care for the numerics – beware 700 dollars. She, the user, has to consider the implementation of the abstraction. Uhh. Or you as implementer can dive into the numerics, formulate the numerical guaranties and dispatch to a proper set of implementation, e.g. one for Long-values which captures Short, Int and Long and one for Double-values which covers Double and Float. The trait Numeric then has no role anymore, except to provide a constraint for the type parameter T. Ironically, a good and fast compromise might be to use doubles all over plus some sound formulae and accept but guarantee the error bounds.
A nice example for a class design as well.
All this is well known but all too often ignored, maybe because generalization is so beautiful.
Even more off-topic: All this would be easier if integer overflow would raise an exception. At least it would trigger much more attention to the innocent looking integer product.
Sincerely yours,Burkhard
2010/1/6 Sébastien Pierre <sebastien@type-z.org>Thanks !
And just for the sake of example, would it be possible to express that instead of Numeric, we want a "either type Int, either type Long, either type Float, either type Double" (something like "T <=> Int|Long|Float|Double") ?
-- Sébastien
Le 6 janvier 2010 17:15, David Hall <dlwh@cs.berkeley.edu> a écrit :err copy and paste failure:
class Metrics[T:Numeric] {
private val numerics = implicitly[Numeric[T]];
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _
var count:T = numerics.zero;
def register(value:T):T = {
min = numerics.min(value,min);
min
}
}
2010/1/6 David Hall <dlwh@cs.berkeley.edu>:
> If you're using 2.8, try:
>
> class Metrics[T:Numeric] {
> var min:T = _
> var max:T = _
> var mean:T = _
> var stddev:T = _
> var total:T = _
> var count:T = 0
> def register(value:T):T = {
> min = Math.min(min, value)
> min
> }
>
> }
>
> Outside of 2.8, you're out of luck.
>
> -- David
>
> 2010/1/6 Sébastien Pierre <sebastien@type-z.org>:
>> Hi guys, I have a tricky type question for you :)
>> I would like to convert the following class to use generic types:
>> class Metrics {
>> var min:Double = _
>> var max:Double = _
>> var mean:Double = _
>> var stddev:Double = _
>> var total:Double = _
>> var count:Double = 0
>> def register(value:Double):Double = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> so that it would look like this:
>> class Metrics[T] {
>> var min:T = _
>> var max:T = _
>> var mean:T = _
>> var stddev:T = _
>> var total:T = _
>> var count:T = 0
>> def register(value:T):T = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> however, this doesn't work:
>> 12: error: overloaded method value min with alternatives (x: Double,y:
>> Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long
>> <and> (x: Int,y: Int)Int cannot be applied to (T,T)
>> min = Math.min(min, value)
>> What would be the-right-way-to-do-it ?
>> Thanks !
>> -- Sébastien
>>
>>
>>
>>
>
Thu, 2010-01-07, 16:37
#15
Re: Scala generics where T is any of (Int,Long,Float,Double)
2010/1/6 Sébastien Pierre <sebastien@type-z.org>
I believe that eventually this should work with 2.8 by doing this:
class Metrics[@specialized[Long|Double|Int|Float] T] { ... }
I don't think it's done yet, though.
class Metrics[T] { var min:T = _ var max:T = _ var mean:T = _ var stddev:T = _ var total:T = _ var count:T = 0 def register(value:T):T = { min = Math.min(min, value) min } }
however, this doesn't work:
12: error: overloaded method value min with alternatives (x: Double,y: Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long <and> (x: Int,y: Int)Int cannot be applied to (T,T) min = Math.min(min, value)
What would be the-right-way-to-do-it ?
I believe that eventually this should work with 2.8 by doing this:
class Metrics[@specialized[Long|Double|Int|Float] T] { ... }
I don't think it's done yet, though.
Thu, 2010-01-07, 16:47
#16
Re: Scala generics where T is any of (Int,Long,Float,Double)
Hi Nils,
This is the closest to how I would ideally express it, but it does not seem to work with 2.8.0.r20326-b20091229020159:
<console>:4: error: specialized does not take type parameters class Metrics[@specialized[Long|Double|Int|Float] T]
Thanks though :)
-- Sébastien
Le 7 janvier 2010 10:31, Nils Kilden-Pedersen <nilskp@gmail.com> a écrit :
This is the closest to how I would ideally express it, but it does not seem to work with 2.8.0.r20326-b20091229020159:
<console>:4: error: specialized does not take type parameters class Metrics[@specialized[Long|Double|Int|Float] T]
Thanks though :)
-- Sébastien
Le 7 janvier 2010 10:31, Nils Kilden-Pedersen <nilskp@gmail.com> a écrit :
2010/1/6 Sébastien Pierre <sebastien@type-z.org>
class Metrics[T] { var min:T = _ var max:T = _ var mean:T = _ var stddev:T = _ var total:T = _ var count:T = 0 def register(value:T):T = { min = Math.min(min, value) min } }
however, this doesn't work:
12: error: overloaded method value min with alternatives (x: Double,y: Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long <and> (x: Int,y: Int)Int cannot be applied to (T,T) min = Math.min(min, value)
What would be the-right-way-to-do-it ?
I believe that eventually this should work with 2.8 by doing this:
class Metrics[@specialized[Long|Double|Int|Float] T] { ... }
I don't think it's done yet, though.
Thu, 2010-01-07, 16:57
#17
Re: Scala generics where T is any of (Int,Long,Float,Double)
By the way, Sébastien, if performance is a concern, then you should either forget about using type parameters or use @specialization. Because of issues with primitives and auto-boxing, performance will, otherwise, be much worse.
2010/1/7 Sébastien Pierre <sebastien@type-z.org>
--
Daniel C. Sobral
I travel to the future all the time.
2010/1/7 Sébastien Pierre <sebastien@type-z.org>
Hi Burkhard,
Very true, the actual implementation I use is based on Double so I should be relatively safe -- if I were to do precise arithmetics I would use BigNum, but for this Metrics class, performance is key :)
Anyway, I learned a lot about scala types, thanks everyone !
-- Sébastien
Le 7 janvier 2010 04:16, Burkhard Ludwig <ludwig.burkhard@googlemail.com> a écrit :
(Slightly off-topic)
Sébastien,
I know that you are doing an exercise in scala, not in numerics. Nevertheless I want to mention that your class Metrics does not ask for generalization, at least nor over all numeric types.
The members min, max and count are w/o problems, but already the running total has quite different properties in lets say double and Int: A naive computation has no loss of accuracy when T=Int but might suffer overflow (depending on the scaling of the values) while the opposite holds if T=Double. The integer overflow can be healed by accumulating the running total as a BigInt (or a Long) while for a Double you shall use a BigDecimal and still consider rounding.
It gets worse for the [intermediate terms of] a variance calculation: the square of an Int (or the product of two Ints) is a sleeping bug in a general purpose code since e.g. 65536*65536 evaluates to zero. (Apply your class to price statistics in cents). A Long would help for T=Int but for T=Long it would fail (more rarely). And so on.
You have two possibilities to react in a class design: Ignore it and use mostly-working-and-sometimes-not formulae and leave it to the user to care for the numerics – beware 700 dollars. She, the user, has to consider the implementation of the abstraction. Uhh. Or you as implementer can dive into the numerics, formulate the numerical guaranties and dispatch to a proper set of implementation, e.g. one for Long-values which captures Short, Int and Long and one for Double-values which covers Double and Float. The trait Numeric then has no role anymore, except to provide a constraint for the type parameter T. Ironically, a good and fast compromise might be to use doubles all over plus some sound formulae and accept but guarantee the error bounds.
A nice example for a class design as well.
All this is well known but all too often ignored, maybe because generalization is so beautiful.
Even more off-topic: All this would be easier if integer overflow would raise an exception. At least it would trigger much more attention to the innocent looking integer product.
Sincerely yours,Burkhard
2010/1/6 Sébastien Pierre <sebastien@type-z.org>Thanks !
And just for the sake of example, would it be possible to express that instead of Numeric, we want a "either type Int, either type Long, either type Float, either type Double" (something like "T <=> Int|Long|Float|Double") ?
-- Sébastien
Le 6 janvier 2010 17:15, David Hall <dlwh@cs.berkeley.edu> a écrit :err copy and paste failure:
class Metrics[T:Numeric] {
private val numerics = implicitly[Numeric[T]];
var min:T = _
var max:T = _
var mean:T = _
var stddev:T = _
var total:T = _
var count:T = numerics.zero;
def register(value:T):T = {
min = numerics.min(value,min);
min
}
}
2010/1/6 David Hall <dlwh@cs.berkeley.edu>:
> If you're using 2.8, try:
>
> class Metrics[T:Numeric] {
> var min:T = _
> var max:T = _
> var mean:T = _
> var stddev:T = _
> var total:T = _
> var count:T = 0
> def register(value:T):T = {
> min = Math.min(min, value)
> min
> }
>
> }
>
> Outside of 2.8, you're out of luck.
>
> -- David
>
> 2010/1/6 Sébastien Pierre <sebastien@type-z.org>:
>> Hi guys, I have a tricky type question for you :)
>> I would like to convert the following class to use generic types:
>> class Metrics {
>> var min:Double = _
>> var max:Double = _
>> var mean:Double = _
>> var stddev:Double = _
>> var total:Double = _
>> var count:Double = 0
>> def register(value:Double):Double = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> so that it would look like this:
>> class Metrics[T] {
>> var min:T = _
>> var max:T = _
>> var mean:T = _
>> var stddev:T = _
>> var total:T = _
>> var count:T = 0
>> def register(value:T):T = {
>> min = Math.min(min, value)
>> min
>> }
>> }
>> however, this doesn't work:
>> 12: error: overloaded method value min with alternatives (x: Double,y:
>> Double)Double <and> (x: Float,y: Float)Float <and> (x: Long,y: Long)Long
>> <and> (x: Int,y: Int)Int cannot be applied to (T,T)
>> min = Math.min(min, value)
>> What would be the-right-way-to-do-it ?
>> Thanks !
>> -- Sébastien
>>
>>
>>
>>
>
--
Daniel C. Sobral
I travel to the future all the time.
Thu, 2010-01-07, 16:57
#18
Re: Scala generics where T is any of (Int,Long,Float,Double)
2010/1/7 Sébastien Pierre <sebastien@type-z.org>
Should be on its way
http://article.gmane.org/gmane.comp.lang.scala.internals/1953
Hi Nils,
This is the closest to how I would ideally express it, but it does not seem to work with 2.8.0.r20326-b20091229020159:
<console>:4: error: specialized does not take type parameters class Metrics[@specialized[Long|Double|Int|Float] T]
Should be on its way
http://article.gmane.org/gmane.comp.lang.scala.internals/1953
Thu, 2010-01-07, 17:07
#19
Re: Scala generics where T is any of (Int,Long,Float,Double)
OK, thanks !
BTW, what is @specialization ?
-- Sébastien
Le 7 janvier 2010 10:40, Daniel Sobral <dcsobral@gmail.com> a écrit :
BTW, what is @specialization ?
-- Sébastien
Le 7 janvier 2010 10:40, Daniel Sobral <dcsobral@gmail.com> a écrit :
By the way, Sébastien, if performance is a concern, then you should either forget about using type parameters or use @specialization. Because of issues with primitives and auto-boxing, performance will, otherwise, be much worse.
Thu, 2010-01-07, 17:57
#20
Re: Scala generics where T is any of (Int,Long,Float,Double)
That should have been @specialized
Basically, it will create one copy of each method for every primitive. During execution, if you happen to be calling your class with an Int, then the Int method will be executed, instead of the parameterized one. That avoids auto-boxing.
2010/1/7 Sébastien Pierre <sebastien@type-z.org>
--
Daniel C. Sobral
I travel to the future all the time.
Basically, it will create one copy of each method for every primitive. During execution, if you happen to be calling your class with an Int, then the Int method will be executed, instead of the parameterized one. That avoids auto-boxing.
2010/1/7 Sébastien Pierre <sebastien@type-z.org>
OK, thanks !
BTW, what is @specialization ?
-- Sébastien
Le 7 janvier 2010 10:40, Daniel Sobral <dcsobral@gmail.com> a écrit :
By the way, Sébastien, if performance is a concern, then you should either forget about using type parameters or use @specialization. Because of issues with primitives and auto-boxing, performance will, otherwise, be much worse.
--
Daniel C. Sobral
I travel to the future all the time.
Thu, 2010-01-07, 19:47
#21
Re: Scala generics where T is any of (Int,Long,Float,Double)
Nils Kilden-Pedersen wrote:
>
> I believe that eventually this should work with 2.8 by doing this:
>
> class Metrics[@specialized[Long|Double|Int|Float] T] { ... }
>
> I don't think it's done yet, though.
>
I thought that this would still create a general class for all T, but
additionally create special optimized versions that are used when T == Long,
Double, Int or Float.
Thu, 2010-01-07, 19:57
#22
Re: Scala generics where T is any of (Int,Long,Float,Double)
On Thu, Jan 7, 2010 at 12:27 PM, Matthias Becker <bekkah@web.de> wrote:
You're probably right. That won't work. What we really need is something like
class Metrics[T <: Long|Double|Int|Float] { ... }
I thought that this would still create a general class for all T, but
additionally create special optimized versions that are used when T == Long,
Double, Int or Float.
You're probably right. That won't work. What we really need is something like
class Metrics[T <: Long|Double|Int|Float] { ... }
2010/1/6 Sébastien Pierre <sebastien@type-z.org>
--
Daniel C. Sobral
I travel to the future all the time.