This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Array[T] in function with type parameter T

5 replies
HjP
Joined: 2012-02-07,
User offline. Last seen 32 weeks 2 days ago.

Hi,

why does the following function declaration yield an error?

def dummyfunction[T<:AnyRef](x:T) {
var dummyArray: Array[T] = Array(x)
}

(Raplacing "Array" by "List" eliminates the error.)

Thanks,
HjP

d_m
Joined: 2010-11-11,
User offline. Last seen 35 weeks 2 days ago.
Re: Array[T] in function with type parameter T

On Mon, Feb 06, 2012 at 07:07:47PM -0800, HjP wrote:
> why does the following function declaration yield an error?
>
> def dummyfunction[T<:AnyRef](x:T) {
> var dummyArray: Array[T] = Array(x)
> }

Did you Google the error you got? The "Array" type is special (since it
maps to types like Object[] and int[] on the JVM). To create a new
array with a generic type requires a Manifest.

def tryMe[T<:AnyRef:Manifest](x:T) = Array(x)

barden
Joined: 2010-03-30,
User offline. Last seen 33 weeks 5 days ago.
Help neeed: flatten nested tuples

Hi

I need to flatten nested tuples with elements of kind (1, ((2, 3), 4)) (always Tuple2!).

I got quite far using a naive binary tree:

sealed trait NT[+X <: AnyVal]
case class E[+X <: AnyVal](x: X) extends NT[X]
case class T[+X <: AnyVal](_1: NT[X], _2: NT[X]) extends NT[X]

def fltn[X <: AnyVal](nTpl: NT[X]): List[X] = nTpl match {
case T(_1, _2) => fltn(_1) ::: fltn(_2)
case E(x) => List(x)
}

implicit def toNT[X <: AnyVal](a: Any): NT[X] = a match {
case (x, y) => T(x, y)
case x: X => E(x)
}

Ignoring for a moment the warning "abstract type X in type pattern X is unchecked since it is eliminated by erasure case x: X => E(x)" (quite likely part of the problem) it is not so bad:

scala> fltn[Int]((1, ((2, 3), 4)))
res1: List[Int] = List(1, 2, 3, 4)

But it should be possible to do better:

1) fltn needs help: fltn((1, ((2, 3), 4))) gives List[Nothing], how to avoid this?

2) how to use view bounds, means fltn((1, ((2.0, 3), 4))) should give List[Double], currently without type help I get List[Nothing], but even when I do

scala> fltn[Double]((1, ((2, 3.0), 4)))
res3: List[Double] = List(1, 2, 3.0, 4)

which is as the rhs indicates crap already, because res3.head gives

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double ...

Any idea how to improve?

Thanks a lot, Volker.

milessabin
Joined: 2008-08-11,
User offline. Last seen 33 weeks 3 days ago.
Re: Help neeed: flatten nested tuples

On Wed, Feb 8, 2012 at 10:56 AM, Bardenhorst, Volker Dr.
wrote:
> Hi
>
> I need to flatten nested tuples with elements of kind (1, ((2, 3), 4)) (always Tuple2!).
>
> I got quite far using a naive binary tree:
>
> sealed trait NT[+X <: AnyVal]
> case class E[+X <: AnyVal](x: X) extends NT[X]
> case class T[+X <: AnyVal](_1: NT[X], _2: NT[X]) extends NT[X]
>
> def fltn[X <: AnyVal](nTpl: NT[X]): List[X] = nTpl match {
>  case T(_1, _2) => fltn(_1) ::: fltn(_2)
>  case E(x) => List(x)
> }
>
> implicit def toNT[X <: AnyVal](a: Any): NT[X] = a match {
>  case (x, y) => T(x, y)
>  case x: X => E(x)
> }
>
> Ignoring for a moment the warning "abstract type X in type pattern X is unchecked since it is eliminated by erasure case x: X => E(x)" (quite likely part of the problem) it is not so bad:
>
> scala> fltn[Int]((1, ((2, 3), 4)))
> res1: List[Int] = List(1, 2, 3, 4)
>
> But it should be possible to do better:
>
> 1) fltn needs help: fltn((1, ((2, 3), 4))) gives List[Nothing], how to avoid this?
>
> 2) how to use view bounds, means fltn((1, ((2.0, 3), 4))) should give List[Double], currently without type help I get List[Nothing], but even when I do
>
> scala> fltn[Double]((1, ((2, 3.0), 4)))
> res3: List[Double] = List(1, 2, 3.0, 4)
>
> which is as the rhs indicates crap already, because res3.head gives
>
> java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double ...
>
> Any idea how to improve?
>
> Thanks a lot, Volker.

That's a fantastic non-trival example for shapeless ... thanks! :-)

I've just pushed a solution here,

http://goo.gl/TqYGr

and will incorporate some of the infrastructure into the main library
later. From a usage point of view the code looks exactly how you want
it to (although from an implementation point of view there's a lot of
heavy lifting going on in the background),

val t1 = (1, ((2, 3), 4))
val f1 = flatten(t1) // Inferred type is Int :: Int :: Int :: Int :: HNil
val l1 = f1.toList // Inferred type is List[Int]

val t2 = (1, ((2, 3.0), 4))
val f2 = flatten(t2) // Inferred type is Int :: Int :: Double ::
Int :: HNil
val ds = f2 map toDouble // Inferred type is Double :: Double ::
Double :: Double :: HNil
val l2 = ds.toList // Inferred type is List[Double]

Note that this is quite a bit more general than you asked for. For
example we can flatten nested tuples of arbitrary arities and with
arbitrary element types,

val t3 = (23, ((true, 2.0, "foo"), "bar"), (13, false))
val f3 = flatten(t3) // Inferred type is Int :: Boolean ::
Double :: String :: String :: Int :: Boolean :: HNil
val t3b = f3.tupled // Inferred type is (Int, Boolean, Double,
String, String, Int, Boolean)

I'd love to know what your application for this is ...

Cheers,

Miles

Stefan Zeiger
Joined: 2008-12-21,
User offline. Last seen 27 weeks 3 days ago.
Re: Help neeed: flatten nested tuples

On 2012-02-08 11:56, Bardenhorst, Volker Dr. wrote:
> I need to flatten nested tuples with elements of kind (1, ((2, 3), 4)) (always Tuple2!).

> 1) fltn needs help: fltn((1, ((2, 3), 4))) gives List[Nothing], how to avoid this?
>
> 2) how to use view bounds, means fltn((1, ((2.0, 3), 4))) should give List[Double], currently without type help I get List[Nothing], but even when I do
>
> scala> fltn[Double]((1, ((2, 3.0), 4)))
> res3: List[Double] = List(1, 2, 3.0, 4)

Functional dependencies to the rescue:

trait Flatten[T, R] extends (T => List[R])

object Flatten {
implicit def flattenTuple2[T1, T2, R](implicit f1: Flatten[T1, _ <:
R], f2: Flatten[T2, _ <: R]): Flatten[(T1, T2), R] = new Flatten[(T1,
T2), R] {
def apply(value: (T1, T2)): List[R] = f1(value._1) ::: f2(value._2)
}
implicit def flattenAnything[T <: AnyVal, R](implicit f: (T => R)):
Flatten[T, R] = new Flatten[T, R] {
def apply(value: T) = List(f(value))
}
}

def flatten[R] = new {
def apply[T](v: T)(implicit f: Flatten[T, R]): List[R] = f(v)
}

Types can be inferred when the tuples are uniformly typed:

flatten((1, ((2, 3), 4)))

I couldn't get type unification or implicit conversions to be inferred
automatically but it works if you annotate it with the desired result type:

flatten[Double]((1, ((2, 3.0), 4)))

Cheers,
Stefan

barden
Joined: 2010-03-30,
User offline. Last seen 33 weeks 5 days ago.
RE: Help neeed: flatten nested tuples

Hi Stefan, Klaus,

both replies did the job. Thanks you very much.

Klaus: you created that on the fly or did you adapt an older use case?

Miles: I created my own collection TimeSeries (~TreeMap). Currently I didn't set up a type safe DataTable. In the mean time to deal with multi columen data I added a zip to TimeSeries zipping corresponding time stamps like that

(t -> x) zip (t -> y) gives (t -> (x, y))

Repeating that the values can pump up to nested tuples. My problem was linked to the use case to do operations on those nested tuples.

Take care, Volker.

-----Original Message-----
From: scala-user [at] googlegroups [dot] com [mailto:scala-user [at] googlegroups [dot] com] On Behalf Of Stefan Zeiger
Sent: 08 February 2012 13:39
To: scala-user [at] googlegroups [dot] com
Subject: Re: [scala-user] Help neeed: flatten nested tuples

On 2012-02-08 11:56, Bardenhorst, Volker Dr. wrote:
> I need to flatten nested tuples with elements of kind (1, ((2, 3), 4)) (always Tuple2!).

> 1) fltn needs help: fltn((1, ((2, 3), 4))) gives List[Nothing], how to avoid this?
>
> 2) how to use view bounds, means fltn((1, ((2.0, 3), 4))) should give
> List[Double], currently without type help I get List[Nothing], but
> even when I do
>
> scala> fltn[Double]((1, ((2, 3.0), 4)))
> res3: List[Double] = List(1, 2, 3.0, 4)

Functional dependencies to the rescue:

trait Flatten[T, R] extends (T => List[R])

object Flatten {
implicit def flattenTuple2[T1, T2, R](implicit f1: Flatten[T1, _ <:
R], f2: Flatten[T2, _ <: R]): Flatten[(T1, T2), R] = new Flatten[(T1, T2), R] {
def apply(value: (T1, T2)): List[R] = f1(value._1) ::: f2(value._2)
}
implicit def flattenAnything[T <: AnyVal, R](implicit f: (T => R)):
Flatten[T, R] = new Flatten[T, R] {
def apply(value: T) = List(f(value))
}
}

def flatten[R] = new {
def apply[T](v: T)(implicit f: Flatten[T, R]): List[R] = f(v)
}

Types can be inferred when the tuples are uniformly typed:

flatten((1, ((2, 3), 4)))

I couldn't get type unification or implicit conversions to be inferred automatically but it works if you annotate it with the desired result type:

flatten[Double]((1, ((2, 3.0), 4)))

Cheers,
Stefan

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland