- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
functional abstract class managing data
Fri, 2009-03-27, 21:44
Hi,
I'm struggling with a basic problem in combining FP and OO styles. I
have a class hierarchy, and the root of the hierarchy manages some
data for all its subclasses. Only the superclass ever has to do
anything with the data. I want it to be functional. I can write
something like:
abstract class Super protected (data: List[Int]) {
def this() = this(Nil)
def add(i: Int): Super
def doSomethingWithData = {
// omitted
}
}
class Sub1 private (data: List[Int]) extends Super(data) {
def this() = this(Nil)
def add(i: Int) = new Sub1(i :: data)
...
}
class Sub2 private (data: List[Int]) extends Super(data) {
def this() = this(Nil)
def add(i: Int) = new Sub2(i :: data)
...
}
This is bad. The definition of add is exactly the same in all the
subclasses, except that the class being constructed is always the same
as the class on which the method is invoked. Worse, since only Super
needs to access data, the subclasses should not even have to know
about the existence of data. Data should be private in Super, and the
subclasses should not need their private constructors. With mutable
state this would be easy:
abstract class Super {
private var data: List[Int] = Nil
def add(i: Int) { data = i :: data }
def doSomethingWithData = {
// omitted
}
}
class Sub1 extends Super {
...
}
class Sub2 extends Super {
...
}
There must be a simple solution that I'm missing. Any ideas?
Thanks,
Avi
Fri, 2009-03-27, 22:17
#2
Re: functional abstract class managing data
The subclasses all provide additional functionality and structure not
present in the superclass. In my application I have a rich class
hierarchy of models, which can further be extended by users. Models
have constraints, and it so happens that the Model superclass can take
care of the constraints on its own, and can save the subclasses from
having to worry about them. But the subclasses extend Model in a
variety of useful and unforeseen ways. So I think I do need the
subclassing.
On Fri, Mar 27, 2009 at 4:53 PM, Tony Morris wrote:
> Hello Avi,
> Have you considered implementing add?
>
> abstract class Super protected (data: List[Int]) {
> def this() = this(Nil)
> def add(i: Int): Super = new Super(i :: data)
> def doSomethingWithData = {
> // omitted
> }
> }
>
> Why the need for subclassing?
>
>
> Avi Pfeffer wrote:
>> Hi,
>>
>> I'm struggling with a basic problem in combining FP and OO styles.
>> I have a class hierarchy, and the root of the hierarchy manages
>> some data for all its subclasses. Only the superclass ever has to
>> do anything with the data. I want it to be functional. I can write
>> something like:
>>
>> abstract class Super protected (data: List[Int]) { def this() =
>> this(Nil) def add(i: Int): Super def doSomethingWithData = { //
>> omitted } }
>>
>> class Sub1 private (data: List[Int]) extends Super(data) { def
>> this() = this(Nil) def add(i: Int) = new Sub1(i :: data) ... }
>>
>> class Sub2 private (data: List[Int]) extends Super(data) { def
>> this() = this(Nil) def add(i: Int) = new Sub2(i :: data) ... }
>>
>> This is bad. The definition of add is exactly the same in all the
>> subclasses, except that the class being constructed is always the
>> same as the class on which the method is invoked. Worse, since only
>> Super needs to access data, the subclasses should not even have to
>> know about the existence of data. Data should be private in Super,
>> and the subclasses should not need their private constructors. With
>> mutable state this would be easy:
>>
>> abstract class Super { private var data: List[Int] = Nil def add(i:
>> Int) { data = i :: data } def doSomethingWithData = { // omitted }
>> }
>>
>> class Sub1 extends Super { ... }
>>
>> class Sub2 extends Super { ... }
>>
>> There must be a simple solution that I'm missing. Any ideas?
>>
>> Thanks, Avi
>>
>
> --
> Tony Morris
> http://tmorris.net/
>
>
>
Fri, 2009-03-27, 22:27
#3
Re: functional abstract class managing data
OK, but is there a benefit to implementing add in each subclass? Can
you implement it in Super then leave other functionality to the
subclasses?
Avi Pfeffer wrote:
> The subclasses all provide additional functionality and structure
> not present in the superclass. In my application I have a rich
> class hierarchy of models, which can further be extended by users.
> Models have constraints, and it so happens that the Model
> superclass can take care of the constraints on its own, and can
> save the subclasses from having to worry about them. But the
> subclasses extend Model in a variety of useful and unforeseen ways.
> So I think I do need the subclassing.
>
> On Fri, Mar 27, 2009 at 4:53 PM, Tony Morris
> wrote:
>> Hello Avi, Have you considered implementing add?
>>
>> abstract class Super protected (data: List[Int]) { def this() =
>> this(Nil) def add(i: Int): Super = new Super(i :: data) def
>> doSomethingWithData = { // omitted } }
>>
>> Why the need for subclassing?
>>
>>
>> Avi Pfeffer wrote:
>>> Hi,
>>>
>>> I'm struggling with a basic problem in combining FP and OO
>>> styles. I have a class hierarchy, and the root of the hierarchy
>>> manages some data for all its subclasses. Only the superclass
>>> ever has to do anything with the data. I want it to be
>>> functional. I can write something like:
>>>
>>> abstract class Super protected (data: List[Int]) { def this() =
>>> this(Nil) def add(i: Int): Super def doSomethingWithData = {
>>> // omitted } }
>>>
>>> class Sub1 private (data: List[Int]) extends Super(data) { def
>>> this() = this(Nil) def add(i: Int) = new Sub1(i :: data) ... }
>>>
>>> class Sub2 private (data: List[Int]) extends Super(data) { def
>>> this() = this(Nil) def add(i: Int) = new Sub2(i :: data) ... }
>>>
>>> This is bad. The definition of add is exactly the same in all
>>> the subclasses, except that the class being constructed is
>>> always the same as the class on which the method is invoked.
>>> Worse, since only Super needs to access data, the subclasses
>>> should not even have to know about the existence of data. Data
>>> should be private in Super, and the subclasses should not need
>>> their private constructors. With mutable state this would be
>>> easy:
>>>
>>> abstract class Super { private var data: List[Int] = Nil def
>>> add(i: Int) { data = i :: data } def doSomethingWithData = { //
>>> omitted } }
>>>
>>> class Sub1 extends Super { ... }
>>>
>>> class Sub2 extends Super { ... }
>>>
>>> There must be a simple solution that I'm missing. Any ideas?
>>>
>>> Thanks, Avi
>>>
Fri, 2009-03-27, 22:37
#4
Re: functional abstract class managing data
Avi,
Isn't this exactly the use case that the 'Towards Equal Rights for Higher-kinded Types' paper and implicits proposal was intended to address? Maybe i'm missing something about your example.
Best wishes,
--greg
On Fri, Mar 27, 2009 at 1:44 PM, Avi Pfeffer <avi@eecs.harvard.edu> wrote:
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
806 55th St NE
Seattle, WA 98105
+1 206.650.3740
http://biosimilarity.blogspot.com
Isn't this exactly the use case that the 'Towards Equal Rights for Higher-kinded Types' paper and implicits proposal was intended to address? Maybe i'm missing something about your example.
Best wishes,
--greg
On Fri, Mar 27, 2009 at 1:44 PM, Avi Pfeffer <avi@eecs.harvard.edu> wrote:
Hi,
I'm struggling with a basic problem in combining FP and OO styles. I
have a class hierarchy, and the root of the hierarchy manages some
data for all its subclasses. Only the superclass ever has to do
anything with the data. I want it to be functional. I can write
something like:
abstract class Super protected (data: List[Int]) {
def this() = this(Nil)
def add(i: Int): Super
def doSomethingWithData = {
// omitted
}
}
class Sub1 private (data: List[Int]) extends Super(data) {
def this() = this(Nil)
def add(i: Int) = new Sub1(i :: data)
...
}
class Sub2 private (data: List[Int]) extends Super(data) {
def this() = this(Nil)
def add(i: Int) = new Sub2(i :: data)
...
}
This is bad. The definition of add is exactly the same in all the
subclasses, except that the class being constructed is always the same
as the class on which the method is invoked. Worse, since only Super
needs to access data, the subclasses should not even have to know
about the existence of data. Data should be private in Super, and the
subclasses should not need their private constructors. With mutable
state this would be easy:
abstract class Super {
private var data: List[Int] = Nil
def add(i: Int) { data = i :: data }
def doSomethingWithData = {
// omitted
}
}
class Sub1 extends Super {
...
}
class Sub2 extends Super {
...
}
There must be a simple solution that I'm missing. Any ideas?
Thanks,
Avi
--
L.G. Meredith
Managing Partner
Biosimilarity LLC
806 55th St NE
Seattle, WA 98105
+1 206.650.3740
http://biosimilarity.blogspot.com
Sat, 2009-03-28, 00:07
#5
Re: functional abstract class managing data
Avi Pfeffer wrote:
> There must be a simple solution that I'm missing. Any ideas?
There is an example on pp. 428ff of Programming in Scala that solves a
similar problem using a factory pattern. Adapted to your description:
abstract class SuperMaker {
type Sub <: Super
protected def make(data: List[Int]): Sub
def make(): Sub = make(Nil)
abstract class Super(data: List[Int]) {
def add(i: Int) : Sub = make(i :: data)
def doSomethingWithData = {
println(data)
}
}
}
object Sub1Maker extends SuperMaker {
abstract class Sub1(data: List[Int]) extends Super(data)
type Sub = Sub1
protected def make(data: List[Int]) = new Sub1(data) {}
}
It is a bit verbose, but seems to work, add returns the correct, if
somewhat unwieldy, type:
scala> Sub1Maker.make()
res0: Sub1Maker.Sub = Sub1Maker$$anon$1@53aed4
scala> res0.add(1)
res1: Sub1Maker.Sub = Sub1Maker$$anon$1@125ee49
scala> res1.doSomethingWithData
List(1)
Sat, 2009-03-28, 00:17
#6
Re: functional abstract class managing data
On Fri, Mar 27, 2009 at 9:44 PM, Avi Pfeffer wrote:
> Hi,
>
> I'm struggling with a basic problem in combining FP and OO styles. I
> have a class hierarchy, and the root of the hierarchy manages some
> data for all its subclasses. Only the superclass ever has to do
> anything with the data. I want it to be functional. I can write
> something like:
>
> abstract class Super protected (data: List[Int]) {
> def this() = this(Nil)
> def add(i: Int): Super
> def doSomethingWithData = {
> // omitted
> }
> }
>
> class Sub1 private (data: List[Int]) extends Super(data) {
> def this() = this(Nil)
> def add(i: Int) = new Sub1(i :: data)
> ...
> }
>
> class Sub2 private (data: List[Int]) extends Super(data) {
> def this() = this(Nil)
> def add(i: Int) = new Sub2(i :: data)
> ...
> }
>
> This is bad. The definition of add is exactly the same in all the
> subclasses, except that the class being constructed is always the same
> as the class on which the method is invoked. Worse, since only Super
> needs to access data, the subclasses should not even have to know
> about the existence of data. Data should be private in Super, and the
> subclasses should not need their private constructors. With mutable
> state this would be easy:
>
> abstract class Super {
> private var data: List[Int] = Nil
> def add(i: Int) { data = i :: data }
> def doSomethingWithData = {
> // omitted
> }
> }
>
> class Sub1 extends Super {
> ...
> }
>
> class Sub2 extends Super {
> ...
> }
>
> There must be a simple solution that I'm missing. Any ideas?
>
> Thanks,
> Avi
>
Just concerning the creation of a derived instance with the new
immutable state
http://code.google.com/p/scala-scales/wiki/VirtualConstructorPreSIP
can give some ideas.
Delegate the actual instantiation to a single virtual constructor, i
really like the name newThis :-) Then if you know the hierarchy
doesn't need type parameters you can use this.type as your return type
on the "mutators", each of which call newThis for the actual instance.
If there are type parameters you need to use an abstract type member.
Then just hide the state in the super, i.e. add calls newThis, and
then sets the new instances data once and returns the new instance.
From outside Super it is still immutable and new instances are always
returned, you just have to ensure that the actual internal data is
itself immutable.
Sat, 2009-03-28, 00:27
#7
Re: functional abstract class managing data
On Sat, Mar 28, 2009 at 12:01 AM, Florian Hars wrote:
> Avi Pfeffer wrote:
>>
>> There must be a simple solution that I'm missing. Any ideas?
>
> There is an example on pp. 428ff of Programming in Scala that solves a
> similar problem using a factory pattern. Adapted to your description:
>
> abstract class SuperMaker {
> type Sub <: Super
> protected def make(data: List[Int]): Sub
> def make(): Sub = make(Nil)
> abstract class Super(data: List[Int]) {
> def add(i: Int) : Sub = make(i :: data)
> def doSomethingWithData = {
> println(data)
> }
> }
> }
>
> object Sub1Maker extends SuperMaker {
> abstract class Sub1(data: List[Int]) extends Super(data)
> type Sub = Sub1
> protected def make(data: List[Int]) = new Sub1(data) {}
> }
>
> It is a bit verbose, but seems to work, add returns the correct, if
> somewhat unwieldy, type:
Thats a prime reason for my virtual constructor pre sip, it seems only
a few people are interested in this kind of structure though. The
problem is that you either have to delay specifying the actual type
until the end types in a heirarchy (not great for extensibility) or
use factory functions, which add substantial boilerplate.
Sat, 2009-03-28, 03:07
#8
Re: functional abstract class managing data
Quoting Chris Twiner :
>> (...)
>> It is a bit verbose, but seems to work, add returns the correct, if
>> somewhat unwieldy, type:
>
> Thats a prime reason for my virtual constructor pre sip, it seems only
> a few people are interested in this kind of structure though.
Actually I stumbled over the problem too and after looking at various
patterns I decided that all solutions are ugly, boilerplate heavy
infected and not scalable at all, so it doesn't matter which you choose:
> The
> problem is that you either have to delay specifying the actual type
> until the end types in a heirarchy (not great for extensibility) or
> use factory functions, which add substantial boilerplate.
I wonder if this is java heritage/compat (not a java guy here). This
are the moments where I just think ruby..
class A; def A.getme ; new ; end ; end
class B < A ; end
B.getme => #
Sigh.
Sat, 2009-03-28, 09:47
#9
Re: functional abstract class managing data
On Sat, Mar 28, 2009 at 2:56 AM, Martin S. Weber wrote:
> Quoting Chris Twiner :
>
>>> (...)
>>> It is a bit verbose, but seems to work, add returns the correct, if
>>> somewhat unwieldy, type:
>>
>> Thats a prime reason for my virtual constructor pre sip, it seems only
>> a few people are interested in this kind of structure though.
>
> Actually I stumbled over the problem too and after looking at various
> patterns I decided that all solutions are ugly, boilerplate heavy infected
> and not scalable at all, so it doesn't matter which you choose:
>
Agreed they are all terrible, as it stands even if my presip could
work, you would still have to refine the type at all points in the
hierarchy you wish to extend in the future.
Its a shame because most scala usage saves code complexity and gives
you more flexibility to boot. This kind of pattern would seem, to me
at least, to be a corner stone of an oo/functional approach. It sure
would be nice to make it pleasant to work with.
It should be noted that the compiler does this with this.type, which
works fine as it doesn't use type parameters. Also extending this
type doesn't make sense as its just a type path.
Hello Avi,
Have you considered implementing add?
abstract class Super protected (data: List[Int]) {
def this() = this(Nil)
def add(i: Int): Super = new Super(i :: data)
def doSomethingWithData = {
// omitted
}
}
Why the need for subclassing?
Avi Pfeffer wrote:
> Hi,
>
> I'm struggling with a basic problem in combining FP and OO styles.
> I have a class hierarchy, and the root of the hierarchy manages
> some data for all its subclasses. Only the superclass ever has to
> do anything with the data. I want it to be functional. I can write
> something like:
>
> abstract class Super protected (data: List[Int]) { def this() =
> this(Nil) def add(i: Int): Super def doSomethingWithData = { //
> omitted } }
>
> class Sub1 private (data: List[Int]) extends Super(data) { def
> this() = this(Nil) def add(i: Int) = new Sub1(i :: data) ... }
>
> class Sub2 private (data: List[Int]) extends Super(data) { def
> this() = this(Nil) def add(i: Int) = new Sub2(i :: data) ... }
>
> This is bad. The definition of add is exactly the same in all the
> subclasses, except that the class being constructed is always the
> same as the class on which the method is invoked. Worse, since only
> Super needs to access data, the subclasses should not even have to
> know about the existence of data. Data should be private in Super,
> and the subclasses should not need their private constructors. With
> mutable state this would be easy:
>
> abstract class Super { private var data: List[Int] = Nil def add(i:
> Int) { data = i :: data } def doSomethingWithData = { // omitted }
> }
>
> class Sub1 extends Super { ... }
>
> class Sub2 extends Super { ... }
>
> There must be a simple solution that I'm missing. Any ideas?
>
> Thanks, Avi
>