(T,T)* resolves to Seq[(T,T)] after erasure, but how to represent (T,T)* itself as a type?
The reason I ask is there's an API I'm using that defines a:
def foo(bar: (String,String)*) = ...
but fails when I try to pass in a Seq[(String,String)].
My pull request to add in:
def foo(bar: Seq[(String,String)]) = ...
blows up due to the 2 methods having the same type after erasure.
Are star projections able to be represented as a concrete type?
You can pass the Seq if you follow it with :_* like this:
val s:Seq[(String, String)] = Seq( ("a", "b"), ("c", "d"), ... )
foo(s:_*)
So you shouldn't need both signatures.
To disambiguate the erased signatures:
scala> class X { def f(is: Int*) = is.sum }
defined class X
scala> class Y extends X { def f(is: Seq[Int])(implicit d: DummyImplicit): Int = f(is: _*) }
defined class Y
scala> new Y().f(1 to 10)
res3: Int = 55
or this is better, the signatures in collections always look like this to mean "two or more":
scala> class X {
| def f(i: Int): Int = i
| def f(is: Seq[Int]): Int = is.sum
| def f(i: Int, j: Int, rest: Int *): Int = i + j + rest.sum
| }
defined class X
scala> new X().f(3)
res9: Int = 3
scala> new X().f(3,4)
res10: Int = 7
scala> new X().f(3,4,5)
res11: Int = 12
scala> new X().f(1 to 10)
res12: Int = 55
You can't refer to a repeated parameter type, just as you can't refer to a by-name parameter type as such. So you can't convert to it. However, you can detect it reflectively, by name:
scala> import reflect.runtime.universe._
import reflect.runtime.universe._
scala> typeOf[X].member(TermName("f")).asMethod.paramss.flatten.head.asTerm.typeSignature.typeSymbol.name
warning: there were 1 deprecation warning(s); re-run with -deprecation for details
res4: reflect.runtime.universe.Symbol#NameType = <repeated>
There is internal API, definitions.isRepeated(sym), if you want to cast for it.
Related
Is there a difference between whether I use def or val while defining a partial function? I thought that probably def will be evaluated everytime (like a function call) while val will be evaluated only once but that doesn't seem to be the case.
scala> def add(x:Int)(y:Int) = {println("inadd");x+y}
add: (x: Int)(y: Int)Int
//def
scala> def add2ToDef= add(2) _
add2ToDef: Int => Int
//val
scala> val add2ToVal= add(2) _
add2ToVal: Int => Int = $$Lambda$1032/1413020227#512abf25
scala> add2ToDef(3)
inadd
res0: Int = 5
scala> add2ToVal(3)
inadd
res1: Int = 5
scala> add2ToDef(4)
inadd
res2: Int = 6
scala> add2ToVal(5)
inadd
res3: Int = 7
Essentially the same difference as between val and def in general:
def will produce a new lambda (new object) every time you reference it.
val will produce it once (at definition time) and every reference to it refers to the same instance.
In this case, val makes more sense so it's not creating a new lambda every time.
You are right that:
def will be evaluated every time you reference the function and val will be evaluated only once and the same value will be used every time.
It is true with partial functions as well. To see the behavior you can see this example:
scala> def add(x:Int)(y:Int) = {println("inadd");x+y}
add: (x: Int)(y: Int)Int
scala> def addWithDef = add(2)(3)
addWithDef: Int
scala> addWithDef // Evaluated
inadd
res0: Int = 5
scala> addWithDef // Evaluated again as "inadd" is printed again
inadd
res1: Int = 5
scala> val addWithVal = add(2)(3) // Evaluated once
inadd
addWithVal: Int = 5
scala> addWithVal //Same value referenced again(no "inadd" printed)
res2: Int = 5
scala> addWithVal //Same value referenced again(no "inadd" printed)
res3: Int = 5
Is it possible to implement in Scala an implicit conversion for the group of parameters (without defining them as some class member) like
implicit def triple2One (x :Int, s :String, d :Double) = x // just as an example
So that I would be able to call it in the code like
val x :Int = (1, "test", 2.0)
It is possible:
scala> implicit def iFromISD(isd: (Int, String, Double)): Int = isd._1
iFromISD: (isd: (Int, String, Double))Int
scala> val x: Int = (1, "two", 3.0)
x: Int = 1
Naturally, there has to be a type annotation on the resulting val to drive the search for and application of the implicit conversion.
Addendum
It occurs to me there's another way that doesn't involve dubious implicit conversions:
scala> val (y, _, _) = (1, "two", 3.0)
y: Int = 1
I know it's possible to pass individual arguments to a vararg function and it's possible to pass a seq using :_* but is it possible to pass both?
for example:
scala> object X { def y(s: String*) = println(s) }
defined module X
scala> X.y("a", "b", "c")
WrappedArray(a, b, c)
scala> X.y(Seq("a", "b", "c"):_*)
List(a, b, c)
scala> X.y("a", Seq("b", "c"):_*)
<console>:9: error: no `: _*' annotation allowed here
(such annotations are only allowed in arguments to *-parameters)
X.y("a", Seq("b", "c"):_*)
^
Edit: In Scala 2.10 (in case that matters)
Hacky but this should work well:
X.y(Seq("a") ++ Seq("b", "c"):_*)
If you look around in the Scala standard library you'll find this sort of pattern in places:
def doIt(arg: Thing)
def doIt(arg1: Thing, arg2: Thing, moreArgs: Thing*)
You can see this, e.g., in Set.+(...). It allows you to have any number of arguments without ambiguity in the overloads.
Addendum
Proof of concept:
scala> class DI { def doIt(i: Int) = 1; def doIt(i1: Int, i2: Int, iMore: Int*) = 2 + iMore.length }
defined class DI
scala> val di1 = new DI
di1: DI = DI#16ac0be1
scala> di1.doIt(0)
res1: Int = 1
scala> di1.doIt(1, 2)
res2: Int = 2
scala> di1.doIt(1, 2, 3)
res3: Int = 3
scala> di1.doIt(1, 2, List(3, 4, 5): _*)
res4: Int = 5
Is it possible to get the type of a type field after creating an object ?
I would like to do something like this:
scala> class A { type T = String }
defined class A
scala> val a = new A
a: A = A#591171
scala> a.T
<console>:13: error: value T is not a member of A
a.T
^
The last
What do you want to do with the type? You can use a type projection in various ways with the class's type (without an instance):
scala> class A { type T = String }
defined class A
scala> val x: A#T = "test"
x: java.lang.String = test
scala> def f(b: A#T) = b
f: (a: java.lang.String)java.lang.String
Or if you enable -Ydependent-method-types, you can get the type member from the instance:
scala> val a = new A
a: A = A#6a3de2df
scala> val x: a.T = "test"
x: a.T = test
scala> def f(b: a.T) = b
f: (b: a.T)a.T
Scala's reflection API prior to 2.10 doesn't really model types in any clean way, so if you want to "get the type" in some other sense, you're probably out of luck.
One way is with reflection (since 2.10M4):
// with static types
scala> class A { type T = String }
defined class A
scala> import reflect.runtime.{universe => u}
import reflect.runtime.{universe=>u}
scala> val t = u.typeOf[A]
t: reflect.runtime.universe.Type = A
scala> val types = t.declarations.filter(_.isType)
types: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(type T)
scala> types.toList.head.typeSignature
res9: reflect.runtime.universe.Type = String
// with instances
scala> val a = new A
a: A = A#68d7c870
scala> import reflect.runtime.{currentMirror => m}
import reflect.runtime.{currentMirror=>m}
scala> m.reflect(a).symbol.asType // same type as t
res20: reflect.runtime.universe.Type = A
After having discovered that currying multi parameter-groups method is possible, I am trying to get a partially applied function which requires implicit parameters.
It seams not possible to do so. If not could you explain me why ?
scala> def sum(a: Int)(implicit b: Int): Int = { a+b }
sum: (a: Int)(implicit b: Int)Int
scala> sum(3)(4)
res12: Int = 7
scala> val partFunc2 = sum _
<console>:8: error: could not find implicit value for parameter b: Int
val partFunc2 = sum _
^
I use a singleton object to create this partially applied function and I want to use it in a scope where the implicit int is defined.
That is because you don't have an implicit Int in scope. See:
scala> def foo(x: Int)(implicit y: Int) = x + y
foo: (x: Int)(implicit y: Int)Int
scala> foo _
<console>:9: error: could not find implicit value for parameter y: Int
foo _
^
scala> implicit val b = 2
b: Int = 2
scala> foo _
res1: Int => Int = <function1>
The implicit gets replaced with a real value by the compiler. If you curry the method the result is a function and functions can't have implicit parameters, so the compiler has to insert the value at the time you curry the method.
edit:
For your use case, why don't you try something like:
object Foo {
def partialSum(implicit x: Int) = sum(3)(x)
}
scala> object MySingleton {
| def sum(a: Int)(implicit b: Int): Int = { a+b }
|
|
| def caller(a: Int) = {
| implicit val b = 3; // This allows you to define the partial below
| def pf = sum _ // and call sum()() without repeating the arg list.
| pf.apply(a)
| }
| }
defined module MySingleton
scala> MySingleton.caller(10)
res10: Int = 13