Reputation: 73589
Is it possible to set a variable which has scope in a method from it's child class in scala?
Why I need is explained in following code snippet:
abstract class SuperTask {
def doWork():Unit = {
var taskData:Option[TaskData] = None
try {
_actualWork()
}
catch {
// catch exception and do reporting using taskData variable
}
}
protected def _actualWork(): Unit
}
class FunTask extends SuperTask {
override def _actualWork(): Unit = {
//This will have data for taskData
//PROBLEM is how to set taskData of parent class from here so that if this throws exception, I can do reporting from catch in doWork method.
}
}
I want to set value of taskData
variable, so that if _actualWork
fails, I can have proper reporting, retries, etc which can be common for all child classes of SuperTask
class.
I can not define taskData
variable at SuperTask
class level as it then will be shared and fail in case of concurrency.
Upvotes: 0
Views: 88
Reputation: 44908
Just pass a closure which knows how to set taskData
to _actualWork
:
type TaskData = String
abstract class SuperTask {
def doWork():Unit = {
var taskData:Option[TaskData] = None
try {
_actualWork(td => taskData = td)
} catch {
case _: Throwable => println("last task data: " + taskData)
}
}
protected def _actualWork(setTaskData: Option[TaskData] => Unit): Unit
}
object FunTask extends SuperTask {
override def _actualWork(setTaskData: Option[TaskData] => Unit): Unit = {
// No problem to set taskData of parent class from here:
setTaskData(Some("Hello, world!"))
throw new Error("error")
}
}
If you now invoke doWork
on FunTask
, which sets the taskData
and throws an error, you get the following output:
FunTask.doWork()
// output: last task data: Some(Hello, world!)
Note that this is merely a really cheap variant of the "Observer"-pattern, where the state of your registered "observer" consists of a single local variable, and the "notifications" consist of invocations of the closure setTaskData
. You could just as well pass a whole bunch of proper "observers" into the _actualWork
method, so that they can monitor what's going on inside _actualWork
.
Upvotes: 1
Reputation: 544
This regarding my last comment below your message:
Split _actualWork
into two functions? 1st one is Option[TaskData]
and the 2nd one is _actualWork(taskData: Option[TaskData])
.
abstract class SuperTask {
def doWork():Unit = {
val taskData:Option[TaskData] = getData
try {
_actualWork(taskData)
}
catch {
// catch exception and do reporting using taskData variable
}
}
protected def getData(): Option[TaskData]
protected def _actualWork(taskData: Option[TaskData]): Unit
}
class FunTask extends SuperTask {
override def getData(): Option[TaskData] = Some(data)
override def _actualWork(taskData: Option[TaskData]): Unit = {
//do some work with taskData
}
}
Upvotes: 0