constraints on constructor parameters - scala

Excuse me, but I'm new to Scala.
I have a abstract class and a concrete class that inherits from the abstract class and implements its fields.
abstract class Element {
var name: String
var description: String
}
class ConcreteElement (var name: String, var description: String)extends Element
Is this right? Yes?
I have many classes that inherit from abstract class Element.
Now I want to put a check on the variable name, that I want to instantiate name only in accordance with certain constraints. Where do I put this control? Obviously in abstract class Element.
In Scala A variable declaration var x: T is equivalent to declarations of a getter function x and a setter function x_=, defined as follows:
def x: T
def x_= (y: T): Unit
So I decided to declare the variables in this way and posizionere my constraints in the getter method name.
abstract class Element {
def name: String
def name_= (y: String): Unit = {CONSTRAINT}
var description: String
}
class ConcreteElement (var name: String, var description: String)extends Element
This reasoning is correct?
ConcreteElement actually implements the fields of Element?

Your def name_= works only if it has not been overriden by the sub-class. So I guess you need final to prevent it being overriden.
abstract class Element {
protected var _name: String
final def name: String = _name
final def name_= (value: String) {
if (isBadValue(value)) throw new IllegalArgumentException
_name = value
}
var description: String
}
class ConcreteElement (protected var _name: String, var description: String) extends Element

Related

Scala - object extends abstract class and takes parameters

//File Animal.scala
abstract class Animal {
val name: String
def getSomething(tClass: TypeClass): String = {
tClass.tName.split('.').lift(0)
}
def apply(tClass: TypeClass): SomeOtherClassType = {
// something...
}
// File: DogSpike, this is used for some specific cases (overwrites
base class val)
object DogSpike extends Animal {
override val name: String = "Spike"
}
this call then works (calls apply)
myTransformation(() => DogSpike(this))
Now I would like to create a more generic object that one can pass arguments but I am unable to.
It would work to create a derived Object from Animal that takes one arguments and being able to use the apply call
object TheDog(name: String) extends Animal {
override val name: String = "Spike"
//...
}
not sure how to implicitly call Animal.apply for TheDog object where I could pass a parameter (name)
myTransformation(() => TheDog(this))
// also this seems to be incorrect "*Wrong top statement declaration*"
object TheDog(val n: String) extends Animal {
override val name: String = n
//...
}
As of *Wrong top statement declaration* (I can understand only this part of your question) - you can't have constructor in object as object is a singleton, so you should use a case class (ADT):
final case class TheDog(name: String) extends Animal
scala>TheDog("Spike")
res2_2: TheDog = TheDog("Spike")
val and companion object with apply is added automatically for case classes, so you don't need to define your own own apply in Animal. case class TheDog(val name: String) is same as case class TheDog(name: String).
I's also use traits instead of abstract class:
trait Animal {
val name: String
def getSomething: String = {
"Dog: " + name
}
}
I don't understand your TypeClass type, but if you really want type classes:
trait Animal {
def name: String
}
final case class TheDog(name: String) extends Animal
final case class TheCat(name: String) extends Animal
implicit class RichDog(dog: TheDog){
def getSomething: String = {
"Dog" + dog.name
}
}
implicit class RichCat(cat: TheCat){
def getSomething: String = {
"Cat: " + cat.name
}
}
scala> TheDog("Spike").getSomething
res4_5: String = "DogSpike"
scala> TheCat("Tom").getSomething
res4_6: String = "Cat: Tom"
About calling apply "implicitly", I don't know why would anyone need this, but:
trait AnimalFactory[A <: Animal] {
def apply(name: String)(implicit constructor: String => A) = constructor(name)
}
object TheeeDog extends AnimalFactory[TheDog]
implicit def createDog(name: String) = TheDog(name)
TheeeDog("Spike")
Of course you have to provide createDog and make it visible for a client, but it doesn't really make sense if you can just use ADTs and define additional required applys in companion object:
case class TheMouse(name: String)
object TheMouse{
def apply(isJerry: Boolean): TheMouse = if (isJerry) TheMouse("Jerry") else TheMouse("NotJerry")
}
TheMouse(true)
If you want to add some parameter to constructor, just add it:
class AnimalFactory(clazz: SomeClass){
def doSomething = clazz.name
def apply(name: String)
}
val dogFactory = new AnimalFactory(dogClassDescriptor)
val catFactory = new AnimalFactory(catClassDescriptor)
dogFactory("Spike")
catFactory("Tom")
You can even create a factory for factory (I wouldn't recommend - this solution already looks overcomplicated):
object AnimalFactory{ //please don't use classes for that - avoiding `new` is not their purpose
def apply(clazz: SomeClass) = new AnimalFactory(clazz)
}
val dogFactory = AnimalFactory(dogClassDescriptor)
//or even `val spike = AnimalFactory(dogClassDescriptor)("Spike")`
But still what's the point if you could just provide underlying clazz either as a member or just in a wrapper:
final case class ClazzWrapper[T <: Animal](clazz: SomeClass, animal: T)

Extend trait with private constructor parameter

In Scala, how can I extend a trait in a class with private constructor parameter that is defined in the trait?
trait Parent {
protected def name: String
require(name != "", "wooo problem!")
}
class Child(private val name: String) extends Parent {
println("name is " + name)
}
The above class gives an error:
class Child needs to be abstract, since method name in trait Parent of type ⇒ String is not defined.
Of-course I can:
make the Child class abstract,
define it without using the private in the constructor like class Child(val name: String).
make the Parent an abstract class instead of a trait
But with the above implementation, is there no way I can have a private constructor parameter while extending a trait? Note that I want the variable to be private so that I should not be able to do childInstance.name.
Try this
trait Parent {
protected def name: String
require(name != "", "wooo problem!")
}
class Child(override protected val name: String) extends Parent {
val publicVar = "Hello World"
println("name is " + name)
}
def main(args: Array[String]): Unit = {
val child = new Child("John Doe")
println(child.publicVar)
println(child.name) // Does not compile
}
You will not be able to access to child.name
If you have an abstract method in a trait, then all the derived classes need to have the same (or more permissive) modifier (in your case at least protected) for the abstract methods.
trait Parent {
protected def name: String
require(name != "", "wooo problem!")
}
class Child(private val privateName: String) extends Parent {
override protected def name: String = privateName
println("name is " + name)
}
You can keep your constructor private, but you need to define the override protected def name: String and make use of the private value of your constructor.

Access a field created by the constructor in an abstract class (Scala)

I have an abstract class that implements one method.
How can I access the parameter internalValue (set by the abstract class constructor?)
abstract class Value(internalValue:Int) {
def equal( v:Value ): Boolean
def notEqual( v:Value ): Boolean = {
//here I get an error on v.internalValue:
//"value internalValue is not a member of Value"
(internalValue != v.internalValue)
}
}
case class Value1(internalValue:Int) extends Value(internalValue){
def equal( v:Value1 ): Boolean = {
//this works correctly
(internalValue == v.internalValue)
}
}
Thank you.
Define internalValue to be val:
abstract class Value(val internalValue: Int)
or if you are concerned about encapsulation (which the name internalValue suggests) you can use private val:
abstract class Value(private val internalValue: Int)
Not declaring any modified at all is effectively equivalent (?) similar to private[this] which means: only this particular instance of Value can access this private field.

Can I provide a default value for an abstract type in Scala?

I have a class like this:
abstract class CrudResource extends Controller {
type ResourceIdType
def getAction(id: ResourceIdType) = ...
def deleteAction(id: ResourceIdType) = ...
...
}
which is intended to be used like so:
class Payees extends CrudResource {
type ResourceIdType = Int
...
}
I'd like to default the ResourceIdType to Int, like so:
abstract class CrudResource extends Controller {
type ResourceIdType = Int
...
}
so that the ID type will be Int unless a subclass overrides it like so:
override type ResourceId = String
but this fails to compile with:
error: overriding type ResourceIdType in class CrudResource, which equals Int;
type ResourceIdType has incompatible type
class Payees extends CrudResource { override type ResourceIdType = String }
Is it possible to do what I'm trying to do? I tried, in CrudResource, type ResourceIdType <: Any = Int, but that's not valid syntax.
That would be a violation of the liskov substitution principle. Let's assume you can do it.
abstract class CrudResource extends Controller {
type ResourceIdType = Int
def resources: List[ResourceIdType] = ???
def getAction(id: ResourceIdType) = ???
def deleteAction(id: ResourceIdType) = ???
}
class Payees extends CrudResource {
override type ResourceIdType = String
}
class Trouble {
var resource: Controller.ResourceIdType
}
val trouble = new Trouble
val crudResource: CrudResource = new Payee
trouble.resource = crudResource.resources.head // assigning String to Int var!
However, you are halfway to a cake pattern. If you define ResourceId as an abstract nested class, you could have subclasses implementing them in terms of Int or String, as long as its API doesn't expose the specific types.
Not sure if you can really do this, but generics and inheritance can do it in a nice way:
abstract class CrudController [T] {
def getAction( resource : T )
def deleteAction( resource : T )
def updateAction( resource : T )
}
abstract class IntCrudController extends CrudController [Int]
class PayeesController extends IntCrudController {
override def getAction( resource : Int ) {}
def deleteAction(resource: Int) {}
def updateAction(resource: Int) {}
}
No, as far as I know, this isn't possible.
Scala's abstract type become frozen once you define it. You can't override one type with another in a inherited class

Using scala constructor to set variable defined in trait

If I understand correctly, traits are the closest thing to Java interfaces and class constructors automatically set the variables.
But what if I have a class that extends a trait and has a constructor which sets a variable from the trait, so something like:
trait Foo {
var foo: String
}
class Bar (foo: String) extends Foo { /* ... */ }
Where I want the foo string of the trait been set when I make a Bar object.
The compiler seems to give me errors about this. What is the correct way to achieve this?
trait Foo { var foo: String = _ }
class Bar(foo0: String) extends Foo { foo = foo0 }
The trait declares an uninitialized var; the class then sets it equal to the input parameter.
Alternatively,
trait Foo {
def foo: String
def foo_=(s: String): Unit
}
class Bar(var foo: String) extends Foo {}
declares the getter/setter pair corresponding to a foo, which are set by the class.
Bar must define the abstract var foo in Foo (would be the same for a val). This can be done in the constructor
class Bar(var foo: String) extends Foo{...}
(of course, it could be done in the body of Bar too). By default, constructor parameters will be turned to private val if need be, that is if they are used outside the initiailization code, in methods. But you can force the behavior by marking them val or var, and possibly control the visibility as in
class X(protected val s: String, private var i: Int)
Here you need a public var to implement Foo.