scala - How do I make a typesafe builder that doesn't need an explicit build method? -


i using slight abuse of builder pattern make fluent imperative execution chain. after way make compile error forget execute method @ end. goal following

withservicea {  dostuff() } withserviceb {   dostuff() } withclient client 

withservicea , withserviceb can both return values, if return value used obvious if return type wrong, if used imperatively, whole object falls on floor silently. want ensure forgetting withclient call compile error no matter context used in.

i want able skip blocks if unneeded , put them in arbitrary order looking replace nested inner class pattern using ala

def onservicea[a](body: servicea => a) = new {      def onserviceb[b >: a](body: serviceb => b) = {b => {     dostuff()   } } 

it looks type-safe builder pattern. see this answer.

in case:

trait ttrue trait tfalse  class myclass[ta, tb, tc] private(){   def withservicea(x: => unit)(implicit e: ta =:= tfalse) = {x; new myclass[ttrue, tb, tc]}   def withserviceb(x: => unit)(implicit e: tb =:= tfalse) = {x; new myclass[ta, ttrue, tc]}   def withservicec(x: => unit)(implicit e: tc =:= tfalse) = {x; new myclass[ta, tb, ttrue]}   def withclient(x: => unit)(implicit e1: ta =:= ttrue, e2: tb =:= ttrue) = x }  object myclass{   def apply() = new myclass[tfalse, tfalse, tfalse] } 

usage:

myclass()   .withclient(println("withclient")) //<console>:22: error: cannot prove tfalse =:= ttrue. //                .withclient(println("withclient")) //                           ^   myclass()   .withserviceb(println("with b"))   .withservicea(println("with a"))   .withclient(println("withclient")) //with b //with //withclient  myclass()   .withservicea(println("with a"))   .withservicec(println("with c"))   .withserviceb(println("with b"))   .withclient(println("withclient")) //with //with c //with b //withclient  myclass()   .withservicec(println("with c"))   .withserviceb(println("with b"))   .withservicea(println("with a"))   .withservicec(println("with c2"))   .withclient(println("withclient")) //<console>:25: error: cannot prove ttrue =:= tfalse. //                .withservicec(println("with c2")) //                             ^ 

you provide custom error messages custom replacements =:= class.

if want sure after every myclass.apply withclient called, call manually this:

sealed class context private() object context {    def withcontext(f: context => myclass[ttrue, ttrue, _])(withclient: => unit) =      f(new context).withclient(withclient) }  object myclass{   def apply(c: context) = new myclass[tfalse, tfalse, tfalse] } 

usage:

context   .withcontext(     myclass(_)       .withservicea(println("with a"))       .withservicec(println("with c"))       .withserviceb(println("with b"))   )(println("withclient")) 

on ideone.

one can't create myclass outside of withcontext method , withclient called @ least once.


Comments

Popular posts from this blog

javascript - Using jquery append to add option values into a select element not working -

Android soft keyboard reverts to default keyboard on orientation change -

jquery - javascript onscroll fade same class but with different div -