idiomatic property changed notification in scala? - scala

I'm trying to find a cleaner alternative (that is idiomatic to Scala) to the kind of thing you see with data-binding in WPF/silverlight data-binding - that is, implementing INotifyPropertyChanged. First, some background:
In .Net WPF or silverlight applications, you have the concept of two-way data-binding (that is, binding the value of some element of the UI to a .net property of the DataContext in such a way that changes to the UI element affect the property, and vise versa. One way to enable this is to implement the INotifyPropertyChanged interface in your DataContext. Unfortunately, this introduces a lot of boilerplate code for any property you add to the "ModelView" type. Here is how it might look in Scala:
trait IDrawable extends INotifyPropertyChanged
{
protected var drawOrder : Int = 0
def DrawOrder : Int = drawOrder
def DrawOrder_=(value : Int) {
if(drawOrder != value) {
drawOrder = value
OnPropertyChanged("DrawOrder")
}
}
protected var visible : Boolean = true
def Visible : Boolean = visible
def Visible_=(value: Boolean) = {
if(visible != value) {
visible = value
OnPropertyChanged("Visible")
}
}
def Mutate() : Unit = {
if(Visible) {
DrawOrder += 1 // Should trigger the PropertyChanged "Event" of INotifyPropertyChanged trait
}
}
}
For the sake of space, let's assume the INotifyPropertyChanged type is a trait that manages a list of callbacks of type (AnyRef, String) => Unit, and that OnPropertyChanged is a method that invokes all those callbacks, passing "this" as the AnyRef, and the passed-in String). This would just be an event in C#.
You can immediately see the problem: that's a ton of boilerplate code for just two properties. I've always wanted to write something like this instead:
trait IDrawable
{
val Visible = new ObservableProperty[Boolean]('Visible, true)
val DrawOrder = new ObservableProperty[Int]('DrawOrder, 0)
def Mutate() : Unit = {
if(Visible) {
DrawOrder += 1 // Should trigger the PropertyChanged "Event" of ObservableProperty class
}
}
}
I know that I can easily write it like this, if ObservableProperty[T] has Value/Value_= methods (this is the method I'm using now):
trait IDrawable {
// on a side note, is there some way to get a Symbol representing the Visible field
// on the following line, instead of hard-coding it in the ObservableProperty
// constructor?
val Visible = new ObservableProperty[Boolean]('Visible, true)
val DrawOrder = new ObservableProperty[Int]('DrawOrder, 0)
def Mutate() : Unit = {
if(Visible.Value) {
DrawOrder.Value += 1
}
}
}
// given this implementation of ObservableProperty[T] in my library
// note: IEvent, Event, and EventArgs are classes in my library for
// handling lists of callbacks - they work similarly to events in C#
class PropertyChangedEventArgs(val PropertyName: Symbol) extends EventArgs("")
class ObservableProperty[T](val PropertyName: Symbol, private var value: T) {
protected val propertyChanged = new Event[PropertyChangedEventArgs]
def PropertyChanged: IEvent[PropertyChangedEventArgs] = propertyChanged
def Value = value;
def Value_=(value: T) {
if(this.value != value) {
this.value = value
propertyChanged(this, new PropertyChangedEventArgs(PropertyName))
}
}
}
But is there any way to implement the first version using implicits or some other feature/idiom of Scala to make ObservableProperty instances function as if they were regular "properties" in scala, without needing to call the Value methods? The only other thing I can think of is something like this, which is more verbose than either of the above two versions, but is still less verbose than the original:
trait IDrawable {
private val visible = new ObservableProperty[Boolean]('Visible, false)
def Visible = visible.Value
def Visible_=(value: Boolean): Unit = { visible.Value = value }
private val drawOrder = new ObservableProperty[Int]('DrawOrder, 0)
def DrawOrder = drawOrder.Value
def DrawOrder_=(value: Int): Unit = { drawOrder.Value = value }
def Mutate() : Unit = {
if(Visible) {
DrawOrder += 1
}
}
}

I couldn't claim that this is a canonical property change framework in Scala, but I've used a class like this before:
abstract class Notifier[T,U](t0: T) {
import java.util.concurrent.atomic.AtomicReference
import scala.actors.OutputChannel
type OCUT = OutputChannel[(U,AtomicReference[T])]
val data = new AtomicReference[T](t0)
def id: U
protected var callbacks = Nil:List[T => Unit]
protected var listeners = Nil:List[OCUT]
def apply() = data.get
def update(t: T) {
val told = data.getAndSet(t)
if (t != told) {
callbacks.foreach(_(t))
listeners.foreach(_ ! (id,data))
}
}
def attend(f: T=>Unit) { callbacks ::= f }
def attend(oc: OCUT) { listeners ::= oc }
def ignore(f: T=>Unit) { callbacks = callbacks.filter(_ != f) }
def ignore(oc: OCUT) { listeners = listeners.filter(_ != oc) }
}
The motivation for creating this class was that I wanted a flexible thread-safe way to react to changes, which this provides (as it delivers both callbacks and can push messages to actors).
It seems to me--unless I'm misunderstanding exactly what you want because I haven't had occasion to learn the WPF/Silverlight stuff--that this can implement everything you want and more.
For example,
class IDrawable extends SomethingWithOnPropertyChanged {
val drawOrder = new Notifier[Int,Symbol](0) { def id = 'DrawOrder }
val visible = new Notifier[Boolean,Symbol](false) { def id = 'Visible }
drawOrder.attend((i:Int) => OnPropertyChanged(drawOrder.id))
def mutate {
if (visible()) drawOrder() += 1
}
}
should be roughly equivalent to what you want. (Again, I'm not sure how flexible you want this to be; you could create a set of symbol -> notifier mappings that you would look up with an apply method so the target would have an easier time of doing something when it gets the DrawOrder symbol.)
The only significant difference from your usage is that the Notifier uses its apply/update methods to save boilerplate; you don't have to write def x and def x_= methods every time, but you do have to use () for access.

Related

Is there any way to rewrite the below code using Scala value class or other concept?

I need to write two functions to get the output format and the output index for file conversion. As part of this, I wrote a TransformSettings class for these methods and set the default value. And in the transformer class, I created a new object of TransformSettings class to get the default values for each job run. Also, I have another class called ParquetTransformer that extends Transformer where I want to change these default values. So I implemented like below.
class TransformSettings{
def getOuputFormat: String = {
"orc"
}
def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("orc.column.index.access")
}
}
class Transformer{
def getTransformSettings: TransformSettings = {
new TransformSettings
}
def posttransform(table: AWSGlueDDL.Table):Dateframe ={
val indexAccess = getTransformSettings.getOuputIndex(table: AWSGlueDDL.Table)
........
}
}
class ParquetTransformer extends Transformer{
override def getTransformSettings: TransformSettings = {
val transformSettings = new TransformSettings {
override def getOuputFormat: String = {
"parquet"
}
override def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("parquet.column.index.access")
}
}
}
}
Is there a way to avoid creating a brand new object of TransformSettings in Transfomer class every time this is called?
Also is there a way to rewrite the code using Scala value class?
As #Dima proposed in the comments try to make TransformSettings a field / constructor parameter (a val) in the class Transformer and instantiate them outside
class TransformSettings{
def getOuputFormat: String = {
"orc"
}
def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("orc.column.index.access")
}
}
class Transformer(val transformSettings: TransformSettings) {
def posttransform(table: AWSGlueDDL.Table): DataFrame ={
val indexAccess = transformSettings.getOuputIndex(table: AWSGlueDDL.Table)
???
}
}
val parquetTransformSettings = new TransformSettings {
override def getOuputFormat: String = {
"parquet"
}
override def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("parquet.column.index.access")
}
}
class ParquetTransformer extends Transformer(parquetTransformSettings)
You don't seem to need value classes (... extends AnyVal) now. They are more about unboxing, not about life-cycle management. TransformSettings and Transformer can't be value classes because they are not final (you're extending them in class ParquetTransformer extends Transformer... and new TransformSettings { ... }). By the way, value classes have many limatations
https://failex.blogspot.com/2017/04/the-high-cost-of-anyval-subclasses.html
https://github.com/scala/bug/issues/12271
Besides value classes, there are scala-newtype library in Scala 2 and opaque types in Scala 3.

Events in Scala

I have a CategoryRepository class which implements several methods such that saves a category to database.
I also have an object Product that contains a list of categories.
What I want to do is to trigger an event that the Product object will listen to, and will update the product itself with the new data of its category.
In C# I know I can use delegates but I don't know if I can do something like this in Scala.
I don't want the CategoryRepository class to know the class Product so I won't call some method in Product that will update it through CategoryRepository.
My CategoryRepository class:
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
class CategoryRepositoryImpl extends CategoryRepository {
val dbRepository = CategoryDbRepository
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
}
}
}
The product repository looks the same as this category's repository.
Now I want to add a line after dbRepository.save(cat) that will trigger an event that will call the updateProduct() function within ProductRepository.
Please give an implementation example.
Thanks.
a (not so) basic implementation for an update channel based on events.
I took care to only generalize to the bare bone, as to give a hint to future evolution and code reuse.
Base infrastructure
We introduce an updates channel
//Listens for updates to A's and notifies interested listeners
class UpdateChannel[A] {
//simplified register
var listenMap: Map[A, Listening[A]] = Map()
//update call
def apply(a: A): Unit = listenMap.get(a).foreach(_.event(a))
//update call
def registerFor(a: value, listen: Listening[A]) = listenMap += (a, listen)
}
and a generic listener interested in corrisponding updates
//Listens to changes for type A
trait Listening[A] {
def event(upd: A): Unit
}
Application
Now we adapt the Repo Component to inject the channel
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
/************** NEW CODE HERE **************
* define a channel to send category updates
*******************************************/
def updateChannel: UpdateChannel[Category]
class CategoryRepositoryImpl extends CategoryRepository {
val dbRepository = CategoryDbRepository
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
//send the update to the channel
updateChannel(cat) //***************** << AND HERE
}
}
}
We also need to enable the product to event listening
//product must be listening to category updates
class Product(val category: Category) extends Listening[Category] {
def event(cat: Category) = ??? //strut your stuff here
...business stuff here too
}
Finally, here we put the ingredients together
//put the pieces together
def wireup() = {
//the channel
val catChan: UpdateChannel[Category] = new UpdateChannel[Category]
//the Repository component wired to the channel
val catRep = new CategoryRepositoryComponentImpl {
val updateChannel = catChan
}
//a nice cat
val myCat: Category = ???
//a nice prod with her nice cat
val p: Product = new Product(myCat)
//prod wants to know what happens to her cat
catChan.registerFor(myCat, p)
}
Remarks
we can make the Product independent of the whole framework by using refinement types
val product = new Product(myCat) with Listening[Category] {
def event(cat: Category) = ??? //strut your stuff here
}
a different solution would be to avoiding all the wirings and simply register a list of update closures in the RepositoryComponent
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
//public listeners, they should be encapsulated
var categoryUpdates: Seq[Category => Unit]
[...]
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
//send the update to the channel
categoryUpdates.foreach(_.apply(cat))
}
}
}
and the product needs only to add his own update function
catRep.categoryUpdates +:= (cat) => p.event(cat)
I think this would be more or less how it's done in C# with events and delegates.
When you define Event like this you'd have to use tuples (Event[(Any,EventArgs)] for instance) if you want to pass more than one parameter to the event listeners.
class Event[Arg] {
type L = Arg => Unit
private val listeners = scala.collection.mutable.ListBuffer.empty[L]
def +=(listener: L) {
listeners.append(listener)
}
def apply(arg: Arg) {
listeners.foreach(_(arg))
}
}
class CategoryRepository {
val event = new Event[String]
def fireEvent(data: String) {
event(data)
}
}
object Product {
def update(data: String) {
println(s"updating: $data")
}
}
object Main extends App {
val repo = new CategoryRepository()
repo.event += Product.update
repo.fireEvent("new data")
}

specs2 After method runs before the example

I have the following test:
class Foo extends mutable.SpecificationWithJUnit {
sequential
"this example should run before the 'After' method" in new Context {
bar must beSome
}
class Context extends mutable.BeforeAfter with mutable.Around {
override def apply[T : AsResult](a: =>T): Result = {
lazy val result = super[Around].apply(a)
super[BeforeAfter].apply(result)
}
override def delayedInit(x: => Unit): Unit = around { try { before; x; Success() } finally { after }}
#Resource var barReader : BarReader = _
val bar = barReader.someBar
override def before : Any = { //some stuff}
def after: Any = {
bar = None
}
override def around[T : AsResult](t: =>T) = {
//spring context injection logic
AsResult.effectively(t)
}
}
}
}
I expect this test to pass but in reality what happens is that because of the delayed init, the after runs before the example. If I change the Context to a trait I lose the delayed init functionality. Is this a bug or am I doing something wrong?
**Edited:
This example will throw an NPE when the Context is a trait. What I expect to happen is that because of the delayed-init, the Context's constructor, which consequentially means the barReader.someBar will run only after the barReader has been injected.
Thanks
Netta
You should use a trait instead of a class for Context. If you use a class, delayedInit (hence after) will be triggered twice. Once for the body of the Context class and another time for the body of the anonymous class new Context. With a trait you don't get such a behavior:
class Foo extends mutable.SpecificationWithJUnit {
sequential
"this example should run before the 'After' method" in new Context {
bar must beSome
}
trait Context extends mutable.After {
var bar : Option[String] = Some("bar")
def after: Any = bar = None
}
}
Simple answer, looks like this can't be done.

scala, transform a callback pattern to a functional style internal iterator

Suppose this API is given and we cannot change it:
object ProviderAPI {
trait Receiver[T] {
def receive(entry: T)
def close()
}
def run(r: Receiver[Int]) {
new Thread() {
override def run() {
(0 to 9).foreach { i =>
r.receive(i)
Thread.sleep(100)
}
r.close()
}
}.start()
}
}
In this example, ProviderAPI.run takes a Receiver, calls receive(i) 10 times and then closes. Typically, ProviderAPI.run would call receive(i) based on a collection which could be infinite.
This API is intended to be used in imperative style, like an external iterator. If our application needs to filter, map and print this input, we need to implement a Receiver which mixes all these operations:
object Main extends App {
class MyReceiver extends ProviderAPI.Receiver[Int] {
def receive(entry: Int) {
if (entry % 2 == 0) {
println("Entry#" + entry)
}
}
def close() {}
}
ProviderAPI.run(new MyReceiver())
}
Now, the question is how to use the ProviderAPI in functional style, internal iterator (without changing the implementation of ProviderAPI, which is given to us). Note that ProviderAPI could also call receive(i) infinite times, so it is not an option to collect everything in a list (also, we should handle each result one by one, instead of collecting all the input first, and processing it afterwards).
I am asking how to implement such a ReceiverToIterator, so that we can use the ProviderAPI in functional style:
object Main extends App {
val iterator = new ReceiverToIterator[Int] // how to implement this?
ProviderAPI.run(iterator)
iterator
.view
.filter(_ % 2 == 0)
.map("Entry#" + _)
.foreach(println)
}
Update
Here are four solutions:
IteratorWithSemaphorSolution: The workaround solution I proposed first attached to the question
QueueIteratorSolution: Using the BlockingQueue[Option[T]] based on the suggestion of nadavwr.
It allows the producer to continue producing up to queueCapacity before being blocked by the consumer.
PublishSubjectSolution: Very simple solution, using PublishSubject from Netflix RxJava-Scala API.
SameThreadReceiverToTraversable: Very simple solution, by relaxing the constraints of the question
Updated: BlockingQueue of 1 entry
What you've implemented here is essentially Java's BlockingQueue, with a queue size of 1.
Main characteristic: uber-blocking. A slow consumer will kill your producer's performance.
Update: #gzm0 mentioned that BlockingQueue doesn't cover EOF. You'll have to use BlockingQueue[Option[T]] for that.
Update: Here's a code fragment. It can be made to fit with your Receiver.
Some of it inspired by Iterator.buffered. Note that peek is a misleading name, as it may block -- and so will hasNext.
// fairness enabled -- you probably want to preserve order...
// alternatively, disable fairness and increase buffer to be 'big enough'
private val queue = new java.util.concurrent.ArrayBlockingQueue[Option[T]](1, true)
// the following block provides you with a potentially blocking peek operation
// it should `queue.take` when the previous peeked head has been invalidated
// specifically, it will `queue.take` and block when the queue is empty
private var head: Option[T] = _
private var headDefined: Boolean = false
private def invalidateHead() { headDefined = false }
private def peek: Option[T] = {
if (!headDefined) {
head = queue.take()
headDefined = true
}
head
}
def iterator = new Iterator[T] {
// potentially blocking; only false upon taking `None`
def hasNext = peek.isDefined
// peeks and invalidates head; throws NoSuchElementException as appropriate
def next: T = {
val opt = peek; invalidateHead()
if (opt.isEmpty) throw new NoSuchElementException
else opt.get
}
}
Alternative: Iteratees
Iterator-based solutions will generally involve more blocking. Conceptually, you could use continuations on the thread doing the iteration to avoid blocking the thread, but continuations mess with Scala's for-comprehensions, so no joy down that road.
Alternatively, you could consider an iteratee-based solution. Iteratees are different than iterators in that the consumer isn't responsible for advancing the iteration -- the producer is. With iteratees, the consumer basically folds over the entries pushed by the producer over time. Folding each next entry as it becomes available can take place in a thread pool, since the thread is relinquished after each fold completes.
You won't get nice for-syntax for iteration, and the learning curve is a little challenging, but if you feel confident using a foldLeft you'll end up with a non-blocking solution that does look reasonable on the eye.
To read more about iteratees, I suggest taking a peek at PlayFramework 2.X's iteratee reference. The documentation describes their stand-alone iteratee library, which is 100% usable outside the context of Play. Scalaz 7 also has a comprehensive iteratee library.
IteratorWithSemaphorSolution
The first workaround solution that I proposed attached to the question.
I moved it here as an answer.
import java.util.concurrent.Semaphore
object Main extends App {
val iterator = new ReceiverToIterator[Int]
ProviderAPI.run(iterator)
iterator
.filter(_ % 2 == 0)
.map("Entry#" + _)
.foreach(println)
}
class ReceiverToIterator[T] extends ProviderAPI.Receiver[T] with Iterator[T] {
var lastEntry: T = _
var waitingToReceive = new Semaphore(1)
var waitingToBeConsumed = new Semaphore(1)
var eof = false
waitingToReceive.acquire()
def receive(entry: T) {
println("ReceiverToIterator.receive(" + entry + "). START.")
waitingToBeConsumed.acquire()
lastEntry = entry
waitingToReceive.release()
println("ReceiverToIterator.receive(" + entry + "). END.")
}
def close() {
println("ReceiverToIterator.close().")
eof = true
waitingToReceive.release()
}
def hasNext = {
println("ReceiverToIterator.hasNext().START.")
waitingToReceive.acquire()
waitingToReceive.release()
println("ReceiverToIterator.hasNext().END.")
!eof
}
def next = {
println("ReceiverToIterator.next().START.")
waitingToReceive.acquire()
if (eof) { throw new NoSuchElementException }
val entryToReturn = lastEntry
waitingToBeConsumed.release()
println("ReceiverToIterator.next().END.")
entryToReturn
}
}
QueueIteratorSolution
The second workaround solution that I proposed attached to the question. I moved it here as an answer.
Solution using the BlockingQueue[Option[T]] based on the suggestion of nadavwr.
It allows the producer to continue producing up to queueCapacity before being blocked by the consumer.
I implement a QueueToIterator that uses a ArrayBlockingQueue with a given capacity.
BlockingQueue has a take() method, but not a peek or hasNext, so I need an OptionNextToIterator as follows:
trait OptionNextToIterator[T] extends Iterator[T] {
def getOptionNext: Option[T] // abstract
def hasNext = { ... }
def next = { ... }
}
Note: I am using the synchronized block inside OptionNextToIterator, and I am not sure it is totally correct
Solution:
import java.util.concurrent.ArrayBlockingQueue
object Main extends App {
val receiverToIterator = new ReceiverToIterator[Int](queueCapacity = 3)
ProviderAPI.run(receiverToIterator)
Thread.sleep(3000) // test that ProviderAPI.run can produce 3 items ahead before being blocked by the consumer
receiverToIterator.filter(_ % 2 == 0).map("Entry#" + _).foreach(println)
}
class ReceiverToIterator[T](val queueCapacity: Int = 1) extends ProviderAPI.Receiver[T] with QueueToIterator[T] {
def receive(entry: T) { queuePut(entry) }
def close() { queueClose() }
}
trait QueueToIterator[T] extends OptionNextToIterator[T] {
val queueCapacity: Int
val queue = new ArrayBlockingQueue[Option[T]](queueCapacity)
var queueClosed = false
def queuePut(entry: T) {
if (queueClosed) { throw new IllegalStateException("The queue has already been closed."); }
queue.put(Some(entry))
}
def queueClose() {
queueClosed = true
queue.put(None)
}
def getOptionNext = queue.take
}
trait OptionNextToIterator[T] extends Iterator[T] {
def getOptionNext: Option[T]
var answerReady: Boolean = false
var eof: Boolean = false
var element: T = _
def hasNext = {
prepareNextAnswerIfNecessary()
!eof
}
def next = {
prepareNextAnswerIfNecessary()
if (eof) { throw new NoSuchElementException }
val retVal = element
answerReady = false
retVal
}
def prepareNextAnswerIfNecessary() {
if (answerReady) {
return
}
synchronized {
getOptionNext match {
case None => eof = true
case Some(e) => element = e
}
answerReady = true
}
}
}
PublishSubjectSolution
A very simple solution using PublishSubject from Netflix RxJava-Scala API:
// libraryDependencies += "com.netflix.rxjava" % "rxjava-scala" % "0.20.7"
import rx.lang.scala.subjects.PublishSubject
class MyReceiver[T] extends ProviderAPI.Receiver[T] {
val channel = PublishSubject[T]()
def receive(entry: T) { channel.onNext(entry) }
def close() { channel.onCompleted() }
}
object Main extends App {
val myReceiver = new MyReceiver[Int]()
ProviderAPI.run(myReceiver)
myReceiver.channel.filter(_ % 2 == 0).map("Entry#" + _).subscribe{n => println(n)}
}
ReceiverToTraversable
This stackoverflow question came when I wanted to list and process a svn repository using the svnkit.com API as follows:
SvnList svnList = new SvnOperationFactory().createList();
svnList.setReceiver(new ISvnObjectReceiver<SVNDirEntry>() {
public void receive(SvnTarget target, SVNDirEntry dirEntry) throws SVNException {
// do something with dirEntry
}
});
svnList.run();
the API used a callback function, and I wanted to use a functional style instead, as follows:
svnList.
.filter(e => "pom.xml".compareToIgnoreCase(e.getName()) == 0)
.map(_.getURL)
.map(getMavenArtifact)
.foreach(insertArtifact)
I thought of having a class ReceiverToIterator[T] extends ProviderAPI.Receiver[T] with Iterator[T],
but this required the svnkit api to run in another thread.
That's why I asked how to solve this problem with a ProviderAPI.run method that run in a new thread. But that was not very wise: if I had explained the real case, someone might have found a better solution before.
Solution
If we tackle the real problem (so, no need of using a thread for the svnkit),
a simpler solution is to implement a scala.collection.Traversable instead of a scala.collection.Iterator.
While Iterator requires a next and hasNext def, Traversable requires a foreach def,
which is very similar to the svnkit callback!
Note that by using view, we make the transformers lazy, so elements are passed one by one through all the chain to foreach(println).
this allows to process an infinite collection.
object ProviderAPI {
trait Receiver[T] {
def receive(entry: T)
def close()
}
// Later I found out that I don't need a thread
def run(r: Receiver[Int]) {
(0 to 9).foreach { i => r.receive(i); Thread.sleep(100) }
}
}
object Main extends App {
new ReceiverToTraversable[Int](r => ProviderAPI.run(r))
.view
.filter(_ % 2 == 0)
.map("Entry#" + _)
.foreach(println)
}
class ReceiverToTraversable[T](val runProducer: (ProviderAPI.Receiver[T] => Unit)) extends Traversable[T] {
override def foreach[U](f: (T) => U) = {
object MyReceiver extends ProviderAPI.Receiver[T] {
def receive(entry: T) = f(entry)
def close() = {}
}
runProducer(MyReceiver)
}
}

ZeroC Ice "checked casts" in Scala

ZeroC Ice for Java translates every Slice interface Simple into (among other things) a proxy interface SimplePrx and a proxy SimplePrxHelper. If I have an ObjectPrx (the base interface for all proxies), I can check whether it actually has interface Simple by using a static method on SimplePrxHelper:
val obj : Ice.ObjectPrx = ...; // Get a proxy from somewhere...
val simple : SimplePrx = SimplePrxHelper.checkedCast(obj);
if (simple != null)
// Object supports the Simple interface...
else
// Object is not of type Simple...
I wanted to write a method castTo so that I could replace the second line with
val simple = castTo[SimplePrx](obj)
or
val simple = castTo[SimplePrxHelper](obj)
So far as I can see, Scala's type system is not expressive enough to allow me to define castTo. Is this correct?
Should be able to do something with implicits, along these lines:
object Casting {
trait Caster[A] {
def checkedCast(obj: ObjectPrx): Option[A]
}
def castTo[A](obj: ObjectPrx)(implicit caster: Caster[A]) =
caster.checkedCast(obj)
implicit object SimplePrxCaster extends Caster[SimplePrx] {
def checkedCast(obj: ObjectPrx) = Option(SimplePrxHelper.checkedCast(obj))
}
}
Then you just bring things into scope where you want to use them:
package my.package
import Casting._
...
def whatever(prx: ObjectPrx) {
castTo[SimplePrx](prx) foreach (_.somethingSimple())
}
...
You can get something like what you want with structural types:
def castTo[A](helper: { def checkedCast(o: Object): A })(o: Object) = {
helper.checkedCast(o)
}
class FooPrx { }
object FooPrxHelper {
def checkedCast(o: Object): FooPrx = o match {
case fp : FooPrx => fp
case _ => null
}
}
scala> val o: Object = new FooPrx
o: java.lang.Object = FooPrx#da8742
scala> val fp = castTo(FooPrxHelper)(o)
fp: FooPrx = FooPrx#da8742