Using builder-like functions conditionally - scala

Assume this situation:
I have a Tuple of size n.
Each element is a Boolean flag that defines if a specific function should be called on an object (here: builder).
The syntax that comes to my mind first would be:
(el1, el2, el3, ...) => {
val builder = MyBuilder()
val builder1 = if(el1) builder.func1(...) else builder
val builder2 = if(el2) builder1.func2(...) else builder1
val builder3 = if(el3) builder2.func3(...) else builder2
...
}
The last builder builderN would be the desired object. But this code is nasty.
What would be a good, clean alternative? (Note: I am using cats.)
Another way to represent my problem would be:
val result = MyBuilder.
.func1(...) //ONLY if el1!
.func2(...) //ONLY if el2!
.func3(...) //ONLY if el3!
....
.funcn(...) //ONLY if el4!
EDIT : Fixed example code!

You can zip list of flags with list of building functions and then in the fold conditionally apply builder function
class Builder() {
def func1(in: Any): Builder = {
println("func1")
this
}
def func2(in: Any): Builder = {
println("func2")
this
}
def func3(in: Any): Builder = {
println("func3")
this
}
}
val flags = List(true, false, true)
val funcs = List[Builder => Builder](b => b.func1(1), b => b.func2(2), b => b.func3(3))
val result = flags.zip(funcs).foldLeft(new Builder()) {
case (builder, (flag, func)) => if (flag) func(builder) else builder
}
prints to console:
func1
func3

Related

Scala conditional accumulation

I'm trying to implement a function that extracts from a given string "placeholders" delimited by $ character.
Processing the string:
val stringToParse = "ignore/me/$aaa$/once-again/ignore/me/$bbb$/still-to-be/ignored
the result should be:
Seq("aaa", "bbb")
What would be a Scala idiomatic alternative of following implementation using var for toggling accumulation?
import fiddle.Fiddle, Fiddle.println
import scalajs.js
import scala.collection.mutable.ListBuffer
#js.annotation.JSExportTopLevel("ScalaFiddle")
object ScalaFiddle {
// $FiddleStart
val stringToParse = "ignore/me/$aaa$/once-again/ignore/me/$bbb$/still-to-be/ignored"
class StringAccumulator {
val accumulator: ListBuffer[String] = new ListBuffer[String]
val sb: StringBuilder = new StringBuilder("")
var open:Boolean = false
def next():Unit = {
if (open) {
accumulator.append(sb.toString)
sb.clear
open = false
} else {
open = true
}
}
def accumulateIfOpen(charToAccumulate: Char):Unit = {
if (open) sb.append(charToAccumulate)
}
def get(): Seq[String] = accumulator.toList
}
def getPlaceHolders(str: String): Seq[String] = {
val sac = new StringAccumulator
str.foreach(chr => {
if (chr == '$') {
sac.next()
} else {
sac.accumulateIfOpen(chr)
}
})
sac.get
}
println(getPlaceHolders(stringToParse))
// $FiddleEnd
}
I'll present two solutions to you. The first is the most direct translation of what you've done. In Scala, if you hear the word accumulate it usually translates to a variant of fold or reduce.
def extractValues(s: String) =
{
// We can combine the functionality of your boolean and StringBuilder by using an Option
s.foldLeft[(ListBuffer[String],Option[StringBuilder])]((new ListBuffer[String], Option.empty))
{
//As we fold through, we have the accumulated list, possibly a partially built String and the current letter
case ((accumulator,sbOption),char) =>
{
char match
{
//This logic pretty much matches what you had, adjusted to work with the Option
case '$' =>
{
sbOption match
{
case Some(sb) =>
{
accumulator.append(sb.mkString)
(accumulator,None)
}
case None =>
{
(accumulator,Some(new StringBuilder))
}
}
}
case _ =>
{
sbOption.foreach(_.append(char))
(accumulator,sbOption)
}
}
}
}._1.map(_.mkString).toList
}
However, that seems pretty complicated, for what sounds like it should be a simple task. We can use regexes, but those are scary so let's avoid them. In fact, with a little bit of thought this problem actually becomes quite simple.
def extractValuesSimple(s: String) =
{
s.split('$'). //Split the string on the $ character
dropRight(1). //Drops the rightmost item, to handle the case with an odd number of $
zipWithIndex.filter{case (str, index) => index % 2 == 1}. //Filter out all of the even indexed items, which will always be outside of the matching $
map{case (str, index) => str}.toList //Remove the indexes from the output
}
Is this solution enough?
scala> val stringToParse = "ignore/me/$aaa$/once-again/ignore/me/$bbb$/still-to-be/ignored"
stringToParse: String = ignore/me/$aaa$/once-again/ignore/me/$bbb$/still-to-be/ignored
scala> val P = """\$([^\$]+)\$""".r
P: scala.util.matching.Regex = \$([^\$]+)\$
scala> P.findAllIn(stringToParse).map{case P(s) => s}.toSeq
res1: Seq[String] = List(aaa, bbb)

sequencing (parallel) Observables in Outwatch (or zipping)

How should I render a list of Observables in Outwatch? What if I need a single Observable: how should I sequence/zip them as an applicative? Is it expected that it render, when I use the applicative(?) operation 'zip' to transform a List[Observable] to an Observable[List] ? (ie when I don't need Observables to be chained)
val literals:Seq[Observable[VNode]] = handlers.map { i => i.map(li(_)) }
return div(ol( children <-- Observable.zip[VNode, Seq[VNode]](literals)(identity) ))
With one answer below
div(ol(
(for (item <- literals) yield { child <-- item} ):_*))
any one child is only rendered only after every input has been entered by the user. How do I render each child as soon as the user enters any first input, without having to enter them all?
Full code follows
import outwatch.dom._
import rxscalajs.Observable
import scala.scalajs.js.JSApp
object Outwatchstarter extends JSApp {
def createInputMappedToStringHandler(s:Handler[String]) = input(inputString --> s)
def main(): Unit = {
val root = {
val names = (0 until 2).map(_.toString) // when 0 until 1, this emits
val handlers: Seq[Handler[String]] = names.map(name => createStringHandler())
val inputNodes = handlers.map(createInputMappedToStringHandler)
val notworkingformorethan1 = {
val literals = handlers.map { i => i.map(li(_)) }
val y: Observable[Seq[VNode]] = Observable.zip[VNode, Seq[VNode]](literals)(identity)
div(ol(
children <-- y
))
}
val list = List("What", "Is", "Up?").map(s => li(s))
val lists = Observable.just(list)
val workingList = ul(children <-- lists)
div(
div(inputNodes: _*),
workingList,
notworkingformorethan1)
}
OutWatch.render("#app", root)
}
}
Nothing shows up when list length >1, but does with a one-element list. I'm an html/scala-js and rx noob. And may be misunderstanding how Observables may (or may not) be applicative functors. I was looking for 'sequence' rather than 'zip'.
Screenshot from full code
For-comprehensions work inside the OutWatch DOM DSL
div(ol(
(for (item <- literals) yield { child <-- item} ):_*))

Scala: Create object only if it doesn't exist yet

I'm new to Scala, and this probably a very simple question, but I'm struggling to figure out how to make an object only if one doesn't exist yet.
I would like to query a database, and find out if there's anything present, if so, store it in an object, otherwise create a new one. In Java I know that this would be something like
PushMessage push = null;
if(GetFromDatabase() == null) {
push = new PushMessaage(param1, param2...);
}
else {
push = GetFromDatabase();
}
But, how do I do this in Scala. When I try and do the same thing, it tells me that GetFromDatabase() doesn't conform to expected type Null. Similarly, I tried doing pattern matching and doing something like
val push = GetFromDatabase match {
case Some(pushMessage) => pushMessage
case None => new PushMessage(param1, param2...)
}
But, that also didn't work as it told me that
Constructor cannot be instantiated to expected type, found: Some[A], expected: PushMessage
So, how do I do this? Any and all help would be really appreciated.
I assume your GetFromDatabase returns either null or PushMessage, so in order to pattern match correctly, you need to wrap it into Option:
val push = Option(GetFromDatabase) match {
case Some(pushMessage) => pushMessage
case None => new PushMessage(param1, param2...)
}
Or (bad style, but gives an understanding of how it works):
// Option(null) === None, Option(notNull) === Some(notNull):
// same as `if (x ne null) Some(x) else None
val pushMaybe: Option[PushMessage] = Option(GetFromDatabase)
val push: PushMessage =
if (pushMaybe.isEmpty) new PushMessage(param1, param2...)
else pushMaybe.get
You can simplify it all with:
val push = Option(GetFromDatabase).getOrElse(new PushMessage(param1, param2...))
P.S. If GetFromDatabase isn't some external method, it's better to rewrite it as returning Option[PushMessage] instead of PushMessage, something like:
def getFromDatabase = {
val rs = driver.getResulSet(query)
if (!rs.isBeforeFirst()) None else Some(parse(rs))
}
Here's a little demonstration why "cool" things are not always cool. Let's see Scala generated code for two cases (I made them very simple):
def getMessage: String = null
val m = getMessage
val push = if (m == null) new AnyRef else m
=>
iw.this.m = iw.this.getMessage();
iw.this.push = if (iw.this.m().==(null))
new Object()
else
iw.this.m();
vs
def getMessage: String = null
val push = Option(getMessage) match {
case Some(x) => x
case None => new AnyRef
}
=>
iw.this.push = {
case <synthetic> val x1: Option = scala.Option.apply(iw.this.getMessage());
case6(){
if (x1.$isInstanceOf[Some]())
{
<synthetic> val x2: Some = (x1.$asInstanceOf[Some](): Some);
{
val x: String = x2.x().$asInstanceOf[String]();
matchEnd5(x)
}
}
else
case7()
};
case7(){
if (scala.None.==(x1))
matchEnd5(new Object())
else
case8()
};
case8(){
matchEnd5(throw new MatchError(x1))
};
matchEnd5(x: Object){
x
}
};
So as long as we are not propagating null (and we don't) I don't see any advantages of the second option.
UPDATE
As requested:
val path = Option(m).getOrElse(new AnyRef)
=>
final <artifact> private[this] def $anonfun$1(): Object = new Object();
...
iw.this.path = scala.Option.apply($line13.iw.m()).getOrElse({
(() => iw.this.$anonfun$1())
});
I wouldn't consider it much better than the second option above. getOrElse hides about the same logic, and we have anonymous function since getOrElse takes by-name argument.
In fact it's not just about saving cycles. Constructing and deconstructing Option object for the sake of avoiding local null? Or saving one line? I would totally accept it if we used Option for passing it further.

Storing an anonymous function passed as a parameter in a Map

I'm trying to implement a simple web application server as a personal project to improve my Scala, but I've hit upon a problem.
I'd like to be able to set up routes using code like the following:
def routes()
{
get("/wobble")
{
...many lines of code here...
}
get("/wibble")
{
...many lines of code here...
}
post("/wibble")
{
...many lines of code here...
}
post("/wobble")
{
...many lines of code here...
}
}
routes is called by the server when it starts and get and post are functions defined by me like this:
get(url:String)(func:()=>String)=addroute("GET",url,func)
post(url:String(func:()=>String)=addroute("POST",url,func)
addroute(method:String,url:String,f:()=>String)
{
routesmap+=(method->Map[String,()=>String](url,func))
}
Unfortunately, I've had nothing but problems with this. Could anyone tell me the correct way in Scala to add an anonymous function (as passed in as a parameter in the defined routes function above) to a Map (or any other Scala collection for that matter)?
Here is a working example:
scala> var funcs = Map[String,(Int)=>Int]()
funcs: scala.collection.immutable.Map[String,Int => Int] = Map()
scala> funcs += ("time10", i => i * 10 )
scala> funcs += ("add2", i => i + 2 )
scala> funcs("add2")(3)
res3: Int = 5
scala> funcs("time10")(10)
res4: Int = 100
You can also add a declared function:
val minus5 = (i:Int) => i - 5
funcs += ( "minus5", minus5)
Or a method:
def square(i: Int) = i*i
funcs += ("square", square)
In your case, you can have two maps, one for GET and one for POST. It should simplify the design (and at most, you will end with four maps if you include DEL and PUT).
May be, this one ? :
type Fonc = ( (=> String) => Unit)
var routesmap = Map[String,Map[String,()=>String]]()
def addRoute(method:String,url:String,f:()=>String) = {
routesmap+=(method-> (routesmap.getOrElse(method,Map[String,()=>String]()) + (url->f)))
}
def get(url:String):Fonc = (x => addRoute("GET",url,() => x))
def post(url:String):Fonc = (x => addRoute("POST",url,() => x))
def routes()
{
post("/wobble")
{
"toto"
}
get("/wibble")
{
"titi"
}
}
you can try this code :
def addRoute(method:String,url:String,f:()=>String) = {
routesmap+=(method-> (routesmap.getOrElse(method,Map[String,()=>String]()) + (url->f)))
}
def get(url:String,func:()=>String)= addRoute("GET",url,func)
def post(url:String,func:()=>String)= addRoute("POST",url,func)
def routes()
{
get("/wobble",()=>{"toto"})
get("/wibble",()=>{println("test")
"titi"})
}
and execute these commands
scala> routes
scala> routesmap.get("GET").get("/wibble")()

Functional way to update an object based on flags

suppose you are writing a class that normalizes strings. That class has a number of configuration flags. For example:
val makeLowerCase: Boolean = true
val removeVowels: Boolean = false
val dropFirstCharacter: Boolean = true
If I were writing mutable code, I would write the following for the normalize method.
def normalize(string: String) = {
var s = string
if (makeLowerCase) {
s = s.toLowerCase
}
if (removeVowels) {
s = s.replaceAll("[aeiou]", "")
}
if (dropFirstCharacter) {
s = s.drop(1)
}
s
}
Is there a clean and easy way of writing these without mutation? Nested conditionals becomes nasty fast. I could create a list of String=>String lambdas, filter it based on the configuration, and then fold the string through it, but I hope there is something easier.
Your best bet is to define your own method:
class ConditionalMapper[A](a: A) {
def changeCheck(p: A => Boolean)(f: A => A) = if (p(a)) f(a) else a
def changeIf(b: Boolean)(f: A => A) = if (b) f(a) else a
}
implicit def conditionally_change_anything[A](a: A) = new ConditionalMapper(a)
Now you chain these things together and write:
class Normer(makeLC: Boolean, remVowel: Boolean, dropFirst: Boolean) {
def normalize(s: String) = {
s.changeIf(makeLC) { _.toLowerCase }
.changeIf(remVowel) { _.replaceAll("[aeiou]","") }
.changeIf(dropFirst){ _.substring(1) }
}
}
Which gives you:
scala> val norm = new Normer(true,false,true)
norm: Normer = Normer#2098746b
scala> norm.normalize("The Quick Brown Fox Jumps Over The Lazy Dog")
res1: String = he quick brown fox jumps over the lazy dog
That said, the mutable solution is not bad either--just keep it to a small block and you'll be fine. It's mostly a problem when you let mutability escape into the wild. (Where "the wild" means "outside your method, or inside any method more than a handful of lines long".)
If you use scalaz |> operator or have a similar one defined in your utility classes you can do this:
case class N(
makeLowerCase: Boolean = true,
removeVowels: Boolean = false,
dropFirstCharacter: Boolean = true) {
def normalize(string: String) = (
string
|> (s => if (makeLowerCase) s.toLowerCase else s)
|> (s => if (removeVowels) s.replaceAll("[aeiou]", "") else s)
|> (s => if (dropFirstCharacter) s.drop(1) else s)
)
}
N(removeVowels=true).normalize("DDABCUI")
// res1: String = dbc