Take the 2-minute tour ×

I'm currently trying to wrap my mind around Scala with an intention to use it for my next project that has to deal with DICOM. DICOM has quite broad specification that spans over thousands of pages of the standard. My understanding of DICOM is quite limited, but in short DICOM objects - IODs (Information Object Definition) are composed of Modules, and Modules are a collection of typed name-value attribute pairs. It's further complicated by optionality of some modules and attributes. For example:

SimpleImageIOD: {
    PatientModule: {
        name: String
        dateOfBirth: DateTime
    StudyModule: {
        name: String
        date: DateTime (optional)
    SeriesModule: {
        name: String
    ImageModule: {
        height: Integer
        width: Integer
        pixelSize: Double (optional)
    EquipmentModule: { (optional)
        type: String

There are tons of modules, they might be composed in various combinations forming different IODs. Scala in turn has lots of modeling power with all the traits, case classes, dynamic classes, etc. How would you model such domain in Scala? I'm quite new to the language but I've been thinking to use immutable case classes to define modules, then aggregate them in various IODs, and use lenses for updating:

case class Patient(name: String, dateOfBirth: DateTime)
case class Study(name: String, date: Option[DateTime])
case class Series(name: String)
case class Image(height: Integer, width: Integer, pixelSize: Option[Double])
case class Equipment(type: String)

case class SimpleImageIOD(patient: Patient, study: Study, series: Series, 
                          image: Image, equipment: Option[Equipment])

object Patient {
    val nameL: Lens[Patient, String] = ...
    val dateOfBirthL: Lens[Patient, DateTime] = ...

object SimpleImageIOD {
    val patientL: Lens[SimpleImageIOD, Patient] = ...
    val patientNamel = patientL andThen Patient.nameL

Etc etc. With respect to lenses it might become a problem to code all the boilerplate - there's going be order of M x N x L lenses to cover whole domain for M IODs, N modules, and L attributes. Also optionality of some fields complicates the task immensely at least with scalaz-seven.

What other viable approaches are available there that align with the spirit of Scala?

share|improve this question

1 Answer 1

You can nest lenses, so I don't think you'll have M x N x L lenses in total. I think that's a perfectly reasonable approach.

An alternate approach is to define your own single-entry update methods like so:

case class Patient(name: String, dateOfBirth: Long) {
  def name(f: String => String): Patient = copy(name = f(name))
  def dateOfBirth(f: Long => Long): Patient = copy(dateOfBirth = f(dateOfBirth))

which you use like so:

scala> Patient("John",0).name(_ + " Smith")
res1: Patient = Patient(John Smith,0)

This is sort of achievable with lenses, but you have to be very careful to avoid having drastically more boilerplate (in both usage and definition). It doesn't have the flexibility of lenses where you can arbitrarily pull apart capabilities (e.g. updating), but it makes up for it by being streamlined.

I do the majority of my deep updating this way:

myImage.patient(_.study(_.date(_ => Some(System.currentTimeMillis))))

is all you need to update the entire tree with a study with the current time (pretending here that DateTime is actually a Long), and if you really need to extract this capability of regenerating this paticular tree (which is more of a natural with lenses), you could

val setStudyTime = (t: Long) => myImage.patient(_.study(_.date(_ => Some(t))))

or even

def studyTimeSetter(si: SimpleImageIOD) =
  (t: Long) => si.patient(_.study(_.date(_ => Some(t))))

if you need to grab this capability easily at a moment's notice.

If you need everything that lenses offer you, it's more work to rebuild it in an ad-hoc way using this approach, but if you only need a small fraction and mostly just need to cut down on boilerplate for setting, this does a pretty good job.

share|improve this answer
What do you mean by "nesting lenses"? –  ak. Mar 23 '13 at 23:33
@ak. - Well, "compose" really. If you have something like Long => Patient and a Patient => SimpleImageIOD you can compose them to get a Long => SimpleImageIOD. You don't have to build every possibility; you can do it where you're using them. –  Rex Kerr Mar 23 '13 at 23:49
In terms of scalaz lenses you probably mean andThen rather than compose. I think compose applied to two lenses Long => Patient and String => Patient will produce a lens that does (Long, String) => Patient. But the point is not to nest lenses on the boilerplate, right? –  ak. Mar 24 '13 at 15:17
@ak. - I mean "compose" not compose in that it is equivalent to function composition in the mathematical sense. Anyway, the point is that except for those things you use all the time, nest when you use them, not in advance. This will avoid combinatorial explosion. –  Rex Kerr Mar 24 '13 at 15:21
nice! simple and slick. –  sourcedelica Mar 25 '13 at 14:18

Your Answer


