Scala function allowing only certain strings to be passed


#1

Hey there,

I have an object defining some css styles like this:

object Styles {
  def larger = "font-size: 12pt"
  def important = "font-weight: bold"
  def unimportant = "color: #bbb"
}

Now I have this function generating a style:

object Helpers {
  def css(styles: String*) = styles.mkString(";") + ";"
}

My Question is: How can I restrict the parameters passed to css to those defined in Styles.

And … one more question. Somewhere in my code, I define a function called title:

def title(caption: String, styles: String*) = {
   // ... 
   css(styles:_*) 
   // ...
}

It eventually calls my css function passing some varargs. Let’s assume I want any title to be large. I could do something like larger + ";" + css(styles:_*) but this requires me to rewrite the “logic” on how strings get joined. Is there any way I could merge append larger to my varargs before passing them? And is there any way to restrict the parameters passed to title to those defined in Styles excluding larger (as it is supposed to be set by default).

Thanks, Simon


#2

One option for more type safety would be wrapping your Strings in some wrapper class. This class could have some combine method, and you could also define an implicit conversion to a plain String to be able to use String’s methods. Something along the lines of:

case class Style (style:String) { def combine(s: Style) : Style = ??? }

object larger extends Style(“font-size : 12pt”)
object important …

def css(styles: Style*) = styles.reduceLeft(_.combine)

then you can do:
larger combine css(someStyles)

with an implicit conversion in scope ( something like implicit def styleToString(s: Style): String= s.style )
you could use all String utility methods on your Styles, ie. you could do like larger.toUpperCase, without having to manually unwrap the String all the time.


#3

You may want to take a look at refined types,
for example https://github.com/fthomas/refined


#4

The wrapper approach is the right one for your problem. Just fyi, there is a CSS library for Scala: https://japgolly.github.io/scalacss/book/index.html


#5

I use unboxed “tagged types” to solve this kind of problem. Works very well. (See, for example, this O/S version: https://github.com/softwaremill/scala-common#tagging).

I haven’t seriously looked at “refined” types, which I believe is similar, so that might be worth looking at too.

Brian Maso