60

I find myself writing code like this when I want to repeat some execution n times:

for (i <- 1 to n) { doSomething() }

I'm looking for a shorter syntax like this:

n.times(doSomething())

Does something like this exist in Scala already?

EDIT

I thought about using Range's foreach() method, but then the block needs to take a parameter which it never uses.

(1 to n).foreach(ignored => doSomething())
5
  • 3
    Saving 5-6 characters of typing at the cost of requiring readers of your code to understand your personal DSL? I think it's a mistake. Commented May 16, 2010 at 11:06
  • 3
    You can minimize the ignored stuff: 1 to n foreach(_ => doSomething()) Commented May 16, 2010 at 11:32
  • 5
    @Paul It shouldn't be a personal DSL really. A method called times() on numbers is very common in other languages. Commented May 16, 2010 at 14:52
  • 2
    Why would you want to call doSomething() more than once? It's always going to return the same Unit. ;) Commented Mar 31, 2011 at 14:19
  • 1
    So the short answer to the question is: no. Commented Apr 3, 2016 at 7:58

6 Answers 6

56

You could easily define one as an extension method:

scala> implicit def intWithTimes(n: Int) = new {        
     |   def times(f: => Unit) = 1 to n foreach {_ => f}
     | }
intWithTimes: (n: Int)java.lang.Object{def times(f: => Unit): Unit}

scala> 5 times {
     |   println("Hello World")
     | }
Hello World
Hello World
Hello World
Hello World
Hello World
Sign up to request clarification or add additional context in comments.

4 Comments

I would love to have "times" added to RichInt.
It was actually added (lampsvn.epfl.ch/trac/scala/changeset/18599/scala/trunk/src/…), but shortly after removed (lampsvn.epfl.ch/trac/scala/changeset/18648/scala/trunk/src/…). Quoth extempore: "It was the best of times... it was the reversion of times...". Adding stuff to the standard library can break existing code, it has to be done fairly cautiously.
That is really interesting. Is 2.8 not already breaking backwards compatibility? I think in that case someone missed the opportunity to add such a method. It boils down to people writing that code over and over again because there is a usecase for it. You could just name it different like "5 iterationsOf x" or "5 repetitionsOf x".
Joa: you may google up much discussion, including this precise idea.
46

The Range class has a foreach method on it that I think is just what you need. For example, this:

 (1 to 5).foreach(println)

produces

1
2
3
4
5

2 Comments

Alternatively: 7 to 11 foreach { println(_) }
0 to 5 foreach println looks cleaner.
22

With scalaz 5:

doSomething.replicateM[List](n)

With scalaz 6:

n times doSomething

And that works as you would expect with most types (more precisely, for every monoid):

scala> import scalaz._; import Scalaz._; import effects._;
import scalaz._
import Scalaz._
import effects._

scala> 5 times "foo"
res0: java.lang.String = foofoofoofoofoo

scala> 5 times List(1,2)
res1: List[Int] = List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)

scala> 5 times 10
res2: Int = 50

scala> 5 times ((x: Int) => x + 1).endo
res3: scalaz.Endo[Int] = <function1>

scala> res3(10)
res4: Int = 15

scala> 5 times putStrLn("Hello, World!")
res5: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon$2@36659c23

scala> res5.unsafePerformIO
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!

You could also say doSomething replicateM_ 5 which only works if your doSomething is an idiomatic value (see Applicative). It has better type-safety, since you can do this:

scala> putStrLn("Foo") replicateM_ 5
res6: scalaz.effects.IO[Unit] = scalaz.effects.IO$$anon$2@8fe8ee7

but not this:

scala> { System.exit(0) } replicateM_ 5
<console>:15: error: value replicateM_ is not a member of Unit

Let me see you pull that off in Ruby.

10 Comments

Very cool... I didn't know scalaz had an IO monad... in practice do you find this to be worth the effort in scala?
It looks like 5 times 10 is arbitrarily choosing to sequence using the (0,+) monoid, which makes sense since in english we interpret "5 times 10" to mean 50... could you override it to use (1,*) and get exponentiation?
pelotom: To get 2^24, you might write: 24 times (2 ∏)
I'm doing a bit of IO these days, and I do it in a monad.
@Apocalisp I don't always do IO, but when I do, I do it in a monad
|
5

I'm not aware of anything in the library. You can define a utility implicit conversion and class that you can import as needed.

class TimesRepeat(n:Int) {
  def timesRepeat(block: => Unit): Unit = (1 to n) foreach { i => block }
}
object TimesRepeat {
  implicit def toTimesRepeat(n:Int) = new TimesRepeat(n)
}

import TimesRepeat._

3.timesRepeat(println("foo"))

Rahul just posted a similar answer while I was writing this...

Comments

2

It can be as simple as this:

scala> def times(n:Int)( code: => Unit ) {
          for (i <- 1 to n) code
       }
times: (n: Int)(code: => Unit)Unit

scala> times(5) {println("here")}
here
here
here
here
here

Comments

0
def times(f: => Unit)(cnt:Int) :Unit = {
  List.fill(cnt){f}
}

1 Comment

Although the code might solve the problem, a good answer should also explain what the code does and how it helps.

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.