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.
Related
//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)
Upon digging it seems this is a sensitive issue.
class TestNames {
private[this] lazy val _name: String = this.getClass.getName.split("\\.").last
def name: String = _name
}
class Parent extends TestNames
class Parent2 extends Parent
class ClassNameExtraction extends FlatSpec {
it should "correctly extract the table name" in {
object TestNames extends TestNames
assert(TestNames.name === "TestNames")
}
it should "correctly extract the parent name" in {
object Parent extends Parent
assert(Parent.name === "Parent")
}
it should "correctly extract the column names" in {
object Parent2 extends Parent2
assert((Parent2.name === "Parent2"))
}
}
I can see there is a simple pattern: $$annonfun$number$ + ACTUAL_CLASS_NAME + $number$.
Is there a simpler way of doing this?
Update:
Got something working without inheritance:
import scala.reflect.ClassTag
class SomeClass {
private[this] lazy val _name: String = implicitly[ClassTag[this.type]].runtimeClass.getSimpleName
def name: String = _name
}
However this returns the same name in sub classes:
class SomeOtherClass extends SomeClass {}
object SomeOtherClass extends SomeOtherClass
SomeOtherClass.name// is still SomeClass
There is an issue:
https://issues.scala-lang.org/browse/SI-2034
Do you need a class per se or a type name? Because that's what reflection is for.
The policy is not to discuss religion, politics or name mangling.
Through this question, I found this article on the 'config' pattern from Precog. I tried this with two modules:
case class Pet(val name: String)
trait ConfigComponent {
type Config
def config: Config
}
trait Vet {
def vaccinate(pet: Pet) = {
println("Vaccinate:" + pet)
}
}
trait AnotherModule extends ConfigComponent {
type Config <: AnotherConfig
def getLastName(): String
trait AnotherConfig {
val lastName: String
}
}
trait AnotherModuleImpl extends AnotherModule {
override def getLastName(): String = config.lastName
trait AnotherConfig {
val lastName: String
}
}
trait PetStoreModule extends ConfigComponent {
type Config <: PetStoreConfig
def sell(pet: Pet): Unit
trait PetStoreConfig {
val vet: Vet
val name: String
}
}
trait PetStoreModuleImpl extends PetStoreModule {
override def sell(pet: Pet) {
println(config.name)
config.vet.vaccinate(pet)
// do some other stuff
}
}
class MyApp extends PetStoreModuleImpl with AnotherModuleImpl {
type Config = PetStoreConfig with AnotherConfig
override object config extends PetStoreConfig with AnotherConfig {
val vet = new Vet {}
val name = "MyPetStore"
val lastName = "MyLastName"
}
sell(new Pet("Fido"))
}
object Main {
def main(args: Array[String]) {
new MyApp
}
}
However, I get this compile errror:
overriding type Config in trait AnotherModule with bounds <: MyApp.this.AnotherConfig;
type Config has incompatible type
type Config = PetStoreConfig with AnotherConfig
It is not clear to me why this should not work (Precog also uses two components in their example), any ideas?
You define AnotherConfig twice - once in AnotherModule, and again in AnotherModuleImpl. These two definitions of the trait are different, and are considered incompatible. The type Config is defined in terms of the former of these, but when you define MyApp, you are setting the type to the latter - hence the error.
You can fix it by either removing the latter definition of AnotherConfig (as suggested by #rarry) or having the latter trait extend the former (if you have some reason to keep the latter, such as defining extra fields).
Remove definition of AnotherConfig from AnotherModuleImpl
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
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.