1

I have a pseudo-code like shown below. The ItemChurner.churn() is abstracted component which generates objects until x times, where x is unknown. :

def func: MyList = {

    var list: MyList = MyList()

    while(ItemChurner.canChurn) {
        list = new MyList(ItemChurner.churn(), list)
    }

    list
}

Is there a way to avoid use of var?

3
  • 1
    you can implement Iterator interface like val iterator = new Iterator {def hasNext = ItemChurner.canChurn; def next = ItemChurner.churn() , and then iterator.toList Commented Sep 11, 2016 at 8:16
  • 1
    Why are you wrapping the inside of the while loop with a try-catch? Shouldn't ItemChurner return false if there aren't anymore elements? Commented Sep 11, 2016 at 8:21
  • @YuvalItzchakov: right. Corrected the snippet. Commented Sep 11, 2016 at 8:26

3 Answers 3

4

If canChurn works as it should:

def func(churner: ItemChurner) = {
  val iterator = new Iterator {
    def hasNext = churner.canChurn
    def next = churner.churn()
  }
  iterator.toList
}

About version (of the question) that contained catched exception check for churn():

If really expect some exceptions, what's the point of canChurn then?

Anyway, if you care about exceptions:

 Iterator.continually(Try(churner.churn)).takeWhile(_.isSuccess).map(_.get).toList

This actually is not much precise, as churn might throw some other exception that has to be propagated, so here the scala's Exception helpers) come in hand:

def step = catching(classOf[NoMoreElementsException]) opt churner.churn()
Iterator.continually(step).takeWhile(_.nonEmpty).map(_.get).toList
Sign up to request clarification or add additional context in comments.

3 Comments

@dk12, yes. Just realized that if I have canChurn, there is no need to catch exceptions. Thanks for pointing out. Question updated.
@dk12 I think Iterator.continually(if (churner.canChurn) Some(churner.churn()) else None).takeWhile(_.isEmpty).map(_.get).toList is a better choice as it relies only on the exposed part of churner capabilities.
@SarveshKumarSingh it depends. Catching an exception inside Try might be slower, besides code that actually checks for exact exception that signalizes about no more elements is less elegant (might require Exception helpers)
4

If you want to do using Simple recursion and avoid var. This is the general strategy used in functional programming.

Use Vector instead of List for effective append

def func[T](): List[T] = {

  @tailrec
  def helper(result: List[T]): List[T] = {
    if (ItemChurner.canChurn) helper(result ++ List(ItemChurner.churn))
    else result
  }

  helper(List.Empty[T])
}

Assuming ItemChurner.canChurn does not throw any exception. if it throws exceptions simply wrap it inside Try

2 Comments

about effectiveness, List seems to not be a best choice here as List ++ List has linear complexity. Vector has effectively constant append
@dk14 you are absolutely correct. thanks. edited the ans .
0

Improving upon pamu's answer, you can do something on the lines of;

def func: MyList = {
  def process(cur: MyList): MyList = {
    if (ItemChurner.canChurn) process(new MyList(ItemChurner.churn(), cur))
    else cur
  }
  process(new MyList())
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.