0

Could anyone suggest an efficient and succinct way of realizing the following feature of "remove on read"? That is, when the attribute _events is read, it's cleared.

case class Event(nanos: Long)

case class History() {
  private val _events = ArrayBuffer[Event]()
  def add(event: Event): Unit = _events += event
  
  def events: List[Event] = {
    val builder = ArrayBuffer[Event]()
    builder ++= _events
    _events.clear()
    builder.toList 
  }
}
Chema
  • 2,748
  • 2
  • 13
  • 24
Max Wong
  • 694
  • 10
  • 18

2 Answers2

3

Assuming you are not doing concurrency. You don't need to create a new ArrayBuffer. toList creates a new immutable List which will sustain when you clear. Just do

def events: List[Event] = {
  val res = _events.toList
  _events.clear()
  res
}
SwiftMango
  • 15,092
  • 13
  • 71
  • 136
1

You can use ConcurrentLinkedQueue of Java. The following solution supports concurrency, in a way that if you add objects, while retrieving the history, they will be added to the history, and to the result of the current call. However, they are read once in this solution. If you need to stop adding while retrieving the history, we can think about a different solution. Consider having the History class as follows:

case class History() {
  private val _events = new ConcurrentLinkedQueue[Event]()
  def add(event: Event): Unit = _events.add(event)

  def events: List[Event] = {
    if (_events.isEmpty) {
      List()
    } else {
      _events.poll() +: events
    }
  }
}

Then, when running the following code:

def main(args: Array[String]): Unit = {
  val h = History()
  List(
    Event(10),
    Event(20),
    Event(30)
  ).foreach(h.add)

  println(s"Events are: ${h.events.mkString(", ")}")
  println(s"Events are: ${h.events.mkString(", ")}")
}

The output is:

Events are: Event(10), Event(20), Event(30)
Events are: 

Process finished with exit code 0
Tomer Shetah
  • 8,413
  • 7
  • 27
  • 35
  • Maybe `_events.toArray(new Event[]).toList` instead of `_events.poll() +: events` would be more performant? – TeWu Aug 04 '20 at 05:21
  • I don't think it will be more performant. In both cases we need to access each elment once. The problem with your solution, is that if more elements were added at the time of creating the array, you will remove thenm when removing all elements. And you will never get those when calling the events method. – Tomer Shetah Aug 04 '20 at 05:24