I want to assign a member function of a class instance as a first class function to a variable:
class A(val id:Int){ def f(u:Int)=id+u }
val a= new A(0)
val h=a.f // fails: interpreted as a.f(with missing parameter u)
val h1 = (u:Int)=>a.f(u) // OK and does what we want
We can get the desired effect by assigning an appropriate anonymous function.
Is this the only way?
I searched but could find no reference at all.
Use a placeholder to indicate it is partially applied:
scala> class A(val id:Int){ def f(u:Int)=id+u }
defined class A
scala> val a = new A(0)
a: A = A#46a7a4cc
scala> val h = a.f _
h: Int => Int = <function1>
scala> h(2)
res0: Int = 2
EDIT
Trying the code out in the REPL prints
scala> val h = a.f
<console>:9: error: missing arguments for method f in class A;
follow this method with `_' if you want to treat it as a partially applied function
val h = a.f
^
Related
I have the following structure in a data class:
data class A(
val b: Int,
val c: C
) {
data class B(
val d: Int
)
data class C(
val d: Int
)
}
and an instance of this class is being passed to a method which has the following signarure:
fun doSomethingMethod(object: A.B?): Mono<Unit> =
// do something
}
So now I am trying to initialize an instance of the data class A with only initializing B as wel but I dont understand how to do it. So far I have tried:
val testObject = A(A.B(5))
But its not working. Anyone has an idea?
To create an object of nested data class just use next syntax:
val instance = OuterClass.NestedClass([params])
In your case it will be:
val b = A.B(5)
Complete example:
fun doSomethingMethod(b: A.B?): Mono<Unit> {
// do something
}
val b = A.B(5)
val mono = doSomethingMethod(b)
I would like to make the following work:
def foo(x:Int = 1) = {
object obj {
val x = foo.this.x
}
}
But I don't know how to reference x from within the object. Can this be done without renaming x in one of the two spots?
Renaming the variables may not be easy when, for example, foo is a widely used API function with x as a named variable, while obj extends a 3rd party trait that has x as an abstract member.
No, this is not possible. There is no way to identify the outer block of the function definition.
For your syntax to work foo would have to be an object with a member x. i.e. this works:
class foo{
val x = 1
object obj {
val x = foo.this.x
}
}
foo also could be a singleton object extending FunctionX, which gives you something very similar to a method. But it is probably easier to just rename one of the values.
It is not possible in Scala.
You write the code, so the easiest option will be to rename one of the xs and problem solved.
However, if from some reason you really need it - you can do a trick and create an object that will behave like your method
object Foo {
self =>
val x = 1
def apply() = {
object obj {
val x1 = self.x
val x2 = Foo.x
// x1 == x2, just 2 different ways of doing this
}
}
}
Because the apply method is implemented you can use it as you would use a function Foo()
Why not just introduce a new variable that has the same value as foo's argument x, but is not shadowed?
def foo(x: Int): Unit = {
val foo_x = x
object obj {
val x = 13
def doStuff: Unit = printf("%d %d\n", x, foo_x);
}
obj.doStuff
}
foo(42)
I am using shapeless 2.1.0 -scala 2.11, jdk 1.7: I have a trait
trait Input[T]{
def location:String
}
object location extends Poly1 {
implicit def caseInput[T] = at[Input[T]](l => l.location)
}
val list = new Input[String] {def location:String="/tmp"} :: HNil
list.map(location)
This returns correctly in my console
shapeless2.::[String,shapeless2.HNil] = /tmp :: HNil
However when I have the exact same logic in a function -where the HList is returned to me from another function call and I map function on it I get a compile time error
:could not find implicit value for parameter mapper: shapeless.ops.hlist.Mapper[location.type,shapeless.::[Input[String]{...},shapeless.HNil]]
I suspect I am probably missing some implicits. I have checked the shapeless tests and documentation -hopefully I didn't miss anything too obvious.
I can create a complete example to recreate the issue if it's not something obvious -thanks for reading.
Best,
Amit
Updated: With an example
trait Input[T]{
def location:String
def value:T
}
trait location extends Poly1 {
implicit def caseList[T] = at[Input[T]](l => l.location)
}
object testfun extends location {
implicit val atString = at[Input[String]](_.location)
implicit val atInt = at[Input[Int]](_.location)
implicit val atLong = at[Input[Long]](_.location)
}
def inputs:HList={
val str = new Input[String]{
override def location: String = "/tmp/string"
override def value: String = "here it is"
}
val ints = new Input[Int]{
override def location: String = "/tmp/1"
override def value: Int = 1
}
val longs = new Input[Long]{
override def location: String = "/tmp/1l"
override def value: Long = 1l
}
str::ints::longs::HNil
}
>>>println(inputs.map(testfun))
could not find implicit value for parameter mapper: shapeless.ops.hlist.Mapper[HListTest.testfun.type,shapeless.HList]
If I were to remove the return type of the def inputs, I don't get any errors.
It turned out that the gist that I have posted works fine -it was an issue with Intellij
gist.github.com/kumaramit01/80ca29b46d2c07e55b0b
Intellij kept on indicating syntax error when I had return type defined as
Input[String] :: Input[Int] :: Input[Long] :: HNil
Amit
I have this:
package models
import play.api.libs.json._
import play.api.libs.functional.syntax._
object ModelWrites {
implicit val tmoWrites= Json.writes[TestModelObject]
implicit val ihWrites = Json.writes[IntHolder]
}
case class TestModelObject(s1:String, s2:String)
case class IntHolder(i1:Int, i2:Int)
trait HasInts {
val ints: List[IntHolder]
}
When I do this:
scala> val tmo = new TestModelObject("hello", "world") with HasInts {
val ints = List(IntHolder(1,2), IntHolder(3,4))
}
scala> Json.toJson(tmo)
res0: play.api.libs.json.JsValue = {"s1":"hello","s2":"world"}
how can I implicity serialize the mixed-in val 'ints'? Like:
scala> val someInts = List(IntHolder(8,9), IntHolder(10,11))
someInts: List[models.IntHolder] = List(IntHolder(8,9), IntHolder(10,11))
scala> Json.toJson(someInts)
res1: play.api.libs.json.JsValue = [{"i1":8,"i2":9},{"i1":10,"i2":11}]
Note: if I try: implicit val hasIntsWrites = Json.writes[HasInts] I (expectedly?) get:
[error] Models.scala:10: No unapply function found
[error] implicit val hasIntsWrites = Json.writes[HasInts]
[error] ^
You're not going to be able to use the experimental "Inception" feature (Json.writes[...]) directly here, since that only works on case classes. You can, however, build on the Writes instances that Inception can provide to accomplish what you want with only a very little boilerplate.
Note that I'm ignoring the question of whether mixing in a trait when instantiating a case class like this is a good idea—it probably isn't—but the approach I give here will work in the more general case as well.
First for the classes and imports (no changes here):
case class TestModelObject(s1: String, s2: String)
case class IntHolder(i1: Int, i2: Int)
trait HasInts { val ints: List[IntHolder] }
import play.api.libs.json._
import play.api.libs.functional.syntax._
Now we need to put all our lower-priority instances into a trait to make sure that the compiler will pick the right one, since TestModelObject with HasInts is a subtype of both TestModelObject and HasInts:
trait LowPriorityWritesInstances {
implicit val tmoWrites = Json.writes[TestModelObject]
implicit val ihWrites = Json.writes[IntHolder]
implicit object hiWrites extends OWrites[HasInts] {
def writes(hi: HasInts) = Json.obj("ints" -> hi.ints)
}
}
And now the main event:
object WritesInstances extends LowPriorityWritesInstances {
implicit val tmowhiWrites = new Writes[TestModelObject with HasInts] {
def writes(o: TestModelObject with HasInts) =
tmoWrites.writes(o) ++ implicitly[OWrites[HasInts]].writes(o)
}
}
And we're done:
scala> import WritesInstances._
import WritesInstances._
scala> val tmo = new TestModelObject("hello", "world") with HasInts {
| val ints = List(IntHolder(1, 2), IntHolder(3, 4))
| }
scala> println(Json.toJson(tmo))
{"s1":"hello","s2":"world","ints":[{"i1":1,"i2":2},{"i1":3,"i2":4}]}
As desired.
How can i deserialize json array using lift-json to scala vector?
For example:
case class Foo(bar: Vector[Bar])
trait Bar {
def value: Int
}
case class Bar1(value: Int) extends Bar
case class Bar2(value: Int) extends Bar
import net.liftweb.json.{ShortTypeHints, Serialization, DefaultFormats}
implicit val formats = new DefaultFormats {
override val typeHintFieldName = "type"
override val typeHints = ShortTypeHints(List(classOf[Foo],classOf[Bar1],classOf[Bar2]))
}
println(Serialization.writePretty(Foo(Vector(Bar1(1), Bar2(5), Bar1(1)))))
The result is:
{
"type":"Foo",
"bar":[{
"type":"Bar1",
"value":1
},{
"type":"Bar2",
"value":5
},{
"type":"Bar1",
"value":1
}]
}
Good. But when i try to deserialize this string
println(Serialization.read[Foo](Serialization.writePretty(Foo(Vector(Bar1(1), Bar2(5), Bar1(1))))))
i get an exception:
net.liftweb.json.MappingException: Parsed JSON values do not match
with class constructor args=List(Bar1(1), Bar2(5), Bar1(1)) arg
types=scala.collection.immutable.$colon$colon constructor=public
test.Foo(scala.collection.immutable.Vector)
It's means that json array associated with scala list, not vector type that defined in class Foo. I know that there is way to create custom serializer by extending net.liftweb.json.Serializer and include it to formats value. But how can i restore type of objects that stores in Vector. I wanna get result of deserializing like this:
Foo(Vector(Bar1(1), Bar2(5), Bar1(1)))
I've often been annoyed by the List-centricness of Lift, and have found myself needing to do similar things in the past. The following is the approach I've used, adapted a bit for your example:
trait Bar { def value: Int }
case class Bar1(value: Int) extends Bar
case class Bar2(value: Int) extends Bar
case class Foo(bar: Vector[Bar])
import net.liftweb.json._
implicit val formats = new DefaultFormats { outer =>
override val typeHintFieldName = "type"
override val typeHints =
ShortTypeHints(classOf[Bar1] :: classOf[Bar2] :: Nil) +
new ShortTypeHints(classOf[Foo] :: Nil) {
val FooName = this.hintFor(classOf[Foo])
override def deserialize = {
case (FooName, foo) => foo \ "bar" match {
case JArray(bars) => Foo(
bars.map(_.extract[Bar](outer, manifest[Bar]))(collection.breakOut)
)
case _ => throw new RuntimeException("Not really a Foo.")
}
}
}
}
Kind of ugly, and could probably be cleaned up a bit, but it works.
You could add an implicit conversion:
implicit def listToVect(list:List[Bar]):Vector[Bar] = list.map(identity)(breakOut)
after that, Serialization.read[Foo] works as expected.