Scala: restrict parameter values - scala

Is there a way to restrict the values of a parameter in a Scala function? For example, if I have one paramater called flag and I only want the user to be able to submit the values 0 or 1 as valid values for that parameter.
I know I could write a simple if statement that checked the values and returned an error message of some sort if it isn't acceptable, but I thought there might be a more succinct way to do it, say when the parameter is named in the function declaration.

What you want is "dependent typing". This sort of call would be a compile error in a language with support for it. Unfortunately scala doesn't support it.
Two typical workarounds would be to use an ADT instead of the larger type, or a wrapper with a restricted method of construction.
object ZeroOrOne {
def apply(i: Int): Option[ZeroOrOne] = if (i == 0 || i == 1) Some(ZeroOrOne(i)) else None
}
case class ZeroOrOne private (i: Int)
def doStuff(zo: ZeroOrOne) { // use zo.i }
or
sealed trait EnableStatus
case object Enabled extends EnableStatus
case object Disabled extends EnableStatus
def setEnabled(es: EnableStatus)

The way I would typically approach this in Scala is to make a base trait with case objects:
sealed trait Color
case object Red extends Color
case object Green extends Color
case object Blue extends Color
//...
def myFn(arg:Color) = //...

Related

How to make an Scala Enumeration implement a Trait without modifying the original Enum?

I'm toying with Scala for the first time so bear with me. Also using tapir to declare an API, where I'm having issues providing a Schema for an enum.
I have a bunch of enums defined that are part of my domain model and that extend Scala's Enumeration. For instance, this is one of them:
object Status extends Enumeration with JsonEnumeration {
val Active, Completed, Archived, Deleted = Value
}
And also have many case classes that uses them. For instance, Order uses our previously defined enumeration, like:
case class Order(
id: String,
name: Option[String],
status: Status.Value,
)
I want to make this enum implement a trait that adds an implicit, but without modifying the original Status enumeration (I don't want to couple the Status enum -and all the others- to this trait).
The trait looks like:
import sttp.tapir.{Schema, Validator}
trait TapirEnumeration { e: Enumeration =>
implicit def schemaForEnum: Schema[e.Value] =
Schema.string.validate(Validator.enumeration(e.values.toList, v => Option(v)))
}
I wanted to somehow modify the Order object so the Status enum is now a TapirStatus enum (or something like that) which extends both the original Status and TapirEnumeration, but I don't think that can be doable, given that Status is originally defined as a companion object.
Ideally, all the enums I want to expose as responses from my API will implement that TapirEnumeration trait while still extending what they already extend.
What can I do to achieve this? Of course, creating a new enum that implements the trait isn't DRY so it's not an option.
Why does implicit need to be defined in the enum itself in the first place? Just make it its own definition.
import scala.language.implicitConversions
object EnumImplicits {
implicit def schema[E <: Enumeration](e: E): Schema[e.Value] = ???
}
Then, wherever you need access to that implicit you just make it available with import EnumImplicits._
Here is an example

Checking derived class arguments in Scala

Assume the following pair of classes:
class A(arg:String)
class B(argList:Vector[String]) extends A(argList.first)
I want to be able to check for argList being empty before providing the base class constructor with its first element. Unfortunately, placing that check in the default constructor for B (e.g through require, as shown here) is way too late, since the base class' constructor will need to be called first.
This is probably a more general OOP question, but the solution is likely to be Scala-specific.
What do you expect to pass if argList is empty? In any case, you could just use the following:
class B(argList:Vector[String]) extends A(argList.headOption.getOrElse("your default string here")
One way to deal with this is via a companion object. You can mark the constructor for B as private to ensure no-one can by-pass the check, then add a suitable apply method to the companion object that pre-checks the input value(s):
class A(arg:String)
class B private(argList:Vector[String]) extends A(argList.head)
object B {
def apply(argList:Vector[String]): B = argList.headOption.map(_ => new B(argList)).getOrElse(throw new RuntimeException("Oops"))
}
Usage examples:
scala> B(Vector("foo", "bar"))
res2: B = B#328e9109
scala> B(Vector())
java.lang.RuntimeException: Oops
at B$$anonfun$apply$2.apply(<console>:24)
...
Note that for simplicity's sake, I simply throw an exception when handling bad data, but would probably try some other way of handling this situation (a default value per #Zoltan's answer is one such way).
That's why in most places constructors are replaced by factory objects. In Scala it's idiomatic to use companion object as such factories.
class A(arg: String)
abstract class B(arg: String) extends A(arg) {
def argList: IndexedSeq[String]
}
object B {
case object Empty extends B("") {
def argList = IndexedSeq.empty
}
case class NonEmpty private[B](argList: Vector[String]) extends B(argList.head)
def apply(argList: Vector[String]) =
if (argList.isEmpty) Empty else NonEmpty(argList)
def unapplySeq(b:B): Option[IndexedSeq[String]] = b match {
case Empty ⇒ Some(IndexedSeq.empty)
case NonEmpty(args) ⇒ Some(args)
}
}
you could verify that
B(Vector()) == B.Empty
B(Vector("x", "y")).isInstanceOf[B.NonEmpty]

Using value classes in scala to implement trait methods?

I have a trait that defines a function--I don't want to specify how it will work until later. This trait is mixed in with several case classes, like so:
trait AnItem
trait DataFormatable {
def render():String = "" // dummy implementation
}
case class Person(name:String, age:Int) extends DataFormatable with AnItem
case class Building(numFloors:Int) extends DataFormatable with AnItem
Ok, so now I want includable modules that pimp specific implementations of this render behavior. Trying to use value classes here:
object JSON {
implicit class PersonRender( val p:Person ) extends AnyVal {
def render():String = {
//render json
}
}
// others
}
object XML {
implicit class PersonRender( val p:Person ) extends AnyVal {
def render():String = {
//render xml
}
}
// others
}
The ideal use would look like this (presuming JSON output desired):
import JSON._
val p:AnItem = Person("John",24)
println(p.render())
All cool--but it doesn't work. Is there a way I can make this loadable-implementation thing work? Am I close?
The DataFormatable trait is doing nothing here but holding you back. You should just get rid of it. Since you want to swap out render implementations based on the existence of implicits in scope, Person can't have it's own render method. The compiler will only look for an implicit conversion to PersonRender if Person doesn't have a method named render in the first place. But because Person inherits (or is forced to implement) render from DataFormatable, there is no need to look for the implicit conversion.
Based on your edit, if you have a collection of List[AnItem], it is also not possible to implicitly convert the elements to have render. While each of the sub-classes may have an implicit conversion that gives them render, the compiler doesn't know that when they are all piled into a list of a more abstract type. Particularly an empty trait such as AnItem.
How can you make this work? You have two simple options.
One, if you want to stick with the implicit conversions, you need to remove DataFormatable as the super-type of your case classes, so that they do not have their own render method. Then you can swap out XML._ and JSON._, and the conversions should work. However, you won't be allowed mixed collections.
Two, drop the implicits altogether and have your trait look like this:
trait DataFormatable {
def toXML: String
def toJSON: String
}
This way, you force every class that mixes in DataFormatable to contain serialization information (which is the way it should be, rather than hiding them in implicits). Now, when you have a List[DataFormatable], you can prove all of the elements can both be converted to JSON or XML, so you can convert a mixed list. I think this would be much better overall, as the code should be more straightforward. What imports you have shouldn't really be defining the behavior of what follows. Imagine the confusion that can arise because XML._ has been imported at the top of the file instead of JSON._.

Custom Scala enum, most elegant version searched

For a project of mine I have implemented a Enum based upon
trait Enum[A] {
trait Value { self: A =>
_values :+= this
}
private var _values = List.empty[A]
def values = _values
}
sealed trait Currency extends Currency.Value
object Currency extends Enum[Currency] {
case object EUR extends Currency
case object GBP extends Currency
}
from Case objects vs Enumerations in Scala. I worked quite nice, till I run into the following problem. Case objects seem to be lazy and if I use Currency.value I might actually get an empty List. It would have been possible to make a call against all Enum Values on startup so that the value list would be populated, but that would be kind of defeating the point.
So I ventured into the dark and unknown places of scala reflection and came up with this solution, based upon the following SO answers. Can I get a compile-time list of all of the case objects which derive from a sealed parent in Scala?
and How can I get the actual object referred to by Scala 2.10 reflection?
import scala.reflect.runtime.universe._
abstract class Enum[A: TypeTag] {
trait Value
private def sealedDescendants: Option[Set[Symbol]] = {
val symbol = typeOf[A].typeSymbol
val internal = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol]
if (internal.isSealed)
Some(internal.sealedDescendants.map(_.asInstanceOf[Symbol]) - symbol)
else None
}
def values = (sealedDescendants getOrElse Set.empty).map(
symbol => symbol.owner.typeSignature.member(symbol.name.toTermName)).map(
module => reflect.runtime.currentMirror.reflectModule(module.asModule).instance).map(
obj => obj.asInstanceOf[A]
)
}
The amazing part of this is that it actually works, but it is ugly as hell and I would be interested if it would be possible to make this simpler and more elegant and to get rid of the asInstanceOf calls.
Here is a simple macro based implementation:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
abstract class Enum[E] {
def values: Seq[E] = macro Enum.caseObjectsSeqImpl[E]
}
object Enum {
def caseObjectsSeqImpl[A: c.WeakTypeTag](c: blackbox.Context) = {
import c.universe._
val typeSymbol = weakTypeOf[A].typeSymbol.asClass
require(typeSymbol.isSealed)
val subclasses = typeSymbol.knownDirectSubclasses
.filter(_.asClass.isCaseClass)
.map(s => Ident(s.companion))
.toList
val seqTSymbol = weakTypeOf[Seq[A]].typeSymbol.companion
c.Expr(Apply(Ident(seqTSymbol), subclasses))
}
}
With this you could then write:
sealed trait Currency
object Currency extends Enum[Currency] {
case object USD extends Currency
case object EUR extends Currency
}
so then
Currency.values == Seq(Currency.USD, Currency.EUR)
Since it's a macro, the Seq(Currency.USD, Currency.EUR) is generated at compile time, rather than runtime. Note, though, that since it's a macro, the definition of the class Enum must be in a separate project from where it is used (i.e. the concrete subclasses of Enum like Currency). This is a relatively simple implementation; you could do more complicated things like traverse multilevel class hierarchies to find more case objects at the cost of greater complexity, but hopefully this will get you started.
A late answer, but anyways...
As wallnuss said, knownDirectSubclasses is unreliable as of writing and has been for quite some time.
I created a small lib called Enumeratum (https://github.com/lloydmeta/enumeratum) that allows you to use case objects as enums in a similar way, but doesn't use knownDirectSubclasses and instead looks at the body that encloses the method call to find subclasses. It has proved to be reliable thus far.
The article "“You don’t need a macro” Except when you do" by Max Afonov
maxaf describes a nice way to use macro for defining enums.
The end-result of that implementation is visible in github.com/maxaf/numerato
Simply create a plain class, annotate it with #enum, and use the familiar val ... = Value declaration to define a few enum values.
The #enum annotation invokes a macro, which will:
Replace your Status class with a sealed Status class suitable for acting as a base type for enum values. Specifically, it'll grow a (val index: Int, val name: String) constructor. These parameters will be supplied by the macro, so you don't have to worry about it.
Generate a Status companion object, which will contain most of the pieces that now make Status an enumeration. This includes a values: List[Status], plus lookup methods.
Give the above Status enum, here's what the generated code looks like:
scala> #enum(debug = true) class Status {
| val Enabled, Disabled = Value
| }
{
sealed abstract class Status(val index: Int, val name: String)(implicit sealant: Status.Sealant);
object Status {
#scala.annotation.implicitNotFound(msg = "Enum types annotated with ".+("#enum can not be extended directly. To add another value to the enum, ").+("please adjust your `def ... = Value` declaration.")) sealed abstract protected class Sealant;
implicit protected object Sealant extends Sealant;
case object Enabled extends Status(0, "Enabled") with scala.Product with scala.Serializable;
case object Disabled extends Status(1, "Disabled") with scala.Product with scala.Serializable;
val values: List[Status] = List(Enabled, Disabled);
val fromIndex: _root_.scala.Function1[Int, Status] = Map(Enabled.index.->(Enabled), Disabled.index.->(Disabled));
val fromName: _root_.scala.Function1[String, Status] = Map(Enabled.name.->(Enabled), Disabled.name.->(Disabled));
def switch[A](pf: PartialFunction[Status, A]): _root_.scala.Function1[Status, A] = macro numerato.SwitchMacros.switch_impl[Status, A]
};
()
}
defined class Status
defined object Status

How to override apply in a case class companion

So here's the situation. I want to define a case class like so:
case class A(val s: String)
and I want to define an object to ensure that when I create instances of the class, the value for 's' is always uppercase, like so:
object A {
def apply(s: String) = new A(s.toUpperCase)
}
However, this doesn't work since Scala is complaining that the apply(s: String) method is defined twice. I understand that the case class syntax will automatically define it for me, but isn't there another way I can achieve this? I'd like to stick with the case class since I want to use it for pattern matching.
The reason for the conflict is that the case class provides the exact same apply() method (same signature).
First of all I would like to suggest you use require:
case class A(s: String) {
require(! s.toCharArray.exists( _.isLower ), "Bad string: "+ s)
}
This will throw an Exception if the user tries to create an instance where s includes lower case chars. This is a good use of case classes, since what you put into the constructor also is what you get out when you use pattern matching (match).
If this is not what you want, then I would make the constructor private and force the users to only use the apply method:
class A private (val s: String) {
}
object A {
def apply(s: String): A = new A(s.toUpperCase)
}
As you see, A is no longer a case class. I am not sure if case classes with immutable fields are meant for modification of the incoming values, since the name "case class" implies it should be possible to extract the (unmodified) constructor arguments using match.
UPDATE 2016/02/25:
While the answer I wrote below remains sufficient, it's worth also referencing another related answer to this regarding the case class's companion object. Namely, how does one exactly reproduce the compiler generated implicit companion object which occurs when one only defines the case class itself. For me, it turned out to be counter intuitive.
Summary:
You can alter the value of a case class parameter before it is stored in the case class pretty simply while it still remaining a valid(ated) ADT (Abstract Data Type). While the solution was relatively simple, discovering the details was quite a bit more challenging.
Details:
If you want to ensure only valid instances of your case class can ever be instantiated which is an essential assumption behind an ADT (Abstract Data Type), there are a number of things you must do.
For example, a compiler generated copy method is provided by default on a case class. So, even if you were very careful to ensure only instances were created via the explicit companion object's apply method which guaranteed they could only ever contain upper case values, the following code would produce a case class instance with a lower case value:
val a1 = A("Hi There") //contains "HI THERE"
val a2 = a1.copy(s = "gotcha") //contains "gotcha"
Additionally, case classes implement java.io.Serializable. This means that your careful strategy to only have upper case instances can be subverted with a simple text editor and deserialization.
So, for all the various ways your case class can be used (benevolently and/or malevolently), here are the actions you must take:
For your explicit companion object:
Create it using exactly the same name as your case class
This has access to the case class's private parts
Create an apply method with exactly the same signature as the primary constructor for your case class
This will successfully compile once step 2.1 is completed
Provide an implementation obtaining an instance of the case class using the new operator and providing an empty implementation {}
This will now instantiate the case class strictly on your terms
The empty implementation {} must be provided because the case class is declared abstract (see step 2.1)
For your case class:
Declare it abstract
Prevents the Scala compiler from generating an apply method in the companion object which is what was causing the "method is defined twice..." compilation error (step 1.2 above)
Mark the primary constructor as private[A]
The primary constructor is now only available to the case class itself and to its companion object (the one we defined above in step 1.1)
Create a readResolve method
Provide an implementation using the apply method (step 1.2 above)
Create a copy method
Define it to have exactly the same signature as the case class's primary constructor
For each parameter, add a default value using the same parameter name (ex: s: String = s)
Provide an implementation using the apply method (step 1.2 below)
Here's your code modified with the above actions:
object A {
def apply(s: String, i: Int): A =
new A(s.toUpperCase, i) {} //abstract class implementation intentionally empty
}
abstract case class A private[A] (s: String, i: Int) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
And here's your code after implementing the require (suggested in the #ollekullberg answer) and also identifying the ideal place to put any sort of caching:
object A {
def apply(s: String, i: Int): A = {
require(s.forall(_.isUpper), s"Bad String: $s")
//TODO: Insert normal instance caching mechanism here
new A(s, i) {} //abstract class implementation intentionally empty
}
}
abstract case class A private[A] (s: String, i: Int) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
And this version is more secure/robust if this code will be used via Java interop (hides the case class as an implementation and creates a final class which prevents derivations):
object A {
private[A] abstract case class AImpl private[A] (s: String, i: Int)
def apply(s: String, i: Int): A = {
require(s.forall(_.isUpper), s"Bad String: $s")
//TODO: Insert normal instance caching mechanism here
new A(s, i)
}
}
final class A private[A] (s: String, i: Int) extends A.AImpl(s, i) {
private def readResolve(): Object = //to ensure validation and possible singleton-ness, must override readResolve to use explicit companion object apply method
A.apply(s, i)
def copy(s: String = s, i: Int = i): A =
A.apply(s, i)
}
While this directly answers your question, there are even more ways to expand this pathway around case classes beyond instance caching. For my own project needs, I have created an even more expansive solution which I have documented on CodeReview (a StackOverflow sister site). If you end up looking it over, using or leveraging my solution, please consider leaving me feedback, suggestions or questions and within reason, I will do my best to respond within a day.
I don't know how to override the apply method in the companion object (if that is even possible) but you could also use a special type for upper case strings:
class UpperCaseString(s: String) extends Proxy {
val self: String = s.toUpperCase
}
implicit def stringToUpperCaseString(s: String) = new UpperCaseString(s)
implicit def upperCaseStringToString(s: UpperCaseString) = s.self
case class A(val s: UpperCaseString)
println(A("hello"))
The above code outputs:
A(HELLO)
You should also have a look at this question and it's answers: Scala: is it possible to override default case class constructor?
For the people reading this after April 2017: As of Scala 2.12.2+, Scala allows overriding apply and unapply by default. You can get this behavior by giving -Xsource:2.12 option to the compiler on Scala 2.11.11+ as well.
It works with var variables:
case class A(var s: String) {
// Conversion
s = s.toUpperCase
}
This practice is apparently encouraged in case classes instead of defining another constructor. See here.. When copying an object, you also keep the same modifications.
Another idea while keeping case class and having no implicit defs or another constructor is to make the signature of apply slightly different but from a user perspective the same.
Somewhere I have seen the implicit trick, but can´t remember/find which implicit argument it was, so I chose Boolean here. If someone can help me out and finish the trick...
object A {
def apply(s: String)(implicit ev: Boolean) = new A(s.toLowerCase)
}
case class A(s: String)
I faced the same problem and this solution is ok for me:
sealed trait A {
def s:String
}
object A {
private case class AImpl(s:String)
def apply(s:String):A = AImpl(s.toUpperCase)
}
And, if any method is needed, just define it in the trait and override it in the case class.
If you're stuck with older scala where you cant override by default or you dont want to add the compiler flag as #mehmet-emre showed, and you require a case class, you can do the following:
case class A(private val _s: String) {
val s = _s.toUpperCase
}
As of 2020 on Scala 2.13, the above scenario of overriding a case class apply method with same signature works totally fine.
case class A(val s: String)
object A {
def apply(s: String) = new A(s.toUpperCase)
}
the above snippet compiles and runs just fine in Scala 2.13 both in REPL & non-REPL modes.
I think this works exactly how you want it to already. Here's my REPL session:
scala> case class A(val s: String)
defined class A
scala> object A {
| def apply(s: String) = new A(s.toUpperCase)
| }
defined module A
scala> A("hello")
res0: A = A(HELLO)
This is using Scala 2.8.1.final