I have the following grails domain objects
abstract class A {
String name
}
class B extends A {
String propertySpecificToB
}
class C extends A {
String propertySpecificToC
}
and I can successfully save them to my database (which in this case is MongoDB). However, I would like to list all the names of the rows in my database, so I do something like:
A.list()
But, that throws an InstantiationException as it tries to create instances of the abstract class A. How can I list off all rows (regardless of which class it is). I could make A non-abstract, but it would never be valid to have a A. Also, I'd like to place some abstract methods in A.
I'd really just like it to return a list of A, with the list actually containing Bs and Cs.
I found a related post, but that didn't solve this problem.
Related
In Chapter 19 ,"Programming in scala 2nd edition",how to explain the bold sentences ?
object private members can be accessed only from within the object in
which they are defined. It turns out that accesses to variables from
the same object in which they are defined do not cause problems with
variance. The intuitive explanation is that, in order to construct a
case where variance would lead to type errors, you need to have a
reference to a containing object that has a statically weaker type
than the type the object was defined with. For accesses to object
private values, however,this is impossible.
I think the most intuitive way to explain what Martin is trying to say is to look at arrays in Java. Arrays in Java are covariant but don't type check according to covariance rules. This means they explode at runtime instead of compile time:
abstract class Animal {}
class Girafee extends Animal {}
class Lion extends Animal {}
public class Foo {
public static void main(String[] args) {
Animal[] animals = new Girafee[10];
animals[0] = new Lion();
}
}
The fact that I can do this is because:
Java doesn't restrict this at compile time (due to a design decision)
I have a reference to the underlying array which allows me to manipulate it's internal values
This doesn't hold when talking about private fields of a class from the outside.
For example, assume the following class:
class Holder[+T](initialValue: Option[T]) {
private[this] var value: Option[T] = initialValue
}
When creating an instance of Holder, I am not visible to it's internal fields, thus I cannot manipulate them directly like I did with the Java array. This way, the compiler makes sure they are protected, and each manipulation to the field will have to be through a method, where the type checker is strict and doesn't allow funky business.
So i have an absract superclass, and a subclass that extends this superclass with fields that are not declared in the superclass. Is there a way to access those fields from within the superclass? I can't declare these fields in the superclass because it has other subclases which may not have these fields.
Edit in order to make it clearer:
So i am making some kind of shop which has different items. Thus i have an abstract class called item (with a field: price) and the different items are object which extend the item class an define the price. But there are also some special items where all the instances of the same item have different id's, they also declare their price. And a "shopper" must be able to make a "shopping list" of items both normal and special ones, where the total price can be calculated but you must also be able to see the id's of the special items from within the list.
Edit: an example of what i want to achieve.
I made a little example
//The numbers are different for each ticket
// and are used to denote a winner in the end.
abstract class LotteryTicket(val numbers: String) {
val price: Int
}
class GoldTicket(numbers: String) extends LotteryTicket(person) {
val price: Int = 10
}
class SilverTicket(numbers: String) extends LotteryTicket(person) {
val price: Int = 5
}
abstract class Drink {
val price: Int
}
object Water extends Drink {
val price: Int = 1
}
object Coffee extends Drink {
val price: Int = 2
}
class Bill
class Customer
The class 'Bill' should contain a list which can include Drinks as well as LotteryTickets,
for which the total can be calculated and the Customer has to be able to make such a bill.
The Customer class also needs a method which confirms the purchase and checks if the numbers on his
LottoryTicket are different for every Ticket he bought. Because when he has the same number on 2 tickets
The confirmation fails.
While indeed not recommended (because it implies a design flaw - you don't know if you have the subclass at hand, but you're still interested in calling its methods), here are some options:
trait A {
// pattern-match to doStuff only if B:
this match {
case b: B => b.doStuff()
case _ => // do nothing
}
// check if type is B (not recommended)
if (this.isInstanceOf[B]) {
this.asInstanceOf[B].doStuff()
}
}
class B extends A {
def doStuff() {}
}
In general this is not available in the principle of object oriented programming. May be if you have to over code make another special price abstract field to work around. Other than that you have to instantiate the sub class in the base class in order to make the fields in the sub class accessible. I don't know if this will help you but if you can post some kind of structure of your classes and what you are trying to do. I think it will help a lot.
Not without resorting to very dirty tricks, which I would strongly recommend against. It looks like your class hierarchy may have some problems - without specific examples it's hard to give exact advice, but I would in Scala primarily look at composition with traits rather than inheritance. For your problem, you could make a trait for everything that can be dropped in a shopping cart
trait Buyable {
def price: Int
}
and then mix that trait in into anything that you want to be able to land in a shopping cart. In that way, you can build small inheritance trees of all sorts of products and just add the trait. For example
class Drink extends Buyable {
// Drink can set the price for all its subclasses
override def price = ...
}
abstract class LotteryTicket extends Buyable {
// LotteryTicket cannot, so it's abstract
}
class SilverTicket {
override def price = 20
}
Your shopping cart is oblivious, just operates on Buyable stuff:
class ShoppingCart {
def add(b: Buyable) ...
}
Of course, you could also move some identifier, etcetera, to Buyable, just like you need it.
I have an abstract class Model from which I create case classes:
abstract class Model
case class User(.) extends Model
an abstract class Table taking such a Model as type parameter, used in one of its default concrete methods:
abstract class Table[M <: Model] {
def parser = SomeExternalBuilder[M]
}
The meaning is rather simple: "Give every instance of Table a default parser based on its own class".
The problem is that SomeExternalBuilder will only accept a case class as argument ("case class expected: M"), so it does not compile.
Can I make Table take only case classes as type parameter?
I have seen a few answers providing a missing copy method (ref1, ref2), so I tried this:
trait Model[T] {
def copy: T
}
abstract class Table[M <: Model[M]]
but now case class User extends Model[User] and must overwrite copy too, every function creating a Model takes a type parameter, and honestly the code quickly starts being atrocious, all that for that single line in Table.
Is there no better way than copying that def parser line in every child's body?
Edit: N.B. The real function is def parser: anorm.Macro.namedParser[M] from the "anorm" library for Play.
Edit: Source of the type check by this macro: https://github.com/playframework/anorm/blob/0a1b19055ba3e3749044ad8a54a6b2326235f7c8/core/src/main/scala/anorm/Macro.scala#L117
The problem is that SomeExternalBuilder will only accept a case class as argument ("case class expected: M"), so it does not compile.
I don't think you can ever get such a message from Scala compiler itself, which means that SomeExternalBuilder.apply is a macro. It requires a specific case class in order to know its fields, so that it doesn't matter if you could limit M to be a case class (which you can't): it still wouldn't accept a type parameter.
What you can do is create a macro annotation, so that when you write e.g.
#HasModel
class SomeTable extends Table[SomeModel] {
...
}
the val parser = namedParser[SomeModel] is generated automatically.
Alternately, write #HasModel[SomeModel] class SomeTable { ... } and generate extends Table[SomeModel] as well.
It wouldn't be hard (as macros go), but you still need to annotate each class extending Table.
Not fool proof solution but worth a try
case classes extend Product and Serialisable. Constraint Product with Serialisable will help you get some type safety. M can be any class which extends Product with Serialisable. But Product is extended by case class mostly
abstract class Table[M <: (Product with Serializable)] {
def parser = SomeExternalBuilder[M]
}
I have a abstract entity class that 3 slightly different entities implements. In my 3 sub classes I have overriden the equals and has methods but the question is, should I also do this in the abstract entity? If I dont I will not be able to compare entities that are only defined by abstract entity unless i cast them. If i do a equals will I risk to compare to different sub entities and get that they are alike?
Example:
abstract class Log{}
SystemLog extends Log{}
UserLog extends Log{}
public void test(Log log){
Log myInner = new SystemLog();
if(log.equals(myInner)){
//do random stuff
}
}
I cannot see problem with casting. Type of argument to equals is Object, so you have to cast anyway to have access to attributes.
If you define equals method in each subclasses, when comes the situation where equals in abstract superclass is called?
If i do a equals will I risk to compare to different sub entities and
get that they are alike
You are in the risk of comparing different subentities to each others anyway. Just imagine Set with superclass as type populated with objects that are two instances of two different subclasses. It has not too much to do with do you override equals in superclass or not.
In your example equals method possibly implemented in abstract class Log will not be called, if we have implementation already in actual subclass:
Assuming:
UserLog extends Log{
public boolean equals(Object o) {
//I do override equals method so I am one who is called.
//and here you go and check type with something like
if (this == o) return true;
if (!(o instanceof UserLog)) return false;//accepts subclasses of UserLog
....
}
...
}
//And then somewhere else
Log ul = new UserLog();
test(ul);
For example (maybe a bit clumsy from a real life view, but just to illustrate):
"User" is a case class containing user name and id. Id can be never set manually, and a User class instance with no id set has no sense.
A UserBase class maintains users base and has a "getUser (name : String) : User" method returning a consistent User instance.
No one other than a UserBase object can know (well, someone can, but really shouldn't rely on this knowledge) a user's id, so constructing a User instance manually makes no sense (and can cause errors in future if someone accidentally hardcodes this and forgets). Moreover, having an orphan User instance not tracked by a UserBase is also undesired.
So the task is to make calling UserBase.getUser the only way to get a User instance.
Can this be implemented in Scala?
You have to put the classes in the same package or make them part of the same class or object. Then:
object O {
class C private[O] (val x: Int) { }
object D { def apply(i:Int) = new C(i) }
def getC(i:Int) = new C(i)
}
scala> O.D(5)
res0: O.C = O$C#5fa6fb3e
scala> new O.C(5)
<console>:10: error: constructor C cannot be accessed in object $iw
new O.C(5)
scala> O.getC(5)
res1: O.C = O$C#127208e4
A case class automatically gets several features, including a companion object with an apply() method for constructing instances of the class. This is why you don't need "new" with case classes. If you try to make an explicit companion with apply() you will get error: method apply is defined twice
If you want to make your own factory method then you should not use case classes. You can still have all of the same features (toString, apply, unapply, etc) but you will have to implement them manually and to your own specification.
You don't actually clarify what a 'base' is in this context, but given your description it sounds like it's really nothing more than a factory for users.
The usual place to put a factory for a class is in the companion object (This is how case classes do it, but the technique isn't restricted to just case classes)
class User private(val id: Int, val name: String) {
...
}
object User {
private def nextId() : Int = ...
def apply(name: String) = new User(nextId(), name)
}
//now create one:
val u = User("Ivan")
Of course, if the User object is immutable (highly recommended), then there's very little reason to hide the id member. You're probably also going to want a (restricted) method to construct a User with a specified ID, mostly for reasons of unit testing.
Working with companions like this, it's also unlikely that you'll still need a distinct UserBase factory. Having your factory named the same as the instances it produces will result in cleaner code.