blue-sky
blue-sky

Reputation: 53866

Is this a pure function in Scala

Below function getRandomString generates a random String from a List of characters :

  def genRandomInt(lb: Int, ub: Int) = {
    val rnd = new scala.util.Random
    lb + rnd.nextInt(ub)
  }     
  def getRandomString(validChars: List[Char]) = {

    val size = validChars.size

    val random = new scala.util.Random
    val stringBuilder = new StringBuilder
    val rnd = genRandomInt(0, size)
    val sb = new StringBuilder

    for (i <- 0 to size - 1) {
      val rnd = genRandomInt(0, size)
      sb.append(validChars(rnd))
    }

    sb.toString
  }                                               //> getRandomString: (validChars: List[Char])String

    val rs = getRandomString(('a' to 'j').toList)
                                                  //> rs  : String = aghdjjhjge

Is getRandomString an example of a pure function as it does not modify state ?

Upvotes: 6

Views: 838

Answers (2)

samthebest
samthebest

Reputation: 31533

No because new scala.util.Random().nextInt ... returns something different each time, which is cogently explained by Imm.

Nevertheless you can simply pass in a seed then it will be a pure function because it will return the same random string every time. You could add the seed as a parameter or just fix it inside the random string method.

Finally, I've noticed you have written a huge amount of code to generate a random String. I suggest you look at ScalaCheck which has stacks of useful functions for generating random stuff (for unit tests), String comes out-of-box.

If you don't want to pull in a library, you can still make that code much more concise:

def randomString(fromChars: List[Char], length: Int): String = {
  val rand = new Random(1234) // Now it's pure functional because the seed is fixed
  val fromCharsSize = fromChars.size // to save us repeatedly counting
  List.fill(length)(fromChars(rand.nextInt(fromCharsSize))).mkString
}

Observe it returns same value every time

scala> randomString("asdf".toList, 10)
res0: String = dsfafssdsa

scala> randomString("asdf".toList, 10)
res1: String = dsfafssdsa

Upvotes: 2

lmm
lmm

Reputation: 17431

No, because it does in fact modify state. new scala.util.Random ultimately invokes new java.util.Random, which accesses and modifies a static (i.e. global), mutable AtomicLong called seedUniquifier. And therefore if this method is called multiple times then the result will change.

This is a good example of how innocent-seeming methods can hide accesses to global mutable state, which would be forbidden in a stricter functional language like Haskell (though that approach comes with its own problems).

Upvotes: 9

Related Questions