Pergunta

I am currently trying to find my way into the world of Scala. Actually I am trying to implement a Round Robin strategy without mutable types.

I have an Scala Object with an initial list of hosts and a method to get the next host.

Object RoundRobin { 
  val optHosts: Option[List[String]] = Option[List[String]]("host1", "host2") // get from Configfile later
  var hosts: List[String] = optHosts.getOrElse(List())

  def url: String = {
    hosts = hosts.tail ++ List(hosts.head)
    hosts(0)
  }

  def execute = ??? // do something with the next host

}

I have read about immutable Queues in Scala but I don't really know how to solve this problem with immutable types. Somehow I would have to remember an index right? Is that one of the cases where it doesn't make sense to use immutable types?

Foi útil?

Solução

If I understand correctly every time you call execute on the object, it shall use a different element. Then because the object has to encapsulate state, so there's no way around the var

var hosts = collection.immutable.Queue ++ optHosts.getOrElse(List())
def url: String = {
   val(element,queue) = hosts.pop
   hosts = queue.enqueue(element)
   element
}

Regarding your questions...

Somehow I would have to remember an index right?

Yes, see above. But also no, see below.

Is that one of the cases where it doesn't make sense to use immutable types?

Depends. If you want to keep your object RoundRobin then clearly, that object is mutable, and you so you only have the choice between mutable vals and immutable vars. (well you could also have vars that point to mutable structures, but why would you do that?)

On the other hand you can also opt for a totally different approach:

class RoundRobin private(left: List[String], all: List[String]) {
   def this(all :List[String]) = this(all, all)
   assume(all.nonEmpty)
   val theElement = left.headOption.getOrElse(all.head)
   def nextRoundRobin = new RoundRobin(if(left.nonEmpty) left.tail else all, all) 
   def execute = {
       // do something with theElement
       println(theElement)
       // return an object that will execute on the next element
       nextRoundRobin
   }
 }

 new RoundRobin(List("1","2")).execute.execute.execute
 // prints 1 2 1

When you use this version of RoundRobin, every time you call execute it will give you a round robin object that will use the next element in round-robin fashion. Clearly the object using RoundRobin can again either be mutable or immutable.

Outras dicas

Made a slight change so that the class will now round robin alternately when executing more than three times as in the example supplied.

 class RoundRobin private(left: List[String], all: List[String]) {
      def this(all :List[String]) = this(all, all)
      assume(all.nonEmpty)
      val theElement = left.headOption.getOrElse(all.head)
      def nextRoundRobin = new RoundRobin(if(left.nonEmpty) left.tail else all.tail, all)
      def execute = {
        // do something with theElement
        println(theElement)
        // return an object that will execute on the next element
        nextRoundRobin
      }
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top