This page is no longer maintained — Please continue to the home page at www.scala-lang.org

functional abstract class managing data

9 replies
Avi Pfeffer
Joined: 2009-02-23,
User offline. Last seen 42 years 45 weeks ago.

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 2
Joined: 2009-03-20,
User offline. Last seen 42 years 45 weeks ago.
Re: functional abstract class managing data

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
>

Avi Pfeffer
Joined: 2009-02-23,
User offline. Last seen 42 years 45 weeks ago.
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/
>
>
>

Tony Morris 2
Joined: 2009-03-20,
User offline. Last seen 42 years 45 weeks ago.
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
>>>

Meredith Gregory
Joined: 2008-12-17,
User offline. Last seen 42 years 45 weeks ago.
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:
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
Florian Hars
Joined: 2008-12-18,
User offline. Last seen 42 years 45 weeks ago.
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)

Chris Twiner
Joined: 2008-12-17,
User offline. Last seen 42 years 45 weeks ago.
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.

Chris Twiner
Joined: 2008-12-17,
User offline. Last seen 42 years 45 weeks ago.
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.

Martin S. Weber
Joined: 2008-12-23,
User offline. Last seen 42 years 45 weeks ago.
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.

Chris Twiner
Joined: 2008-12-17,
User offline. Last seen 42 years 45 weeks ago.
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.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland