How to elegantly implement the pipeline pattern using Scala -
i'm looking build pipeline pattern scala. wish after write pipeline objects, connected this:
pipeline1 :: pipeline2 :: pipeline3 ...
i have experimented few ideas far. work , don't. none of them seems rid of boilerplate code. following closest i've got.
first define pipeline , source abstract class:
// input type , o output type of pipeline abstract class pipeline[i, +o](p: pipeline[_, _ <: i]) { val source = p val name: string def produce(): o def stats():string } abstract class source[+t] extends pipeline[anyref, t](null)
next, created 2 pipelines , try link them together
// creates random integer class randominteger extends source[int] { override val name = "randint" def produce() = { scala.math.round(scala.math.random.asinstanceof[float] * 10) } def stats()="this pipeline stateless" } // multiply ten class timesten(p: pipeline[_, int]) extends pipeline[int, int](p) { private var count = 0 // simple state of pipeline override val name = "times" def produce = { val = source.produce() count += 1 // updating state * 10 } def stats() = "this pipeline has been called " + count + " times" } object timesten { // code achieves desired connection using :: // has repeated in each pipeline subclass. // how remove or abstract away boilerplate code? def ::(that: pipeline[_, int]) = new timesten(that) }
this main class 2 pipelines linked.
object pipeline { def main(args: array[string]) { val p = new randominteger() :: timesten println(p.source) (i <- 0 10) println(p.produce()) println(p.stats()) } }
so code works. have repeat code in timesten companion object in every pipeline class write. not desirable. there better way this? reflection might work, heard bad things it, such involving reflection bad design. i'm unsure scala's support reflection.
thank time.
update: designed toy problem make easy understand. general solution, , application requires, each pipeline object has state, ideally encapsulated within object rather exposed every other pipeline. have modified code above reflect this. wish there object-based solution. i'm still experimenting , let know if find one.
update 2: after thoughts, think idea of pipeline generalized function contains internal states ability compose function0
function function1
function. in scala, function0
class not have compose()
or andthen()
method.
unless i'm missing something, pipeline objects functions, , :: operator "compose"
val randominteger: ()=>int = () => scala.math.round(scala.math.random.asinstanceof[float] * 10) val timesten :int => int = x => x*10 val pipeline: () =>int = timesten compose randominteger
your "produce()" method "apply()", it's common use it's abbreviation of "()". small amount of library pimping allow use operator composition. 1 of cases object-oriented boilerplate gets in way of simple functional concepts. fortunately, scala lets avoid boilerplate lot of use cases this.
Comments
Post a Comment