2

In my application I have use some "data" ValueCell (something like 20) and I would like to create a ValueCell which would be used to detect if any of my "data" ValueCell was updated . So I would like this cell to change whenever one of the other cells are changed.

Here is a simple code example

class StringFilter {

  val referenceList = "foo"::"bar"::"scala"::"lift"::Nil

  val length = ValueCell[Int](3)
  val content = ValueCell[String]("")

  //Here I put some functions to update length or prefix on my webpage
  def filter(s:String):Boolean = (s.length==length.get)&&(s.contains(content.get))

  val changed =ValueCell[???](???)
  val results= changed.lift(referenceList.filter)
}

What should I put instead of ???? I am also open to solutions which are not using ValueCells, even if I will in the end need some cells because I have to use WiringUI.

Edit: lengthand contentdon't need to be cells but they need to be settable

Edit: After some more research I came to an idea: implement a case class like SeqCellbut which would not take a type for the Cells in parameter, and for an arbitrary number of cells. Is it possible?
Here is the implementation of SeqCell:

final case class SeqCell[T](cells: Cell[T]*) extends Cell[Seq[T]] {

  cells.foreach(_.addDependent(this))

  /**
  * The cell's value and most recent change time
  */
  def currentValue: (Seq[T], Long) = {
    val tcv = cells.map(_.currentValue)
    tcv.map(_._1) -> tcv.foldLeft(0L)((max, c) => if (max > c._2) max else c._2)
  }

  /**
   * If the predicate cell changes, the Dependent will be notified
   */
  def predicateChanged(which: Cell[_]): Unit = notifyDependents()
}

Edit: In scala Cellis not covariant, so it seems like I won't be able to make a SeqCell out of my multiple typed cells. I would really appreciate a global solution for an arbitrary number of cells.

Community
  • 1
  • 1
Christopher Chiche
  • 15,075
  • 9
  • 59
  • 98

1 Answers1

1

Check out FuncCell. It's just another cell that will determine its value as a function of one or more other cells. The link I gave is the companion object which has apply methods for 1-5 cells, corresponding to the existing FuncCell1 .. FuncCell5 implementations. When one of those cells changes value, the FuncCell will update its own value- you would then hook up the WiringUI with your FuncCell.

Please forgive any syntax errors, I don't have an IDE open to check myself...

val changed: Cell[List[String]] = FuncCell(length, content){(len,con) =>
  def filter(s: String) = (s.length == len) && (s.contains(con))
  referenceList.filter(filter _)
}

If that's right, then changed is now a Cell whose value will reflect the result of calling referenceList.filter


In response to your edit regarding the SeqCell, I can think of two solutions:

1) Use Any as the type parameter in the SeqCell

val cell1: ValueCell[Int] = ...
val cell2: ValueCell[String] = ...
val cell3: ValueCell[Stuff] = ...
...
val combined: SeqCell[Any] = SeqCell(cell1, cell2, cell3, ...)
val results = FuncCell(combined){ seq: Seq[Any] => ... }

2) Combine the intermediate cells into tuples so that you can use the existing FuncCell implementations.

val intermediate1: Cell[(Int,String)] = 
  FuncCell(cell1,cell2){(a:Int, b:String) => a -> b}
val results = 
  FuncCell(intermediate1, cell3){(i: (Int, String), s: Stuff) => ...}
Dylan
  • 13,645
  • 3
  • 40
  • 67
  • thanks for your solution, I checked for that, however I couldn't manage to use this solution with an arbitrary number of cells, I found something called `SeqCell (cells: Cell[T]*)`but I don't know how to use it (in fact I don't know what the `*` means and as it is a * it is difficult to check for it on a search engine) – Christopher Chiche Jan 20 '12 at 20:00
  • 1
    The `*` means that you can input an arbitrary number of arguments, comma-separated, in place of the `cells` argument. I think you might get some better search results with "varArgs". The limitation of the `SeqCell` is that each cell must be the same type (the `T`). It may be a bit dirty, but you could always condense your arguments into Cells of Tuples. E.g. if you have a Cell[A], and Cell[B], you could combine them with `FuncCell(aCell, bCell){(a,b) => a->b}` – Dylan Jan 20 '12 at 20:49
  • That helps me a lot to understand how I can solve my problem. However I don't understand what you mean by "varArgs" and how to use them. Can you give me an example? – Christopher Chiche Jan 20 '12 at 21:21
  • 1
    An example: `def print(strs: String*) = for(str <- strs) println(str)`, and usage: `print("hi", "there", "buddy")`. – Dylan Jan 20 '12 at 22:06
  • I tried to find a way, i edited my question in consequence, even if I still don't have an answer thanks for your help – Christopher Chiche Jan 21 '12 at 19:24
  • Solution 1 doesn't work because Cell is not covariant. Solution 2 works well but it is still a pain to deal with different types of cells because of that covariant property. So, your answer is valid for my post but I will certainly ask another question to find a general solution to bypass `Cell` covariance. Thank you very much for your explanations, it helped me a lot to better understand my problem – Christopher Chiche Jan 22 '12 at 18:19