score:2
Lenses formalise the concept of having getter and non-mutating 'setter' functions for data structures, but we don't need the formalism to gain some of the advantages. We will use inversion of control to create modifier functions for your class. These modifier functions will encode ideas like:
'Give me the current state and a new AX, and I will give you a new state'
'Give me the current state and a function that calculates a new AX from the current AX, and I will give you a new state'
'Give me the current state and the new flags, and I will give you a new state'
So, the code:
case class State(ax: Int, flags: Int) {
private def setAx(newAx: Int): State = copy(ax = newAx)
private def modAx(f: Int => Int): State = setAx(f(ax))
private def setFlags(newFlags: Int): State = copy(flags = newFlags)
def withModification(modification: StateFieldModification): State =
modification.field match {
case StateField.AX => setAx(modification.value)
case StateField.AH =>
modAx { ax => (ax & 0x00FF) | (modification.value << 8) }
case StateField.AL =>
modAx { ax => (ax & 0xFF00) | modification.value }
case StateField.CF =>
setFlags(flagsWithBit(1, modification.value > 0))
case StateField.CF =>
setFlags(flagsWithBit(12, modification.value > 0))
}
def withModifications(message: ModificationMessage): State =
message.content.foldLeft(this) { (state, modification) =>
state withModification modification
}
}
P.S., you can probably simplify some of your types, e.g. StateField
doesn't really need to be a multi-level hierarchy--you can split it up into separate Register
and Flag
enums; and you can unwrap or type alias ModificationMessage
since it's just a list.
score:2
You seem to be doing it all wrong. This would be an approach to take in a dynamic language like perl or ruby, but scala isn't like that. You can probably mimic something like that with scala, but it'll be hard enough to make you not want to.
.getDetail
is not something you'll often see in scala. If you want to get a person's name, you'd usually just do person.name
not, person.getDetail(PersonDetail.Name)
. Why? Well, why not? There is simply no reason to do the latter when you can do the former.
Likewise for the setter: person.copy(firstName = "foo") works way better than person.withModiciation(PersonDetail.Name, "foo")
The third case is, perhaps, the most complicated. What if you wanted to apply a whole bunch of modifications? Well, I'll, still argue, that something like
val list = List(
PersonDetail.FirstName -> "foo",
PersonDetail.LastName -> "bar",
PersonDetail.OtherStuff -> "baz"
)
person.withModifications(list)
isn't any better than the scala's customary
person.copy(firstName = "foo", lastName = "bar", otherStuff = "baz")
score:2
Have you considered using a Lens library such as Monacle? Lens are functional abstractions that allow you apply functions to part of a data structure, such as your Person case class. A Lens allows you zoom in on part of the structure, so for Person, one could
import monocle.Lens
val firstName = Lens[Person, String]( p => f => p.copy(firstName = f))
val newPerson = firstName.set("someNewName")(person)
In this way each modification in PersonDetail could correspond to a suitable Lens. Lens also support other operations too. For more complex modifications, Lens can be composed as is shown on the Monacle README. Besides calling a set function, they also can modify data based on a current value, to correspond to the FirstNameFirstLetter case.
firstName.headOption.modify(_.toUpper)(person)
Source: stackoverflow.com
Related Query
- Scala case class copy constructor with dynamic fields
- Scala case class copy with dynamic named parameter
- scala call constructor of case class with all fields except one automatically
- Scala - copy case class with dynamic fields. Is it possible?
- Scala copy case class with generic type
- How do I add a no-arg constructor to a Scala case class with a macro annotation?
- compare case class fields with sub fields of another case class in scala
- Scala case class copy doesn't always work with `_` existential type
- Scala - case class with 100 fields (StackOverflowError)
- Scala case class copy with optional values
- Scala case class copy only with some parameters at runtime?
- How to get Scala case class fields and values as (String, String) with Shapeless or Macro
- Can I invoke case class copy method with dynamic parameter without explicit reflection?
- Automatic type class derivation for case classes with Scala Enumeration fields
- Change fields of case class based on map entries with simple type check in scala macros
- Scala case class copy method with Map parameter
- Scala case class constructor with WrappedArray argument
- Parse json array to a case class in scala using playframework with the fields in json not matching the fields in case class
- Case object extending class with constructor in Scala
- Why Scala case class copy method parameterised only with the variables defined in the case class?
- scala - equivalent case class for the text parsing that has dynamic number of fields
- Using Spark converting nested json with optional fields to Scala case class not working
- Scala - How to extract Json4s with dynamic case class created with ToolBox
- How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration
- Scala case class private constructor but public apply method
- Scala case class extending Product with Serializable
- case class copy 'method' with superclass
- Case Classes with optional fields in Scala
- Scala case having 22 fields but having issue with play-json in scala 2.11.5
- Shapeless - turn a case class into another with fields in different order
More Query from same tag
- Turning a list/sequence of combinator parsers into a single one
- Vaadin 8 - Download Button for a text file with String content
- Spark/scala how to subtract the current column's values from the previous column's?
- Logging request time of a Play!2 Scala application
- Where to put a user-editable database connection string for a Scala Lift web application?
- Scala Map pattern matching
- How to avoid the strange order in which maps are concatenated? (A++B++C ---> BAC)
- How can I explain the Apache Spark RDD Lineage Graph?
- Create function to group sequence at breakpoints
- Scala: how to merge a collection of Maps
- Type mismatch error with foldLeft method in Scala
- Akka monitor children restarts
- java.lang.ClassNotFoundException: org.apache.hadoop.hbase.HBaseConfiguration
- Repeat data operation in Scala
- What are good examples of: "operation of a program should map input values to output values rather than change data in place"
- Setting up actions for multiple test folders in SBT using 'Simple' configuration
- How to create DataFrame: The number of columns doesn't match
- Declare generic method returning enumeration
- How do I unit test an akka Actor synchronously?
- Error package org.apache.spark.sql is not a value when I try to compile a SBT in Spark- Scala
- Scala: return element using if inside map function
- How can create a new DataFrame from a list?
- F-bounded type generic vs abstract type
- RSparkling Spark Error on YARN (java.lang.ClassNotFoundException: water.fvec.frame)
- Parsing Data in Apache Spark Scala org.apache.spark.SparkException: Task not serializable error when trying to use textinputformat.record.delimiter
- MultiMap in Scala
- Cannot run scala files from command prompt
- How to find index of element with minimum value?
- Slick for-comprehensions: How to handle an enumerator that can be None or Some-thing?
- IntelliJ doesn't recognize TypeTag in Scala