I have a structure of nested case classes that I create with default values:
case class Alpha(text: String = "content")
case class Beta(alpha: Alpha = Alpha())
case class Gamma(beta: Option[Beta] = None)
I would like to create the whole thing with default values and then modify the elements in particular that need to be non-default using Monocle.
With isos is easy. I can specify the navigation with composition and then use set to modify the inner element:
object Beta {
val alphaI: Iso[Beta, Alpha] = GenIso[Beta, Alpha]
}
object Alpha {
val textI: Iso[Alpha, String] = GenIso[Alpha, String]
}
(Beta.alphaI composeIso Alpha.textI).set("foo")(Beta()) shouldBe Beta(Alpha("foo"))
Unfortunately with prims it doesn't seem that elegant, as set/modify will only modify the inner element if all the options during the navigation are defined (Some(...))
object Gamma {
val betaI: Iso[Gamma, Option[Beta]] = GenIso[Gamma, Option[Beta]]
val betaP: Prism[Gamma, Beta] = Prism[Gamma, Beta](_.beta)(a => Gamma(Some(a)))
}
val navigateToText: Prism[Gamma, String] = Gamma.betaP composeIso Beta.alphaI composeIso Alpha.textI
navigateToText.set("foo")(Gamma(None)) shouldBe Gamma(None)
navigateToText.set("foo")(Gamma(Some(Beta()))) shouldBe Gamma(Some(Beta(Alpha("foo"))))
The best thing I've come up with so far is using a composed optic to set to a Some() each optional element of the path and then the composed optic all the way down to set the element we were interested in to begin with.
(Gamma.betaI.set(Some(Beta())) andThen navigateToText.set("foo")) (Gamma()) shouldBe Gamma(Some(Beta(Alpha("foo"))))
Ideally I'd like each building block of the composition to set the optional values to Some(defaultValue) if they are originally None. Obviously the building block would need to be defined including the appropriate default value for the step of the path.
Any suggestions?
Full code including imports: https://github.com/jcaraballo/navigating-fixtures-with-monocle/blob/master/src/test/scala/pr/NavigateIntoOptionSpec.scala
You could use below from Prism such as the types match in the optics composition:
import monocle.macros.GenIso
import scalaz.std.option._
case class Alpha(text: String = "content")
case class Beta(alpha: Alpha = Alpha())
case class Gamma(beta: Option[Beta] = None)
val navigateToText = GenIso[Gamma, Option[Beta]] composePrism
GenIso[Beta, Alpha].asPrism.below[Option] composePrism
GenIso[Alpha, String].asPrism.below[Option]
navigateToText.set(Some("foo"))(Gamma(None)) // Gamma(Some(Beta(Alpha(foo))))
navigateToText.set(Some("foo"))(Gamma(Some(Beta(Alpha("bar"))))) // Gamma(Some(Beta(Alpha(foo))))
Related
I have a quite big structure of case classes and somewhere deep inside this structure I have fields which I want to refine, for example, make lists non-empty. Is it possible to tell ScalaCheck to make those lists non-empty using automatic derivation from scalacheck-magnolia project (without providing each field specifically)?
Example:
import com.mrdziuban.ScalacheckMagnolia.deriveArbitrary
import org.scalacheck.Arbitrary
import org.scalacheck.Gen
case class A(b: B, c: C)
case class B(list: List[Long])
case class C(list: List[Long])
// I've tried:
def genNEL[T: Gen]: Gen[List[T]] = Gen.nonEmptyListOf(implicitly[Gen[T]])
implicit val deriveNEL = Arbitrary(genNEL)
implicit val deriveA = implicitly[Arbitrary[A]](deriveArbitrary)
But it's didn't worked out.
I'm not sure how to be generic, since I'm not familiar with getting automatic derivation for Arbitrary with scalacheck-magnolia. It seems like scalacheck-magnolia is good for deriving an Arbitrary for case classes, but maybe not for containers (lists, vectors, arrays, etc.).
If you want to just use plain ScalaCheck, you could just define the implicit Arbitrary for A yourself. Doing it by hand is some extra boilerplate, but it has the benefit that you have more control if you want to use different generators for different parts of your data structure.
Here's an example where an Arbitrary list of longs is non-empty by default, but is empty for B.
implicit val listOfLong =
Arbitrary(Gen.nonEmptyListOf(Arbitrary.arbitrary[Long]))
implicit val arbC = Arbitrary {
Gen.resultOf(C)
}
implicit val arbB = Arbitrary {
implicit val listOfLong =
Arbitrary(Gen.listOf(Arbitrary.arbitrary[Long]))
Gen.resultOf(B)
}
implicit val arbA = Arbitrary {
Gen.resultOf(A)
}
property("arbitrary[A]") = {
Prop.forAll { a: A =>
a.b.list.size >= 0 && a.c.list.size > 0
}
}
From what I have understood, scala treats val definitions as values.
So, any instance of a case class with same parameters should be equal.
But,
case class A(a: Int) {
lazy val k = {
println("k")
1
}
val a1 = A(5)
println(a1.k)
Output:
k
res1: Int = 1
println(a1.k)
Output:
res2: Int = 1
val a2 = A(5)
println(a1.k)
Output:
k
res3: Int = 1
I was expecting that for println(a2.k), it should not print k.
Since this is not the required behavior, how should I implement this so that for all instances of a case class with same parameters, it should only execute a lazy val definition only once. Do I need some memoization technique or Scala can handle this on its own?
I am very new to Scala and functional programming so please excuse me if you find the question trivial.
Assuming you're not overriding equals or doing something ill-advised like making the constructor args vars, it is the case that two case class instantiations with same constructor arguments will be equal. However, this does not mean that two case class instantiations with same constructor arguments will point to the same object in memory:
case class A(a: Int)
A(5) == A(5) // true, same as `A(5).equals(A(5))`
A(5) eq A(5) // false
If you want the constructor to always return the same object in memory, then you'll need to handle this yourself. Maybe use some sort of factory:
case class A private (a: Int) {
lazy val k = {
println("k")
1
}
}
object A {
private[this] val cache = collection.mutable.Map[Int, A]()
def build(a: Int) = {
cache.getOrElseUpdate(a, A(a))
}
}
val x = A.build(5)
x.k // prints k
val y = A.build(5)
y.k // doesn't print anything
x == y // true
x eq y // true
If, instead, you don't care about the constructor returning the same object, but you just care about the re-evaluation of k, you can just cache that part:
case class A(a: Int) {
lazy val k = A.kCache.getOrElseUpdate(a, {
println("k")
1
})
}
object A {
private[A] val kCache = collection.mutable.Map[Int, Int]()
}
A(5).k // prints k
A(5).k // doesn't print anything
The trivial answer is "this is what the language does according to the spec". That's the correct, but not very satisfying answer. It's more interesting why it does this.
It might be clearer that it has to do this with a different example:
case class A[B](b: B) {
lazy val k = {
println(b)
1
}
}
When you're constructing two A's, you can't know whether they are equal, because you haven't defined what it means for them to be equal (or what it means for B's to be equal). And you can't statically intitialize k either, as it depends on the passed in B.
If this has to print twice, it would be entirely intuitive if that would only be the case if k depends on b, but not if it doesn't depend on b.
When you ask
how should I implement this so that for all instances of a case class with same parameters, it should only execute a lazy val definition only once
that's a trickier question than it sounds. You make "the same parameters" sound like something that can be known at compile time without further information. It's not, you can only know it at runtime.
And if you only know that at runtime, that means you have to keep all past uses of the instance A[B] alive. This is a built in memory leak - no wonder Scala has no built-in way to do this.
If you really want this - and think long and hard about the memory leak - construct a Map[B, A[B]], and try to get a cached instance from that map, and if it doesn't exist, construct one and put it in the map.
I believe case classes only consider the arguments to their constructor (not any auxiliary constructor) to be part of their equality concept. Consider when you use a case class in a match statement, unapply only gives you access (by default) to the constructor parameters.
Consider anything in the body of case classes as "extra" or "side effect" stuffs. I consider it a good tactic to make case classes as near-empty as possible and put any custom logic in a companion object. Eg:
case class Foo(a:Int)
object Foo {
def apply(s: String) = Foo(s.toInt)
}
In addition to dhg answer, I should say, I'm not aware of functional language that does full constructor memoizing by default. You should understand that such memoizing means that all constructed instances should stick in memory, which is not always desirable.
Manual caching is not that hard, consider this simple code
import scala.collection.mutable
class Doubler private(a: Int) {
lazy val double = {
println("calculated")
a * 2
}
}
object Doubler{
val cache = mutable.WeakHashMap.empty[Int, Doubler]
def apply(a: Int): Doubler = cache.getOrElseUpdate(a, new Doubler(a))
}
Doubler(1).double //calculated
Doubler(5).double //calculated
Doubler(1).double //most probably not calculated
Let's say there is a generic method declaration that performs a set of operations based upon a designated mode that would look something like this:
def doSomethingSmart(mode: OpMode, someGoodyList: List[Any]): Boolean = { /* do foo */ }
Where OpMode is a type/enumeration consisting of:
Read
Create
Delete
Modify
Whatever
Putting the two together would obviously yield a single-mode, reusable, code block.
Now, the type/enumeration part would probably look something like this:
object OpMode extends Enumeration {
type OpMode = Value
val Read, Write, Create, Modify, Delete, Whatever = Value
}
But let's say you wanted to expand the scope of doSomethingSmart() to span what is typically done using bitwise operators, for example: Create & Modify & Whatever. Is there a "scala-way" of restricting the bit-masked argument to that limited data-set (ie, the enumeration/type). Maybe something along these lines:
def doSomethingSmarter(more: T < [BitwiseSelectionOf[OpMode]], ...
Or, is it best to simply drop back to binary-indexed value assignments - in which cases there is no "type" checking per se?
TIA.
EDIT: I guess another possibility would be to change the OpMode to be a List and then just run a series of "contains" operations.
EDIT 2: In particular, I was looking for an efficient mechanism that provides an inline construct when making a call to doSomethingSmarter()
Enumeration defines an inner type called ValueSet which gives you at least some of the functionality you are looking for. The methods on it are still Set-like (you would add a new mode using +, and check for a mode using contains), but it may serve your purposes.
EDIT: had some fun fiddling around and came up with this:
import scala.collection.BitSet
object OpMode extends Enumeration {
protected case class Val(name: String, val mask: Int) extends super.Val(nextId, name)
type OpMode = Val
val Read = Val("Read", 1)
val Write = Val("Write", 2)
val Create = Val("Create", 4)
val Modify = Val("Modify", 8)
val Delete = Val("Delete", 16)
val Whatever = Val("Whatever", 32)
case class FlagSet(bits: BitSet) {
def isSet(mode: OpMode) = bits.contains(mode.mask)
def +(mode: OpMode) = new FlagSet(bits + mode.mask)
def -(mode: OpMode) = new FlagSet(bits - mode.mask)
def &(other: FlagSet) = new FlagSet(bits & other.bits)
def &~(other: FlagSet) = new FlagSet(bits &~ other.bits)
def ^(other: FlagSet) = new FlagSet(bits ^ other.bits)
def |(other: FlagSet) = new FlagSet(bits | other.bits)
def size = bits.size
// etc.
}
object FlagSet {
def apply(flags: OpMode*): FlagSet = apply(BitSet(flags.map(_.mask):_*))
def apply(modes: ValueSet): FlagSet = apply(BitSet(modes.toSeq.map{ case m: OpMode => m.mask }:_*))
}
}
def doSomethingSmarter(modes: OpMode.FlagSet, someGoodyList: List[Any]) = modes.size
val flags = OpMode.FlagSet(OpMode.Read, OpMode.Write)
doSomethingSmarter(flags, Nil)
val modes = OpMode.ValueSet(OpMode.Read, OpMode.Write)
doSomethingSmarter(OpMode.FlagSet(modes), Nil)
Basically, I extended the Enumeration.Val type to add a suitable bit mask for each mode, and added an inner class FlagSet to interoperate between OpModes and an under-the-covers BitSet. Changing doSomethingSmarter to take in such a FlagSet enables usage that should be closer to what you are hoping for.
The above can probably be improved upon, but working with Enumeration can be tricky. As an alternative, you might find it preferable to work with a sealed trait and case classes/objects extending it - this can often give semantics closer to what is possible with Java's enum types.
For scala case class with number of parameters (21!!)
e.g. case class Car(type: String, brand: String, door: Int ....)
where type = jeep, brand = toyota, door = 4 ....etc
And there is a copy method which allow override with named parameter: Car.copy(brand = Kia)
where would become type = jeep, brand = Kia, door = 2...etc
My question is, is there anyway I can provide the named parameter dynamically?
def copyCar(key: String, name: String) = {
Car.copy("key" = "name") // this is something I make up and want to see if would work
}
Is scala reflection library could provide a help here?
The reason I am using copy method is that I don't want to repeat the 21 parameters assignment every time when I create a case class which only have 1 or 2 parameter changed.
Many Thanks!
FWIW, I've just implemented a Java reflection version: CaseClassCopy.scala. I tried a TypeTag version but it wasn't that useful; TypeTag was too restrictive for this purpose.
def copy(o: AnyRef, vals: (String, Any)*) = {
val copier = new Copier(o.getClass)
copier(o, vals: _*)
}
/**
* Utility class for providing copying of a designated case class with minimal overhead.
*/
class Copier(cls: Class[_]) {
private val ctor = cls.getConstructors.apply(0)
private val getters = cls.getDeclaredFields
.filter {
f =>
val m = f.getModifiers
Modifier.isPrivate(m) && Modifier.isFinal(m) && !Modifier.isStatic(m)
}
.take(ctor.getParameterTypes.size)
.map(f => cls.getMethod(f.getName))
/**
* A reflective, non-generic version of case class copying.
*/
def apply[T](o: T, vals: (String, Any)*): T = {
val byIx = vals.map {
case (name, value) =>
val ix = getters.indexWhere(_.getName == name)
if (ix < 0) throw new IllegalArgumentException("Unknown field: " + name)
(ix, value.asInstanceOf[Object])
}.toMap
val args = (0 until getters.size).map {
i =>
byIx.get(i)
.getOrElse(getters(i).invoke(o))
}
ctor.newInstance(args: _*).asInstanceOf[T]
}
}
It is not possible using case classes.
Copy method generated at compile time and named parameters handled on compile time to. There is no possibility to do it ar runtime.
Dynamic may help to solve your issue: http://hacking-scala.tumblr.com/post/49051516694/introduction-to-type-dynamic
Yes, you would need to use reflection to do that.
It is a bit involved, because copy is a synthetic method and you'll have to invoke the getters for all fields except the one you want to replace.
To give you an idea, the copy method in this class does exactly that, except using an argument index instead of name. It calls the companion object's apply method, but the effect is the same.
I'm a bit confused - how is the following not what you need?
car: Car = ... // Retrieve an instance of Car somehow.
car.copy(type = "jeep") // Copied instance, only the type has been changed.
car.copy(door = 4) // Copied instance, only the number of doors has changed.
// ...
Is it because you have a lot of parameters for the initial instance creation? In that case, can you not use default values?
case class Car(type: String = "Jeep", door: Int = 4, ...)
You seem to know about both these features and feel that they don't fit your need - could you explain why?
In Mercury I can use:
A = B^some_field := SomeValue
to bind A to a copy of B, except that some_field is SomeValue instead of whatever it was in B. I believe the Haskell equivalent is something like:
a = b { some_field = some_value }
Does Scala have something like this for "modifying" immutable values. The alternative seems to be to have a constructor that directly sets every field in the instance, which isn't always ideal (if there are invarients the constructor should be maintaining). Plus it would be really clunky and much more fragile if I had to explicitly pass every other value in the instance I want to have a modified copy of.
I couldn't find anything about this by googling, or in a brief survey of the language reference manual or "Scala By Example" (which I have read start-to-finish, but haven't absorbed all of yet, so it may well be in there).
I can see that this feature could have some weird interactions with Java-style access protection and subclasses though...
If you define your class as a case class, a convenient copy method is generated, and calling it you can specify with named parameters new values for certain fields.
scala> case class Sample(str: String, int: Int)
defined class Sample
scala> val s = Sample("text", 42)
s: Sample = Sample(text,42)
scala> val s2 = s.copy(str = "newText")
s2: Sample = Sample(newText,42)
It even works with polymorphic case classes:
scala> case class Sample[T](t: T, int: Int)
defined class Sample
scala> val s = Sample("text", 42)
s: Sample[java.lang.String] = Sample(text,42)
scala> val s2 = s.copy(t = List(1,2,3), 42)
s2: Sample[List[Int]] = Sample(List(1, 2, 3),42)
Note that s2 has a different type than s.
You can use case classes for this, but you don't have to. Case classes are nothing magical - the modifier case just saves you a lot of typing.
The copy method is realized by the use of named and default parameters. The names are the same as the fields and the defaults are the current values of the fields. Here's an example:
class ClassWithCopy(val field1:String, val field2:Int) {
def copy(field1:String = this.field1, field2:Int = this.field2) = {
new ClassWithCopy(field1,field2);
}
}
You can use this just like the copy method on case classes. Named and default parameters are a very useful feature, and not only for copy methods.
If the object you're planning on modifying is a case class then you can use the autogenerated copy method:
scala> val user = User(2, "Sen")
user: User = User(2,Sen)
scala> val corrected = user.copy(name = "Sean")
corrected: User = User(2,Sean)