I am trying to extend a class which has primary and auxiliary constructor.
DO my base class has access to auxilary constructors
class learnInheritance (speed:Int) {
val mph: Int = speed
def race() = println("Racing")
def this (speed:Int, model:String) {
this(speed)
println("Speed of call is " + speed + "and model is " + model)
}
}
class Car(speed:Int) extends learnInheritance(speed) {
override val mph: Int = speed
override def race() = println("Racing Car")
}
val a = new Car(10,"Maruti")
println("Speed of Car: " + a.mph)
a.race()
The constructor is not any utility function, it is a function that should guarantees that object is fully initialized after it is run.
So if you call Car constructor it will return fully initialized Car in the process your instance should become fully initialized learnInheritance before you start initializing it as Car. So you should assume that you can call only one parent constructor.
To deal with this restriction you should require that there is some parent constructor that does all the job, where all other set up some defaults. Then you could call that constructor yourself with your constructor that does all the job, and have other constructors act as utilities with defaults.
class Foo(name: String, age: Int) {
def this(name: String) = this(name, 10)
def this(age: Int) = this("", age)
}
class Bar(name: String, age: Int) extends Foo(name, age) {
def this... // bar constructors
}
if you cannot do this, then unfortunately you have to pick only one case in your class.
Alternatively, consider that each case is a separate class:
class Foo private (name: String, age: Int) {
def this(name: String) = this(name, 10)
def this(age: Int) = this("", age)
}
sealed trait Bar { this: Foo =>
// Bar methods
}
object Bar {
final class Name(name: String) extends Foo(name) with Bar
final class Age(age: Int) extends Foo(age) with Bar
def apply(name: String): Bar = new Name(name)
def apply(age: String): Bar = new Age(age)
}
but this has its own issues.
Most of the time, though, usage of only one parent constructor for everything is not a problem. If it is then we can think for a solution for a particular case.
Constructors are not instance methods. That means they are not inherited.
Related
In this example, I want the generic T to be a case class and a DAOEntity with id, so in the abstract implementation, I can use the copy method.
How to define it?
trait DAOEntity {
def id: String
}
// How to define this generic to force the use of a `case class` to have access to `copy`?
abstract class DAO[T <: DAOEntity] {
def storeInUppercase(entity: T): T = entity.copy(id = entity.id)
}
case class MyEntity(id: String) extends DAOEntity
class MyEntityDAO extends DAO[MyEntity] {
// Other stuff
}
There is no way to know if a type is a case class or not.
And even if there was, you won't get the copy method. The language doesn't provide a way to abstract over constructor; thus neither copy and factories (apply on companions) by extension. Which makes sense, what would be the type signature of such function?
What you can do instead is create a factory-like typeclass and ask for that:
trait DAOFactory[T <: DAOEntity] {
def copy(oldEntity: T, newId: String): T
}
object DAOFactory {
def instance[T <: DAOEntity](f: (T, String) => T): DAOFactory[T] =
new DAOFactory[T] {
override final def copy(oldEntity: T, newId: String): T =
f(oldEntity, newId)
}
}
Which can be used like this:
abstract class DAO[T <: DAOEntity](implicit factory: DAOFactory[T]) {
def storeInUppercase(entity: T): T =
factory.copy(
oldEntity = entity,
newId = entity.id.toUpperCase
)
}
And entities would provide the instance like this:
final case class MyEntity(id: String, age: Int) extends DAOEntity
object MyEntity {
implicit final val MyEntityFactory: DAOFactory[MyEntity] =
DAOFactory.instance {
case (oldEntity, newId) =>
oldEntity.copy(id = newId)
}
}
// This compile thanks to the instance in the companion object.
object MyEntityDAO extends DAO[MyEntity]
You can see the code running here.
I have created a trait called Animal and two classes, Dog and Cat. Both Dog and Cat have companion classes that store the number of lives they have. My Cat object has 9 lives and my Dog object has 1 life. I want to add a function to the Animal trait called isAlive and implement there. The isAlive function needs access to the number of live the Animal has. How would I get access to the lives value in the companion classes?
Should I just move the lives value into the Class and remove the companion classes?
Here's my code.
The trait
package Animal
trait Animal {
def speak: String
def getDeaths: Int
def isAlive: Boolean = {
getDeaths < 1 // I want to replace 1 with the number of lives from the Dog or Cat
}
}
The Cat Class and Companion Class
package Animal
class Cat(a: Int) extends Animal {
private var age: Int = a
private var deaths: Int = 0
def this() = this(0)
override def speak: String = {
if (this.isAlive) {
"Meow"
}
else {
"..."
}
}
// I want to do this in the trait
// override def isAlive: Boolean = this.deaths <= Cat.lives
def setAge(age: Int): Unit = this.age = age
def getAge: Int = this.age
def getDeaths: Int = this.deaths
def die(): Unit = this.deaths += 1
}
object Cat {
val lives: Int = 9
}
I'd include lives as an abstract method in Animal trait, similar to getDeaths (btw, Scala doesn't follow Java's naming conventions for getters and setters).
If you're familiar with Java, companion object in scala is similar to Java's static, meaning that type resolution of objects happens in compile time and it's not possible to use polymorphism the same way as you do with methods and fields of the class.
Here is the code:
trait Animal {
def speak: String
def getDeaths: Int
def lives: Int
def isAlive: Boolean = {
getDeaths < lives
}
}
class Cat(a: Int) extends Animal {
override val lives: Int = 9
private var age: Int = a
private var deaths: Int = 0
def this() = this(0)
/* ... */
}
Alternatively, you can defined lives constant in companion object and reference it in concrete class when overriding lives method:
class Cat(a: Int) extends Animal {
override val lives: Int = Cat.lives
private var age: Int = a
private var deaths: Int = 0
def this() = this(0)
/* ... */
}
object Cat {
val lives = 9
}
To access lives within a trait it either has to be a part of the trait, as #Alvean has pointed out, or you have to make it a requirement that classes extending the trait need to have it.
trait Animal { self: {val lives: Int} =>
def isAlive: Boolean = getDeaths < lives
. . .
}
class Cat(a: Int) extends Animal {
val lives = Cat.lives //required to be an Animal
. . .
}
//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)
As I understand the semantics of a custom constructor may be typically added to a class via a companion object. Is there then, any way to inherit a custom constructor while inheriting a class?
On the one hand I have found that companion objects are not synthetically inherited along a case class, and on the other, I am not aware of a way of creating custom constructors inside a class itself, so that they are inherited. And yet inheriting custom constructors seems to be a perfectly valid use case to me. So is it supported in some (straightforward) way in Scala?
A naive demonstration of intent:
class A {}
object A {
def apply(n: Int) = {
println(n)
new A
}
}
class B extends A {}
object Test {
val a1 = A
val a2 = A(3)
val b1 = B // compile error
val b2 = B(3) // compile error
P.S. I have even found the arcane/deviant technique of defining this custom constructors result in a custom constructor that does not in actuality get inherited (it does work for just creating custom constructors, but quite oddly and unfortunately those do not get inherited). Demonstrating code:
class A {
def this(n: Int) = {
this
println(n)
}
}
class B extends A {}
object Test {
val a1: A = new A
val a2: A = new A(3)
val b1 = new B
val b2 = new B(3) // compile error
}
Clarification of Intent Edit:
consider "constructor" and "companion factory methods" interchangeable for the sake of this question.
You can't inherit constructors directly, and because you can't you also can't inherit things that use them without a little bit of work. But you can abstract away anything beyond the constructor call.
Let's suppose we have
class Foo(text: String) {
override def toString = "Foo: " + text
}
object Foo {
def apply(text: String) = new Foo(text) // Auto-generated for case class
def apply(i: Int) = new Foo(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
and we then decide to
class Bar(text: String) extends Foo(text) {
override def toString = "Bar: " + text
}
Now, what do we do about object Bar? Instead of writing all the logic over again, we create a trait to separate and abstract the object creation from the computation of the constructor parameter(s):
trait FooCompanionLike[A <: Foo] {
def apply(text: String): A // I am abstract!
def apply(i: Int): A = apply(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
Now we can
object Foo extends FooCompanionLike[Foo] {
def apply(text: String) = new Foo(text)
}
object Bar extends FooCompanionLike[Bar] {
def apply(text: String) = new Bar(text)
}
So you can't completely escape boilerplate, but you can reduce it to extending from a trait and a single method call.
If you do it this way (where the abstract apply perfectly matches the constructor), you can even get case classes to work without manually defining the abstract apply method in the companion:
case class Baz(text: String) extends Foo(text) {
override def toString = "Baz: " + text
}
object Baz extends FooCompanionLike[Baz] {
// Nothing here! Auto-generated apply works!
}
Short answer: no straightforward way; try to workaround and resist the desire.
Constructors in Scala are defined in the body of the class and take parameters after the class name e.g.
class A(i: Int) {
println(i)
}
The println(i) in this case is the constructor logic. If you now extend A, like this:
class B(i: Int) extends A(i)
and instantiate B, val b1 = new B(2) you'll see that the constructor is indeed inherited.
As you've already found out, Scala allows you to define alternative constructors by defining functions called this. But these alternative constructors must call the primary constructor.
The way I understand it is that there is really only one constructor for any Scala class, the alternative constructors just filter into it. For example:
class A(x: Int, y: Int) {
// do some constructing!
def this(x: Int) = {
this(x, 1) // provide a default value for y
}
}
I know that we can overload class constructor in Scala as follows-
class Foo(x: Int, z: String) {
def this(z: String) = this(0, z);
}
But how can I overload a class which have two completely different types of parameters as below (imagine that I can identify an user either by name or numeric id)
class User(userId: Int) {
...
}
class User(userName: String) {
...
}
(imagine that I can identify an user either by name or numeric id)
You almost certainly don't want to do this by having optional fields in your class. Rather, you should encode the fact that the user is identified in various ways into the types and structure of your program.
One way to do this is to encode the user identifier using Scala's built-in Either type:
class User private(identifier : Either[String, Int]) {
def this(id : Int) = this(Right(id))
def this(name : String) = this(Left(name))
}
However, you might also want to make the nature of the user identifier a little more explicit, and encode it as your own Algebraic data type:
trait UserIdentifier
object UserIdentifier {
case class ById(id : Int) extends UserIdentifier
case class ByName(name : String) extends UserIdentifier
}
class User(id : UserIdentifier) {
def this(id : Int) = this(UserIdentifier.ById(id))
def this(name : String) = this(UserIdentifier.ByName(name))
}
By doing it this way, you prevent problems such as somebody trying to look up a name on a User which is identified by an id instead. The second approach also allows you to extend the idea of a UserIdentifier in the future, in case a user can be identified by some other construct.
Alternativelly, you can do this
object User {
def apply(userId: Int) = new UserI(userId)
def apply(name: String) = new UserS(name)
class UserI(userId: Int)
class UserS(userName: String)
}
And use it this way:
val u1 = User(1)
val u2 = User("a")
If you have a lot of common logic you can put it into a common abstract class
object User {
def apply(userId: Int) = new UserI(userId)
def apply(name: String) = new UserS(name)
class UserI(userId: Int) extends AUser
class UserS(userName: String) extends AUser
abstract class AUser{
// common logic for both classes
}
}
You can do this:
class User private() {
def this( userName: String ) = { this(); ??? }
def this( userId: Int ) = { this(); ??? }
}
the private keyword makes the no-arg constructor private. This means your other secondary constructors don't need to pass anything to the primary constructor
(effectively making the two secondary constructors independant), but the callers still cannot instantiate the class withouth passing any parameter.
Note that this pattern can be tricky to use when your class has vals to initialize from the construtors parameters.