Implicit conversion to Runnable?
Solution 1
arg, just answered my own question. I implemented the implicit conversion incorrectly. The correct implementation is
implicit def funToRunnable(fun: () => Unit) = new Runnable() { def run() = fun() }
and you call it like this:
save(() => print("2"))
This will yield "2"
Solution 2
If you wanted to live dangerously, you could convert anything to a runnable:
implicit def whateverToRunnable[F](f: => F) = new Runnable() { def run() { f } }
scala> val t = new Thread(println("Hello"))
t: java.lang.Thread = Thread[Thread-2,5,main]
scala> t.start()
Hello
Or you could create your own thread-creator-and-starter:
def thread[F](f: => F) = (new Thread( new Runnable() { def run() { f } } )).start
scala> thread { println("Hi"); Thread.sleep(1000); println("Still here!") }
Hi
scala> Still here!
If you wanted to return the thread, then
def thread[F](f: => F) = {
val t = new Thread( new Runnable() { def run() { f } } )
t.start()
t
}
But all of this, while useful, is perhaps even less useful than scala.actors.Futures
(tested only on 2.8):
scala> import scala.actors.Futures
scala> val x = Futures.future { Thread.sleep(10000); "Done!" }
x: scala.actors.Future[java.lang.String] = <function0>
scala> x.isSet
res0: Boolean = false
scala> x.isSet
res1: Boolean = false
scala> x() // Waits until the result is ready....
res2: java.lang.String = Done!
Solution 3
Actually, you can do it even nicer with call-by-name argument:
implicit def runnable(f: => Unit): Runnable = new Runnable() { def run() = f }
Usage:
import concurrent.ExecutionContext.Implicits.global._
execute(print("hello"))
Solution 4
Interesting, this way you can execute code that receives a Runnable
and pass it a closure.
See:
scala> new Thread( () => print( "Hello" ) ).start()
<console>:5: error: overloaded method constructor Thread with alternatives (java.lang.ThreadGroup,java.lang.Runnable,java.lang.String,Long)java.lang.Thread <and> (java.lang.ThreadGroup,java.lang.Runnable,java.lang.String)java.lang.Thread <and> (java.lang.Runnable,java.lang.String)java.lang.Thread <and> (java.lang.ThreadGroup,java.lang.String)java.lang.Thread <and> (java.lang.String)ja...
new Thread( () => print( "Hello" ) ).start()
scala> implicit def funcToRunnable( func : () => Unit ) = new Runnable(){ def run() = func() }
funcToRunnable: (() => Unit)java.lang.Object with java.lang.Runnable
scala> def doRun( runnable: Runnable ) = runnable.run
doRun: (Runnable)Unit
scala> doRun( () => print("Hola"))
Hola
scala> new Thread(()=>print("Hello")).start()
scala> Hello
Comments
-
Patrick Arnesen almost 2 years
As an exercise, I tried to create an implicit conversion that would accept a function and produce a
Runnable
. That way you could call Java methods that acceptRunnable
objects and use them like closures.The implicit conversion is easy enough:
implicit def funToRunnable(fun : Unit) = new Runnable() { def run = fun }
However I don't know how to call it. How do you pass in a no-arg function that returns Unit, without having it be evaluated at once? For example, I'd like the following to print "12" but instead it prints "21" because
print("2")
is evaluated at once.var savedFun : Runnable = null def save(r : Runnable) = { savedFun = r } save(print("2")) print("1") savedFun.run()
How do I tell the compiler to treat
print("2")
as the body of a function, not something to be evaluated at once? Some possibilities I tried, such assave(() => print("2"))
or
save(=> print("2"))
are not legal syntax.
-
OscarRyz almost 14 yearsI was on the same track. Do you have any idea on why
def run = run
doesn't work? -
Randall Schulz almost 14 years
def run = run
will always be an infinite recursion. Even if there's arun
defined in an enclosing scope, the one defined by thisdef
will shadow it, guaranteeing a direct, unconditional recursive call. -
OscarRyz almost 14 yearsI meant
def run = fun
without parens -
Ken Bloom almost 14 years@Support because fun without parentheses just creates a method that returns the function that was passed. To call a function type, you have to use parentheses, otherwise you're just returning the funciton itself.
-
Martin almost 12 yearsRunnable is not only used to run stuff in a newly Threads. For example in GUI development it is used to run stuff on the special UI thread.
-
David Frank over 10 yearsShouldnt it yield 2 instead of 12?