Unable to understand Scala's type inference - scala

I was going through Learning Concurrency With Scala
It had a following piece of Code.
package week_parallel.week1.SC_Book
import scala.collection.mutable
object SyncPoolArgs extends App {
private val tasks = mutable.Queue[() => Unit]()
object Worker extends Thread {
setDaemon(true)
def poll() = tasks.synchronized {
while (tasks.isEmpty) tasks.wait()
tasks.dequeue()
}
override def run() = while (true) {
val task = poll()
task()
}
}
Worker.start()
def asynchronous(body: =>Unit) = tasks.synchronized {
tasks.enqueue(() => body)
tasks.notify()
}
def sum(x: Int, y:Int) = {println("USING SUM")
x+y}
asynchronous { log("Hello ") }
asynchronous { log("World!") }
asynchronous { sum(4,5) }
Thread.sleep(500)
}
So, my question is if we have tasks of type function that takes no arguments and returns nothing, why does tasks.enqueue(() => body) put sum in the queue, shouldn't it check that the body method signature is wrong in case of sum.
Also, I am particularly unable to grasp how does tasks.enqueue(() => body) confine to the private val tasks = mutable.Queue[() => Unit]() type?

I think you may be confused by the declaration
body: => Unit
This means that body is a pass-by-name parameter of type Unit. This does not mean that body is a function that returns Unit, which would be body: () => Unit.
"pass by name" means that the expression that is passed to body will not be evaluated until the value is required. When it is evaluated, it will return Unit.
Since body is of type Unit, the expression () => body has type () => Unit which is what is required.
In this case the actual value of body is sum(4,5) which is type Int, but Int is compatible with Unit so there is no error.

Related

MVar tryPut returns true and isEmpty also returns true

I wrote simple callback(handler) function which i pass to async api and i want to wait for result:
object Handlers {
val logger: Logger = Logger("Handlers")
implicit val cs: ContextShift[IO] =
IO.contextShift(ExecutionContext.Implicits.global)
class DefaultHandler[A] {
val response: IO[MVar[IO, A]] = MVar.empty[IO, A]
def onResult(obj: Any): Unit = {
obj match {
case obj: A =>
println(response.flatMap(_.tryPut(obj)).unsafeRunSync())
println(response.flatMap(_.isEmpty).unsafeRunSync())
case _ => logger.error("Wrong expected type")
}
}
def getResponse: A = {
response.flatMap(_.take).unsafeRunSync()
}
}
But for some reason both tryPut and isEmpty(when i'd manually call onResult method) returns true, therefore when i calling getResponse it sleeps forever.
This is the my test:
class HandlersTest extends FunSuite {
test("DefaultHandler.test") {
val handler = new DefaultHandler[Int]
handler.onResult(3)
val response = handler.getResponse
assert(response != 0)
}
}
Can somebody explain why tryPut returns true, but nothing puts. And what is the right way to use Mvar/channels in scala?
IO[X] means that you have the recipe to create some X. So on your example, yuo are putting in one MVar and then asking in another.
Here is how I would do it.
object Handlers {
trait DefaultHandler[A] {
def onResult(obj: Any): IO[Unit]
def getResponse: IO[A]
}
object DefaultHandler {
def apply[A : ClassTag]: IO[DefaultHandler[A]] =
MVar.empty[IO, A].map { response =>
new DefaultHandler[A] {
override def onResult(obj: Any): IO[Unit] = obj match {
case obj: A =>
for {
r1 <- response.tryPut(obj)
_ <- IO(println(r1))
r2 <- response.isEmpty
_ <- IO(println(r2))
} yield ()
case _ =>
IO(logger.error("Wrong expected type"))
}
override def getResponse: IO[A] =
response.take
}
}
}
}
The "unsafe" is sort of a hint, but every time you call unsafeRunSync, you should basically think of it as an entire new universe. Before you make the call, you can only describe instructions for what will happen, you can't actually change anything. During the call is when all the changes occur. Once the call completes, that universe is destroyed, and you can read the result but no longer change anything. What happens in one unsafeRunSync universe doesn't affect another.
You need to call it exactly once in your test code. That means your test code needs to look something like:
val test = for {
handler <- TestHandler.DefaultHandler[Int]
_ <- handler.onResult(3)
response <- handler.getResponse
} yield response
assert test.unsafeRunSync() == 3
Note this doesn't really buy you much over just using the MVar directly. I think you're trying to mix side effects inside IO and outside it, but that doesn't work. All the side effects need to be inside.

Handling errors in scala ZIO

I wanted to handle some exceptions in ZIO using catchAll or catchSome as the below :
object Test extends App {
def run(args: List[String]) =
myApp.fold(_ => 1, _ => 0)
val myApp =
for {
_ <- putStrLn(unsafeRun(toINT("3")).toString)
} yield ()
def toINT(s: String): IO[IOException, Int]= {
IO.succeed(s.toInt).map(v => v).catchAll(er =>IO.fail(er))
}
the code succeeded in case I passed a valid format number but it's unable to handle the exception in case I passed invalid format and idea ??
s.toInt gets evaluated outside of the IO monad. What happens is that you evaluate s.toInt first and try to pass the result of that to IO.succeed, but an exception has already been thrown before you can pass anything to IO.succeed. The name of succeed already basically says that you are sure that whatever you pass it is a plain value that cannot fail.
The docs suggest using Task.effect, IO.effect, or ZIO.effect for lifting an effect that can fail into ZIO.
Here is a program that worked for me:
val program =
for {
int <- toINT("3xyz")
_ <- putStrLn(int.toString)
} yield ()
def toINT(s: String): Task[Int] = {
ZIO.fromTry(Try(s.toInt))
}
rt.unsafeRun(program.catchAll(t => putStrLn(t.getMessage)))

How to pass method of String as callable parameter?

Assume I have a function like:
private def throwUnlessValid[T](func: (String => T)): T = {
try {
func()
} catch {
case _: Throwable => throw new Error(s"""string: "${s}" is not a numeric""")
}
}
And I want to call it like:
implicit val intParser: TryParser[Int] = (s: String) => {
s.trim.isEmpty match {
case true => 0
case false => throwUnlessValid[Int](s.toInt)
}
}
This will fail as the result of s.toInt, which is the Int. Even though I want to pass in the callable function to be called in the other method.
How can I achieve this?
The syntax is _.toInt, which is a shorthand for s => s.toInt (or without type inference, (s: String) => s.toInt). Generally, search for "scala lambdas" for a lot more information on this.
But the problem is that you call func() without passing a string to it. There's also s in throw new Error(s"""string: "${s}" is not a numeric"""); if s is in your scope, you should have func(s) instead. Or maybe you want
private def throwUnlessValid[T](func: () => T): T = { ... }
throwUnlessValid(() => s.toInt)
Using by-name parameters, you can even write
private def throwUnlessValid[T](func: => T): T = { ... }
throwUnlessValid(s.toInt)
You can pass a callable function by using _.toInt, which is shorthand for the function x => x.toInt.
However this isn't going to help because your throwUnlessValid function doesn't work, for two reasons:
You don't give a String argument to func
You attempt to print s which is not a visible to this function
You have two choices:
Pass s to throwUnlessValid and give it to func
Make func into a => T parameter and remove the references to s from the Error string.
You need to fix your throwUnlessValid function.
Currently it accepts as argument a function which takes a string as argument:
throwUnlessValid[T](func: (String => T))
However then you are trying to call it without any argument: func() which obviously won't work. Besides that you also have reference to nonexisting variable s: ${s} which also should produce error.
In order to fix the throwUnlessValid function you can pass toInt as by-name argument:
private def throwUnlessValid[T](code: => T): T = {
try {
code
} catch {
case ex: Throwable => throw new Error(s"""string: "${ex.getMessage}" is not a numeric""")
}
}
In other words you don't need to change your existing intParser implementation (including throwUnlessValid[Int](s.toInt) call), you only need to change implementation of throwUnlessValid).
If i understant correctly, you are looking for this.
Actually the problem is that you are not passing string to your function (func) hence it's not working.
import scala.util.{Failure, Success, Try}
object Solution1 extends App {
private def throwUnlessValid[T](func: (String => T)): T = {
Try {
func("1")
} match {
case Success(_) => //do Something which return T
case Failure(ex) => throw new Error(s"""string: "${ex}" is not a numeric""")
}
}
implicit val intParser: String => Int = (s: String) => {
if (s.trim.isEmpty) {
0
} else {
throwUnlessValid[Int](_ => s.toInt)
}
}
}

How to pass a code block to function?

I am trying to create a try clause analogue which repeats code block if exception occurred inside this code block.
def retry(attempts: Int)(func: Unit => Unit) {
var attempt = 0
while (attempt < attempts) {
attempt += 1
try {
func()
} catch {
case _: Throwable =>
}
}
throw new Exception()
}
I expect that it can be used like this
retry(10) { // I would like to pass this block as function
val res = someNotReliableOp(); // <- exception may occur here
print(res)
}
But it doesn't work:
Operations.scala:27: error: type mismatch;
found : Unit
required: Unit => Unit
print(res)
^
one error found
What is the most concise way to pass custom block to my function?
You just need to change your method definition a tiny bit:
def retry(attempts: Int)(func: => Unit)
Unit => Unit means: a function that takes a parameter with a type of Unit and evaluates to Unit.
=> Unit means: a function that takes no parameters and evaluates to Unit. This is called call by name.
Consider
def retry(attempts: Int)(func: => Unit) {
for {
i <- Stream range (0, attempts)
v = Try (func()) toOption
if (v == None)
} ()
}
The for comprehension will invoke func up to an attempts number of times and will stop streaming if the invocation to func succeeds, namely if Try(func) toOption does not deliver None.
For each iteration in the for comprehension, the do-nothing () function is called.
If interested in details on each failure for func, consider replacing the Try in the comprehension with
v = Try(func()) match {
case Success(x) => Some(())
case Failure(x) => println(x) ; None
}
which preserves the semantics initially suggested, yet it extracts information on each failed attempt.

Why is a return statement required to allow this while statement to be evaluated properly?

Why is a return statement required to allow this while statement to be
evaluated properly? The following statement allows
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.io.BufferedReader
import java.io.InputStreamReader
trait Closeable {
def close ()
}
trait ManagedCloseable extends Closeable {
def use (code: () => Unit) {
try {
code()
}
finally {
this.close()
}
}
}
class CloseableInputStream (stream: InputStream)
extends InputStream with ManagedCloseable {
def read = stream.read
}
object autoclose extends App {
implicit def inputStreamToClosable (stream: InputStream):
CloseableInputStream = new CloseableInputStream(stream)
override
def main (args: Array[String]) {
val test = new FileInputStream(new File("test.txt"))
test use {
val reader = new BufferedReader(new InputStreamReader(test))
var input: String = reader.readLine
while (input != null) {
println(input)
input = reader.readLine
}
}
}
}
This produces the following error from scalac:
autoclose.scala:40: error: type mismatch;
found : Unit
required: () => Unit
while (input != null) {
^
one error found
It appears that it's attempting to treat the block following the use as an
inline statement rather than a lambda, but I'm not exactly sure why. Adding
return after the while alleviates the error:
test use {
val reader = new BufferedReader(new InputStreamReader(test))
var input: String = reader.readLine
while (input != null) {
println(input)
input = reader.readLine
}
return
}
And the application runs as expected. Can anyone describe to me what is going
on there exactly? This seems as though it should be a bug. It's been
persistent across many versions of Scala though (tested 2.8.0, 2.9.0, 2.9.1)
That's because it's use is declared as () => Unit, so the compiler expects the block you are giving use to return something that satisfies this signature.
It seems that what you want is to turn the entire block into a by-name parameter, to do so change def use (code : () => Unit) to def use (code : => Unit).
() => Unit is the type of a Function0 object, and you've required the use expression to be of that type, which it obviously isn't. => Unit is a by name parameter, which you should use instead.
You might find my answer to this question useful.
To go the heart of the matter, blocks are not lambdas. A block in Scala is a scope delimiter, nothing more.
If you had written
test use { () =>
val reader = new BufferedReader(new InputStreamReader(test))
var input: String = reader.readLine
while (input != null) {
println(input)
input = reader.readLine
}
}
Then you'd have a function (indicated by () =>) which is delimited by the block.
If use had been declared as
def use (code: => Unit) {
Then the syntax you used would work, but not because of any lambda thingy. That syntax indicates the parameter is passed by name, which, roughly speaking, means you'd take the whole expression passed as parameter (ie, the whole block), and substitute it for code inside the body of use. The type of code would be Unit, not a function, but the parameter would not be passed by value.
return or return expr has the type Nothing. You can substitute this for any type, as it never yields a value to the surrounding expression, instead it returns control to the caller.
In your program, it masquerades as the required type () => Unit.
Here's an occasionally convenient use for that (although you might be tarnished as unidiomatic if you use it too often, don't tell anyone you heard this from me!)
def foo(a: Option[Int]): Int = {
val aa: Int = a.getOrElse(return 0)
aa * 2
}
For the record, you should probably write:
def foo(a: Option[Int]): Int =
a.map(_ * 2).getOrElse(0)
You can get an insight into the mind of the compiler by checking the output of scala -Xprint:typer -e <one-liner>. Add -Ytyper-debug if you like sifting through the reams of output!
scala210 -Ytyper-debug -Xprint:typer -e 'def foo: Any = {val x: () => Any = { return }}'
... elided ...
typed return (): Nothing
adapted return (): Nothing to () => Any,