I've got a question that concerns scoping in scala. I have a function like this:
def getElements(id: Int): Seq[Element] = {
var test = ""
dto.getElementIds(id).map {
elementIds => {
test += " hello "
elementIds.foreach(elementId => dto.getElement(elementId).map {
case Some(element) => test += " hi "
println("ThirdPrint: " + test)
})
println("SecondPrint: " + test)
}
}
println("FirstPrint: " + test)
}
Lets say "elementsIds" has a lenght of 2.
The console says:
FirstPrint:
SecondPrint: hello
ThirdPrint: hello hi
ThirdPrint: hello hi hi
Why is scala doing that? I would assume that third print is executed first. By the time I get to the "FirstPrint" the "hi"'s are gone. Why is the last line of code executed first?
I'm working with slick and Futures, does this have something to do with it? Thanks!
UPDATE
Thanks, works fine.
Is it possible to return a seq instead? Like this:
def getElements(id: Int): Future[Seq[Element]] = {
var mySequence: Seq[Element] = Seq()
val elementsIds: Future[Seq[Int]] = dto.getElementIds(id)
var test = ""
val elementsF = elementsIds.flatMap {
elementIds => {
test += " hello "
val idsAsElements: Seq[Future[Element]] = elementIds.map(elementId => dto.getElement(elementId).collect {
case Some(element) => mySequence = mySequence :+ element
})
val idsAsElementsF: Future[Seq[Element]] = Future.sequence(idsAsElements)
idsAsElementsF.onComplete(_ => println("SecondPrint: " + test))
idsAsElementsF
}
}
elementsF.onComplete(_ => println("FirstPrint: " + test))
elementsF
}
Is it possible to return "mySequence" whenever idsAsElements is "onComplete"?
object X {
import scala.concurrent.ExecutionContext.Implicits.global
case class Element()
object dto{
def getElementIds(i: Int): Future[Seq[Int]] = Future(Seq(1,2,3))
def getElement(i: Int): Future[Option[Element]] = Future(Some(Element()))
}
def main(args: Array[String]): Unit = {
getElements(0)
Thread.sleep(10000) // waiting logs
}
def getElements(id: Int): Future[Seq[Element]] = {
val elementsIds: Future[Seq[Int]] = dto.getElementIds(id)
var test = ""
val elementsF = elementsIds.flatMap {
elementIds => {
test += " hello "
val idsAsElements: Seq[Future[Element]] = elementIds.map(elementId => dto.getElement(elementId).collect {
case Some(element) => test += " hi "
println("ThirdPrint: " + test)
element
})
val idsAsElementsF: Future[Seq[Element]] = Future.sequence(idsAsElements)
idsAsElementsF.onComplete(_ => println("SecondPrint: " + test))
idsAsElementsF
}
}
elementsF.onComplete(_ => println("FirstPrint: " + test))
elementsF
}
}
output:
ThirdPrint: hello hi
ThirdPrint: hello hi hi
ThirdPrint: hello hi hi hi
SecondPrint: hello hi hi hi
FirstPrint: hello hi hi hi
Yes, that's not a good solution. You should avoid blocking in your code, except, maybe at the highest possible level (main method). Also, mutable state is bad, especially, when combined with concurrency (futures).
Your function should return a Future. Something like this will work (I am not sure if I guess the intent of your code correctly - your function was declared to return Seq[Element], but written to return a Unit ... I assume, that what you really wanted to return was the result of getElement calls for every id):
def getElements(id: Int): Future[Seq[Element]] = dto
.getElementIds(id)
.map { ids => ids.map(dto.getElement) }
.flatMap(Future.sequence)
.map(_.flatten)
I removed your printouts, because wasn't sure what was the purpose they serve (since the calls to dto.getElement are also happening in parallel, it is not obvious where and in which order you want those strings printed).
You could simulate your "expected output", by adding another transformation at the end for example:
.andThen { case Success(results) =>
val str = results.foldLeft("hello") { case (a,b) =>
println("ThirdPrint: " + a + " hi")
a + " hi"
}
println("SecondPrint: " + str)
println("FirstPrint: " + str
}
Related
Trying to execute a function in a given time frame, but if computation fails by TimeOut get a partial result instead of an empty exception.
The attached code solves it.
The timedRun function is from Computation with time limit
Any better approach?.
package ga
object Ga extends App {
//this is the ugly...
var bestResult = "best result";
try {
val result = timedRun(150)(bestEffort())
} catch {
case e: Exception =>
print ("timed at = ")
}
println(bestResult)
//dummy function
def bestEffort(): String = {
var res = 0
for (i <- 0 until 100000) {
res = i
bestResult = s" $res"
}
" " + res
}
//This is the elegant part from stackoverflow gruenewa
#throws(classOf[java.util.concurrent.TimeoutException])
def timedRun[F](timeout: Long)(f: => F): F = {
import java.util.concurrent.{ Callable, FutureTask, TimeUnit }
val task = new FutureTask(new Callable[F]() {
def call() = f
})
new Thread(task).start()
task.get(timeout, TimeUnit.MILLISECONDS)
}
}
I would introduce a small intermediate class for more explicitly communicating the partial results between threads. That way you don't have to modify non-local state in any surprising ways. Then you can also just catch the exception within the timedRun method:
class Result[A](var result: A)
val result = timedRun(150)("best result")(bestEffort)
println(result)
//dummy function
def bestEffort(r: Result[String]): Unit = {
var res = 0
for (i <- 0 until 100000) {
res = i
r.result = s" $res"
}
r.result = " " + res
}
def timedRun[A](timeout: Long)(initial: A)(f: Result[A] => _): A = {
import java.util.concurrent.{ Callable, FutureTask, TimeUnit }
val result = new Result(initial)
val task = new FutureTask(new Callable[A]() {
def call() = { f(result); result.result }
})
new Thread(task).start()
try {
task.get(timeout, TimeUnit.MILLISECONDS)
} catch {
case e: java.util.concurrent.TimeoutException => result.result
}
}
It's admittedly a bit awkward since you don't usually have the "return value" of a function passed in as a parameter. But I think it's the least-radical modification of your code that makes sense. You could also consider modeling your computation as something that returns a Stream or Iterator of partial results, and then essentially do .takeWhile(notTimedOut).last. But how feasible that is really depends on the actual computation.
First, you need to use one of the solution to recover after the future timed out which are unfortunately not built-in in Scala:
See: Scala Futures - built in timeout?
For example:
def withTimeout[T](fut:Future[T])(implicit ec:ExecutionContext, after:Duration) = {
val prom = Promise[T]()
val timeout = TimeoutScheduler.scheduleTimeout(prom, after)
val combinedFut = Future.firstCompletedOf(List(fut, prom.future))
fut onComplete{case result => timeout.cancel()}
combinedFut
}
Then it is easy:
var bestResult = "best result"
val expensiveFunction = Future {
var res = 0
for (i <- 0 until 10000) {
Thread.sleep(10)
res = i
bestResult = s" $res"
}
" " + res
}
val timeoutFuture = withTimeout(expensiveFunction) recover {
case _: TimeoutException => bestResult
}
println(Await.result(timeoutFuture, 1 seconds))
I have created a console-interface application as todo-list in Scala. My data access layer works with Slick 3 and my interface works using simple StdIn methods. But I have some troubles with reading lines. My main menu works fine while inner menu acts weirdly sometimes. In particular, when I enter a command for the first time I do not get any result just the same menu is displayed again. Then I enter any command and I get the result. And if I try to enter some command for the 3d time my program just stops with System.exit.
Here is the code for my interface:
object UserInterface {
def displayMainMenu(): Unit ={
println("Main menu:" + " \n1 - Login" + "\n2 - Exit")
println("\nChoose the operation you want to perform:")
val inputMainMenu = readInt()
buildMainMenu(inputMainMenu)
}
def buildMainMenu(inputNumber: Int) = inputNumber match {
case 1 => enterSystem()
case 2 => System.exit(0)
case _ => println("Your input was wrong. Try again"); displayMainMenu()
}
def enterSystem(): Unit ={
println("Input you login, please:")
val inputLogin = readLine()
println("Input you password, please:")
val inputPassword = readLine()
val checkLogin = Await.result(DAO.checkUserLogin(inputLogin, inputPassword), Duration.Inf).toString
val userId = DAO.selectUserId(inputLogin)
def changeOutputs(checkLogin: String):Unit = checkLogin match {
case "true" => println("You have successfully entered"); displayInnerMenu(); buildMenu(userId)
case "false" => println("Your input for login or password is wrong. Please, try again"); displayMainMenu()
case _ => println("Your input is wrong"); displayMainMenu()
}
changeOutputs(checkLogin)
}
def buildMenu(userId: Long): Unit ={
def chooseOption(number: Int):Unit = number match {
case 1 => displayFinishedTasks(userId)
case 2 => displayUnfinishedTasks(userId)
case 3 => addTask(userId)
case 4 => deleteTask()
case 5 => markTaskAsFinished(userId)
case 6 => displayMainMenu()
case _ => println("Your input is wrong"); displayMainMenu()
}
val inputNum = displayInnerMenu()
chooseOption(inputNum)
}
def displayInnerMenu():Int ={
println("TODO List:" + "\n1 - Display finished tasks" + "\n2 - Display unfinished tasks"
+ "\n3 - Add task" + "\n4 - Delete task" + "\n5 - Mark task as finished" + "\n6 - Get back to the main menu")
println("\nChoose the operation you want to perform:")
val inputNum = readInt()
inputNum
}
def displayAllTasks(id: Long) = {
println()
println("User's tasks:\n" + Await.result(DAO.selectTasksByUser(id), Duration.Inf).toList.toString)
displayInnerMenu()
}
def displayFinishedTasks(id: Long) = {
println()
println("User's finished tasks:\n" + Await.result(DAO.selectFinishedTasks(id), Duration.Inf).toList.toString)
displayInnerMenu()
}
def displayUnfinishedTasks(id: Long) = {
println()
println("User's unfinished tasks:\n" + Await.result(DAO.selectUnfinishedTasks(id), Duration.Inf).toList.toString)
displayInnerMenu()
}
def addTask(id: Long) = {
println()
println("Input the task name you want to create, please:")
val taskName = readLine()
Await.result(DAO.addTask(taskName, id), Duration.Inf)
displayInnerMenu()
}
def deleteTask() = {
println()
println("Choose the task you want to delete, please:")
val taskId = readLong()
Await.result(DAO.deleteTask(Some(taskId)), Duration.Inf)
displayInnerMenu()
}
def markTaskAsFinished(id: Long) = {
println()
println("Choose the task you want to mark as finished, please:")
val taskId = readLong()
Await.result(DAO.finishTask(Some(taskId), id), Duration.Inf)
displayInnerMenu()
}
}
What I want is some kind of infinite cycle so I could perform my commands as many times as I need or set the limit. So what changes I can introduce in this code? I would be very grateful for some help!
Your particular troubles seem to come from the fact that changeOutputs in
enterSystem calls displayInnerMenu which reads an Int from input but does nothing useful with it. Probably you should have called buildMenu in most of the places where displayInnerMenu is called.
Also it seems that you should improve your debugging skills. This is a crucial skill and this code is not that hard to debug.
Taken more broadly this is a complicated topic with no simple best answer. But there are certainly bad ones and unfortunately yours is one of those. The thing I don't like most in your code is big separation in the code between the menu item title and menu item action. (Just imagine what it takes to add new menu item in the middle. Or what would it take to create a deeper menu with some items shared between levels.) So I would re-write most of the code. Being more of an OOP-guy than a FP-guy, I would do something like this:
object UserInterface {
// should be non-generic for simplicity of the rest of the code
trait MenuAndStateNG {
def runMenu(): MenuAndStateNG
}
trait MenuItem[S] {
val name: String
def doAction(state: S, curMenu: MenuAndStateNG): MenuAndStateNG
}
case class Menu[S](header: String, items: Seq[MenuItem[S]]) {}
case class MenuAndState[S](menu: Menu[S], state: S) extends MenuAndStateNG {
def runMenu(): MenuAndStateNG = {
var inputNum: Int = -1
var isFirstRun = true
// we use 1-based indices in the menu
while (inputNum <= 0 || inputNum > menu.items.length) {
if (!isFirstRun) {
println("Your input was wrong. Try again")
}
isFirstRun = false
println(menu.header + ":")
println(menu.items.zipWithIndex.map({ case (item, index) => s"${index + 1} - ${item.name}" }).mkString("\n"))
println("Choose the operation you want to perform:")
inputNum = StdIn.readInt()
}
println()
val nextMenu = menu.items(inputNum - 1).doAction(state, this)
nextMenu
}
}
// most of menu items doesn't change current menu
// let's make it easier to implement
trait SimpleMenuItem[S] extends MenuItem[S] {
override def doAction(state: S, curMenu: MenuAndStateNG): MenuAndStateNG = {
doSimpleAction(state)
curMenu
}
def doSimpleAction(state: S): Unit
}
def start(): Unit = {
var curMenu: MenuAndStateNG = MenuAndState(mainMenu, ())
var isFirstRun = true
while (true) {
if (!isFirstRun) {
println
}
isFirstRun = false
curMenu = curMenu.runMenu()
}
}
private val loginItem = new MenuItem[Unit] {
override val name = "Login"
override def doAction(state: Unit, curMenu: MenuAndStateNG): MenuAndStateNG = {
println("Input you login, please:")
val inputLogin = StdIn.readLine()
println("Input you password, please:")
val inputPassword = StdIn.readLine()
val checkLogin = Await.result(DAO.checkUserLogin(inputLogin, inputPassword), Duration.Inf).toString
val userId = DAO.selectUserId(inputLogin)
checkLogin match {
case "true" =>
println("You have successfully entered")
MenuAndState(userMenu, userId)
case "false" =>
println("Your input for login or password is wrong. Please, try again")
curMenu
case _ =>
println("Your input is wrong")
curMenu
}
}
}
private val exitItem = new MenuItem[Unit] {
override val name = "Exit"
override def doAction(state: Unit, curMenu: MenuAndStateNG): MenuAndStateNG = {
System.exit(0)
null // null is bad but it doesn't matter by now
}
}
private val displayFinishedTasks = new SimpleMenuItem[Int] {
override val name: String = "Display finished tasks"
override def doSimpleAction(state: Int): Unit = {
println("User's finished tasks:\n" + Await.result(DAO.selectFinishedTasks(id), Duration.Inf).toList.toString)
}
}
private val displayUnfinishedTasks = new SimpleMenuItem[Int] {
override val name: String = "Display unfinished tasks"
override def doSimpleAction(state: Int): Unit = {
println("User's unfinished tasks:\n" + Await.result(DAO.selectUnfinishedTasks(id), Duration.Inf).toList.toString)
}
}
private val displayAllTasks = new SimpleMenuItem[Int] {
override val name: String = "Display all tasks"
override def doSimpleAction(state: Int): Unit = {
println("User's tasks:\n" + Await.result(DAO.selectTasksByUser(id), Duration.Inf).toList.toString)
}
}
private val addTask = new SimpleMenuItem[Int] {
override val name: String = "Add task"
override def doSimpleAction(state: Int): Unit = {
println("Input the task name you want to create, please:")
val taskName = readLine()
Await.result(DAO.addTask(taskName, id), Duration.Inf)
}
}
private val deleteTask = new SimpleMenuItem[Int] {
override val name: String = "Delete task"
override def doSimpleAction(state: Int): Unit = {
println("Choose the task you want to delete, please:")
val taskId = readLong()
Await.result(DAO.deleteTask(Some(taskId)), Duration.Inf)
}
}
private val markTaskFinished = new SimpleMenuItem[Int] {
override val name: String = "Mark task as finished"
override def doSimpleAction(state: Int): Unit = {
println("Choose the task you want to mark as finished, please:")
val taskId = readLong()
Await.result(DAO.finishTask(Some(taskId), id), Duration.Inf)
}
}
private val logoutTask = new MenuItem[Int] {
override val name = "Get back to the main menu"
override def doAction(state: Int, curMenu: MenuAndStateNG): MenuAndState[Unit] = {
MenuAndState(mainMenu, ())
}
}
val mainMenu: Menu[Unit] = Menu("Main menu", List(loginItem, exitItem))
val userMenu: Menu[Int] = Menu("User menu", List(
displayAllTasks,
displayFinishedTasks,
displayUnfinishedTasks,
addTask,
deleteTask,
markTaskFinished,
logoutTask))
}
The main ideas are following:
Join menu action and title into a single MenuItem
Let the MenuItem select next "menu state" (MenuAndState)
MenuAndState from the outside looks like MenuAndStateNG - i.e. something that just can be run to get next MenuAndStateNG. From the inside it is split into a "fixed part" (Menu) = header + list of items and "variable part" = state. By introducing this separation I was able to make userMenu actually a constant rather than def
Most of the menu items doesn't change menu and just return to their parent. To simplify code for this scenario curMenu is passed as an argument to the doAction and there is a SimpleMenuItem that just always returns it\
Given such design all you need is:
create a val for each menu item
create mainMenu and userMenu vals effectively as lists of those menu items
run an infinite loop starting from the mainMenu (done in start)
Note that because MenuAndStateNG returns the next MenuAndStateNG from its runMenu I can use an infinite loop instead of deepening the stack on each menu iteration (which is generally a bad idea).
I think my question is related but not the same as this one here.
Let define my first class
case class NoteTaker() {
private var note: Seq[String] = Seq("\n")
override def toString: String = this.note.mkString("\n")
def add(newNote: String): Unit = note ++= Seq(newNote)
}
Now I have a trait
trait SilentLogger {
import scala.util.{ Failure, Success }
val notepad = NoteTaker()
def tryAndLog[X, Y](x: X, f: X => Y): Y = {
notepad.add("Run with this input: " + x.toString)
(try {
println("Before: " + notepad.toString)
val result = f(x)
println("After: " + notepad.toString)
notepad.add("Get result:-------------------------------\n" + result.toString)
println(notepad.toString)
Success(result)
} catch {
case e: Throwable => {
println(
"Exception occurs:" + "\n" +
notepad.toString + "\n" +
e.getMessage + "\n" +
e.getStackTrace.mkString("\n")
)
Failure(e)
}}).get
}
}
I intend to use this trait to mix in with any classes where I want to collect some notes and only print out the note when there is an exception. Otherwise, I maybe just save it to a log file somewhere.
I want the notepad to be created once and reused for each of the object. In fact, I don't mind if they share the same notepad. Therefore, I chose to use 'val' in my trait.
As an example, I then create a class
case class MyClass (myField : String) extends SilentLogger {
def makeAnother : MyClass = tryAndLog("makeAnother",(x: String) => {
notepad.add(x)
val result = this.copy(myField = this.myField + " addNewField " + x)
notepad.add(result.myField)
return result
})
}
And finally I try to create two objects as follow:
scala> val firstObject = MyClass("firstObject")
firstObject: MyClass = MyClass(firstObject)
scala> val secondObject = firstObject.makeAnother
Before:
Run with this input: makeAnother
Exception occurs:
Run with this input: makeAnother
makeAnother
firstObject addNewField makeAnother
null
secondObject: MyClass = MyClass(firstObject addNewField makeAnother)
I'm really confused here. Obviously an exception occurred. But the secondObject was created just fine? But the logging message get printed out on stdout with the error 'null'.
I think my question is whether my first and second objects are actually using the same notepad or separate? How are the initialisation and the scope of notepad defined here? Is there something wrong with the way I use 'Try'?
This is caused of anonymous function with explicitly return:
(x: String) => {
notepad.add(x)
val result = this.copy(myField = this.myField + " addNewField " + x)
notepad.add(result.myField)
return result
}
In Scala, when explicitly declare return in anonymous function, it will throw NonLocalReturnControl, this will skip the later code block execute, since you have catched the Throwable, so it also will go to your catch code block.
So maybe you can remove return directly to solve this issue.
I want to place a block of a code into getOrElse method, but I can't:
//1
getOrElse(() => {
println("id is not found: " + x.Id)
new MyClass(-1)
})
//2
getOrElse {
println("id is not found: " + x.Id)
new MyClass(-1)
}
Works fine for me:
scala> None getOrElse { println("AAA")
| 5 }
AAA
res1: Int = 5
BTW, { () => ... } is a function from the empty argument set to something.
Probably here You have problems :
new MyClass(-1)
I dont see much code but this problems.
See this code which works fine:
import scala.io.Source
class Test(x: Int) {
override def toString = "In test "+x
}
object Main extends App {
val test = None
val b = test.getOrElse({
println("not found")
new Test(-1)
})
println(b.toString)
}
I'm new to scala and functional programming. I'm trying out the usual beginner applications and scripts(Obviously using a bit of over-technology)
Anyways I have this code for a calculator that takes arguments and a switch to dictate the operation to use on the arguments.
object Main {
def main(args: Array[String]): Unit = {
var calc = calculate( "" , _:List[Int])
var values:List[Int] = List()
if(args.size < 1) println("No arguments supplied") else{
args collect {_ match{
case arg if arg.contains("-") => {
if(values.size>0){
calc(values)
values = List()}
calc = calculate( arg , _:List[Int])
}
case arg => {
try{
val value=arg.toInt
values = values ::: List(value)
}catch{case e:NumberFormatException=>println("\nError:Invalid argument:\""+arg+"\"\nCannot convert to Integer.\n")}
}
}
}
calc(values)
}
}
def sum(values:List[Int]) { println("The sum is:"+(values.foldLeft(0)((sum,value) => sum + value))) }
def subtract(values:List[Int]) {
val initial:Int = values(0)
var total:Int = 0
for(i <- 1 until values.size){
total = total + values(i)
}
val diff:Int = initial - total
println("The difference is:"+diff)
}
def calculate(operation:String,values:List[Int]) = operation match {
case "-sum" => sum(values)
case "-diff" => subtract(values)
case _ => println("Default operation \"Sum\" will be applied");sum(values)
}
}
Some points that id like to find if theres a better way to do is like removing the try catch statement.
A better way to compose this application would be very welcome.
How about this one?
object Main extends App {
require(args.size > 0, "Please, supply more arguments")
#annotation.tailrec
def parseArguments(arguments: List[String], operation: String, values: List[Int]() = Nil) {
if(values.nonEmpty) calculate(operation, values)
arguments match {
case op::unprocessed if op.startsWith("-") => parseArguments(unprocessed, op)
case maybeNumber::unprocessed => {
val newValues = try {
maybeNumber.toInt::values
} catch {
case _: NumberFormatException =>
println("\nError:Invalid argument:\""+maybeNumber+"\"\nCannot convert to Integer.\n")
values
}
parseArguments(unprocessed, operation, newValues)
}
case Nil => //done processing, exiting
}
}
parseArguments(args.toList, "")
def diff(values:List[Int]) = {
val initial::tail = values
val total = tail.sum
initial - total
}
def calculate(operation:String, values:List[Int]) = operation match {
case "-sum" => println("The sum is " + values.sum)
case "-diff" => println("The difference is: " + diff(values))
case _ =>
println("""Default operation "Sum" will be applied""")
sum(values)
}
}