I'm wondering if its possible to have Enumerations with one value parametrized.
Something like:
object Animal extends Enumeration {
val Dog = Value("dog")
val Cat = Value("cat")
val Other = Value(?)
def create(value: String): Animal.Value = {
Animal.values.find(_.toString == value).getOrElse(Other(value))
}
}
And, for use, something like:
create("dog") // will return Animal.Dog
create("giraffe") // will return Animal.Other
create("dog").toString // will return "dog"
create("giraffe").toString // will return "giraffe"
That is, to be able to have some values typed, but to leave one free.
Thanks!!!
Lucas.
I have to apologize for jumping the gun. I was thinking in Java terms, where an enum is a very rigid thing. Scala, however, is a bit more flexible in that regard. Enumeration does not stop us from extending the enumeration class ourselves.
Disclaimer: This is probably not a good idea. It works, but I don't know how it will behave with respect to serialization or the other nice properties that ordinary enumerations have. So if it works for you, great! But I can't promise that it's a good solution.
object Animal extends Enumeration {
val Dog = Value("dog")
val Cat = Value("cat")
def create(value: String): Animal.Value = {
Animal.values.find(_.toString == value).getOrElse(OtherAnimal(value))
}
}
// Extending the enumeration class by hand and giving it a `String` argument.
case class OtherAnimal(name: String) extends Animal.Value {
override def id = -1
override def toString = name
}
println(Animal.create("dog").toString) // dog
println(Animal.create("cat").toString) // cat
println(Animal.create("giraffe").toString) // giraffe
Related
I need to change an object's behavior on run-time.
I have two concrete object (singleton) classes Dog and Cat, both extend from an abstract class Animal.
The object animal of Animal type should be changed to either Dog or Cat on runtime.
Here's the rough code of something that I am trying to accomplish:
abstract class Animal() {
def sound: Unit
}
object Cat extends Animal {
def sound: Unit = {
print("meow")
}
}
object Dog extends Animal {
def sound: Unit = {
print("bark")
}
}
object MyProgram {
val animal: Animal = _
def initialize(config: Config): Unit ={
// check the config
if (config.getString("ANIMAL_TYPE").equals("Dog")) {
animal = Dog
} else {
animal = Cat
}
}
def run: Unit = {
animal.sound
}
}
def main(): Unit = {
val config = ConfigFactory.praseFile(myconfigfile)
MyProgram.initialize(config)
MyProgram.run
}
Can something like this be done in Scala? If not, how can I accomplish this in Scala.
The error you are getting has nothing to do with typing or dynamic polymorphism:
var animal : Animal = _
^
On line 19: error: local variables must be initialized
As you can see, there is nothing wrong with the types in your program, you simply need to properly initialize your variable:
def main() : Unit = {
var animal = if(config.getString("ANIMAL_TYPE").equals("Dog")) {
Dog
} else {
Cat
}
// this should print either bark or meow
animal.sound
}
Note that there are a couple of non-idiomatic things in your code. A more idiomatic version would look something like this:
trait Animal {
val sound: String
}
object Cat extends Animal {
override val sound = "meow"
}
object Dog extends Animal {
override val sound = "bark"
}
def main(): Unit = {
val animal = if (config.getString("ANIMAL_TYPE").equals("Dog")) Dog else Cat
// this should print either bark or meow
print(animal.sound)
}
Use a trait instead of an abstract class.
Don't use an empty constructor / initializer, just use no constructor / initializer.
Separate input/output from computation: the printing should be done in the main method, not in the Animal.
Use the explicit override modifier.
Don't use type annotations if the type is obvious.
Don't use curly braces around single expressions.
Don't use var, always use val.
if is an expression, don't ignore its return value.
You are defining the main function incorrectly.
The main function should be a member of some object, and it should have an argument of the type Array[String].
object SomeRandomName {
def main(): Unit = {
var animal: Animal = null
// check the config
if(config.getString("ANIMAL_TYPE").equals("Dog")) {
animal = Dog
} else {
animal = Cat
}
// this should print either bark or meow
animal.sound
}
}
And this code should compile and run well.
SIDENOTE: If you are using Scala 3 (instead of Scala 2.x), then you don't need to make a wrapper object of the main function. The function can be at the top level.
Your code should work almost as it is, just assign something to animal.
object MyProgram {
//First of all use some default value for animal.
//It will be safer to use.
var animal: Animal = Cat
// or use explicitly null if there is no sensible default value.
// underscore makes it less clear what will happen.
//var animal: Animal = null
//I thing match is better than if/else here especially when third animal will arrive. You can assign it like that:
def initialize(config: Config): Unit ={
animal = (config.getString("ANIMAL_TYPE") match {
case "Dog" => Dog
case _ => Cat
}
}
}
What is the FP idiomatic way for this: let's say I have this
trait Name
object Name{
def apply(name: String): Name = {
if (name.trim.isEmpty || name.trim.length < 3)
InvalidName
else
ValidName(name.trim)
}
}
case object InvalidName extends Name
case class ValidName(name:String) extends AnyVal with Name
Now I have some helper functions such as
def split = name.splitAt(" ")
//some more functions
which way is more idiomatic:
Put them in the case class it self but that some how makes the case class to contain some logic however I can do something like :
val n = ValidName("john smith")
val (first, last) = n.split
Put them in dedicated object but then the method will look like
def split(n: ValidName) = n.name.splitAt(" ")
Create an object with implicit class that will accept Name and will call the methods
What do you think ?
There is no major issue with adding logic to a case class, especially when it is just extracting the data in a different format. (It becomes problematic when you add data members to a case class).
So I would do option 1 and not worry about it!
In response to the comments, case class is actually just a shortcut for creating a class with a whole bunch of useful pre-implemented methods. In particular, the unapply method allows a case class to be used in pattern matching, and equals does an element-wise comparison of the fields of two instances.
And there are a bunch of other methods to extract the data from the case class in different ways. The most obvious are toString and copy, but there are others like hashCode and all the stuff inherited from Product, such as productIterator.
Since a case class already has methods to extract the data in useful ways, I see no objection to adding your split method as another way of extracting data from the case class.
More idiomatic:
case class Name private (name: String) {
lazy val first :: last :: Nil = name.split(" ").toList
}
object Name {
def fromString (name: String): Either[String, Name] = {
if (name.trim.isEmpty || name.trim.length < 3) Left("Invalid name")
else Right(new Name(name.trim))
}
}
Or maybe this:
case class Name (first: String, last: String) {
lazy val fullName = s"$first $last"
}
object Name {
def fromString (name: String): Either[String, Name] = {
if (name.trim.isEmpty || name.trim.length < 3) Left("Invalid name")
else {
val first :: last :: Nil = name.split(" ").toList
Right(new Name(first, last))
}
}
}
In scala it's more idiomatic to represent failure cases through the use of Either than through inheritance. If you have an instance of N, you can't call any functions on it, you'll probably have to pattern match it. But a type like Either already comes with functions like map, fold, etc. that makes it easier to work with.
Having a private constructor helps ensure that you can only create a valid Name because the only way to create one is through the fromString method.
DO NOT use implicits for this. There's no need and would only make for confusing code. Not really what implicits are for.
I think it depends on context. In this case, if most of the methods you are using are just slight tweaks to String methods, you might want to consider a fourth option:
case class Name(name: String)
implicit def NameToString(n: Name) = n.name
Name("Iron Man").split(" ") // Array(Iron, Man)
To get more type safety in our code base we have started to replace generic Strings, Ints etc. with type safe value classes, but I am struggling to get them working conveniently with the == operator and literals. Hopefully someone can help me out.
Our value classes are defined and used like this:
case class Name(value: String) extends AnyVal {}
object Name { implicit def to(something:String): Name = Name(something) // convenience }
case class Address(value: String) extends AnyVal {}
object Address { implicit def to(something:String): Address = Address(something) // convenience }
case class Person(name: Name, address: Address) {
def move(newAddress: Address) = copy(address=newAddress)
}
val somebody = Person("Pete", "Street 1")
somebody.move(Address("Street 2")) // allowed
somebody.move(somebody.name) // not allowed, which is exactly what we want
somebody.move("Street 2") // allowed by convenience
Now, I would like them to compare "naturally" on their inner value:
Name("Pete") == "Pete" // should be true, but evaluates to False
I can sort of fix this by overriding equals like this:
case class Name(value: String) extends AnyVal {
override def equals(other: Any) =
if (other.isInstanceOf[Name])
other.asInstanceOf[Name].value == this.value
else if (other.isInstanceOf[String])
other == this.value
else
false
}
Name("Pete") == "Pete" // now evaluates to true
However, this solution is not symmetric:
"Pete" == Name("Pete") // evaluates to false, because it is using String.equals
I do not know how to fix this. Not even declaring an implicit conversion from Name to String helps (and I would much prefer not to have such a thing). Is it possible to do what I am trying to do?
EDIT: I probably failed to be clear on this, but I am not really looking for advice on software development. This is meant to be a technical question: Can it be done in Scala or not?
I have some reasons for doing what I have described, but sadly they relate to a codebase of tens of thousands of lines of Scala code, and cannot be conveyed in a short stack overflow question.
I think, you should just get rid of your convenience implicits instead. They defeat the purpose:
val john = Person("Street 1", "John") // mixed up order
john.move("Pete") // Yup, I can "move" to a name ...
Now, john is someone named "Street 1", and living at address "Pete". This isn't something that you want to be allowed after going with the trouble of defining all the value classes.
I don't think == can be made to work in this situation. What you might do is define a different comparison operation.
case class Name(value: String) extends AnyVal {
def is(n: Name): Boolean = value == n.value
}
You'll also have to broaden the scope of the implicit converter so that it can be accessed for these conversions.
implicit def toName(something:String): Name = Name(something) // not in object
Now this works.
val somebody = Person("Pete", "Street 1")
somebody.move(Address("Street 2")) // allowed
somebody.move("Street 2") // allowed by convenience
somebody.name is "Pete" // true
"Pete" is somebody.name // true
I have a situation where I am trying to create a generic function which should be able to take any instance of a class which specifies a certain implicit value in its companion object. I have replicated my problem below:
// Mocking up the library I am working with
trait Formatter[A] {
def output(o: A): String
def input(s: String): A
}
// Some models
trait Human
case class Child(name: String) extends Human
object Child {
implicit val f: Formatter[Child] = new Formatter[Child] {
override def output(c: Child): String = { ... }
override def input(s: String): Child = { ... }
}
}
case class Teen(name: String) extends Human
object Teen {
implicit val f: Formatter[Teen] = new Formatter[Teen] {
override def output(t: Teen): String = { ... }
override def input(s: String): Teen = { ... }
}
}
// The generic function
def gen[A <: Human](a: A)(implicit format: Formatter[A]) = {
// Do something with a formatter...
}
This all works fine, I can pass an instance of a Child or a Teen to my gen function:
gen(Child("Peter"))
gen(Teen("Emily"))
What I am having trouble with is that at run time I only know that the instance I am passing will be a subtype of a Human:
// Example of unknown subtype
val human: Human = Random.nextBoolean match {
case true => Child("Peter")
case false => Teen("Emily")
}
gen(human) // Error: Could not find implicit value for parameter format...
I understand that the error is because Human has no companion object and therefore it has no implementation of a Formatter.
How can I add a constraint to Human that says "anything extending Human will implement a new Formatter" ?
Your scenario fails because you should implement a Formatter[Human]. I think that what you want is that all the Human should be able to have this format "capability" instead.
At this point you have two options, one is to include in the Human trait a method for formatting (this implementation could be in the object if you want it static) or try a dsl approach where you will create a class with the responsibility to provide humans a new capability: "format".
The first approach could be something like this:
trait Human { def format:String }
case class Child(name: String) extends Human {
import Child._
override def format = Child.staticFormat(this)
}
object Child {
def staticFormat(c: Child): String = s"Child(${c.name})"
}
However I think "format" shouldn't be in the contract "Human" so I prefer the second approach:
trait Human
case class Child(name: String) extends Human
case class Teen(name: String) extends Human
import scala.language.implicitConversions
class HumanFormatter(human: Human) {
def format: String = human match {
case c: Child => s"Child(${c.name})"
case t: Teen => s"Teen(${t.name})"
}
}
object HumanDsl {
implicit def humanFormatter(human: Human): HumanFormatter = new HumanFormatter(human)
}
object Test extends App {
def human: Human = Random.nextBoolean match {
case true => Child("Peter")
case false => Teen("Emily")
}
import HumanDsl._
for(i <- 1 to 10) println(human.format)
}
What are the differences between both solutions?
In the first one you force all the new Human classes to implement a format method so you can assure that your code will work always. But at the same time... you are adding a Human a method that from my point of view is not necessary, I think a case class should have only the information needed and if you need to format/parse that class then is better to add this functionality just when needed (dsl approach).
In the other hand, with dsl you should update the formatter anytime a new Human class is created. So it means that the human.format method above will fail if a new Human class is created (you can always match _ to do a default behaviour or raise a custom error).
I think is a matter of design, I hope this would help you a little bit.
Edited:
just like a comment showed the Human trait could be sealed to ensure that the HumanFormatter pattern match doesn't compile if some class is not covered.
You don't need implicits for this.
Just make your subclasses point to the implementation directly:
trait Human[+A <: Human] {
def formatter: Formatter[A]
}
case class Child(name: String) extends Human[Child] {
def formatter = Child.f
}
// etc
def gen[A <: Human](a: A) {
// do something with a.formatter
}
Of course, Formatter needs to be covariant in A too. Otherwise, all bets are off: you simply cannot do what you want - there is nothing useful gen could do with it without knowing the specific type anyway.
If specifics of the concrete type are not needed in gen, you can still use implicits by enumerating them explicitly like this (but I don't really see why you would want that):
object Human {
implicit def formatter(h: Human): Formatter[_] = h match {
case Child(_) => Child.f
case Teen(_) => Teen.f
}
}
gen(h: Human)(implicit f: Formatter[_]) { ... }
Like I said, this does not seem very useful though, so not sure why you want want this over the above approach.
I want to make the following example so that Collar is immutable
trait Collar{
var text:String="";
}
class dog(val name:String){
def bark()= ...
}
val snoopy = new dog("snoopy") with Collar;
snoopy.text="charley's dog";
println(snoopy.text)
However when I try something like
trait Collar(val text:String){
}
I get the compile time error
traits or objects may not have parameters
Is there currently a a way to do this? If not, why not?
Remember, a good dog shouldn't care when it has a Collar.
Not at all sure what your real question is, but perhaps this is what you're looking for:
trait Collar{
val tagText: String // 'val', not 'var'; left undefined here
}
class Dog(val name:String) {
def bark()= ...
}
val snoopy = new Dog("snoopy") with Collar {
val tagText= "charley's dog"
}
println(snoopy.tagText)
Alternatively, Collar.tagText can be set with an initial/default value AND also be overridden where Dog is instantiated.