[scala] usefulness of OOP

[scala] usefulness of OOP

I was watching a Google Tech talk by Martin Odersky, in which he says
that functional programmers do not understand the usefulness of OOP,
specifically, the ability to extend classes by overriding methods.
However, as far as I can tell, he does not support this claim later in
the talk. As a counter-argument, I know that in OCaml, OOP is
available (the "O" part), but is widely viewed as a failed experiment
(not "failed" in a pejorative sense, but even its creator does not use
the objective extensions). What can overriding methods do that
higher-order functions can not do as well or better?

Re: [scala] usefulness of OOP

FFT,

i share your sentiments. One real abstraction technique that i believe has some legs and remotely resembles OO techniques is the Haskell typeclass. i think this really gets at some of what OO is groping towards; but, i think there is a genuine overhead for Scala that is about the rational reconstruction of OO semantics. It's an overhead the main function of which is to ease the transition of the OO community to a more scalable set of abstractions.

I was watching a Google Tech talk by Martin Odersky, in which he says
that functional programmers do not understand the usefulness of OOP,
specifically, the ability to extend classes by overriding methods.
However, as far as I can tell, he does not support this claim later in
the talk. As a counter-argument, I know that in OCaml, OOP is
available (the "O" part), but is widely viewed as a failed experiment
(not "failed" in a pejorative sense, but even its creator does not use
the objective extensions). What can overriding methods do that
higher-order functions can not do as well or better?

Re: [scala] usefulness of OOP

I would almost have to imagine you misheard. Overriding a non-trivial concrete method with another concrete method is very rare in modern mainstream OO practice, to the point where I would almost consider it an anti-pattern. I would imagine it makes a bit more sense with mix-in inheritance, but haven't needed it enough to say, and in any case that use seems more aspect-oriented than object-oriented.

FFT-2 wrote

What can overriding methods do that
higher-order functions can not do as well or better?

Re: [scala] usefulness of OOP

Bad wording on my part (I'm not an OO person, so I don't always use
the correct nomenclature) I think what Martin said was that it's
useful to implement some methods in a class, while leaving some
unimplemented (to be implemented by the user of the class).

He mentioned how functional programmers don't understand the
usefulness of this. I still don't see what useful things this gives
you that higher-order functions don't.

Re: [scala] usefulness of OOP

It doesn't give anything that higher order functions don't. The two techniques are equivalent and can be implemented in terms of one another. However, in each language, one technique will tend to be more readable than the other.

Bad wording on my part (I'm not an OO person, so I don't always use
the correct nomenclature) I think what Martin said was that it's
useful to implement some methods in a class, while leaving some
unimplemented (to be implemented by the user of the class).

He mentioned how functional programmers don't understand the
usefulness of this. I still don't see what useful things this gives
you that higher-order functions don't.

[scala] Re: usefulness of OOP

Meredith Gregory wrote:
> FFT,
>
> i share your sentiments. One real abstraction technique that i believe
> has some legs and remotely resembles OO techniques is the Haskell
> typeclass. i think this really gets at some of what OO is groping
> towards; but, i think there is a genuine overhead for Scala that is
> about the rational reconstruction of OO semantics. It's an overhead the
> main function of which is to ease the transition of the OO community to
> a more scalable set of abstractions.

To be really powerful a language needs to support both static and
dynamic polymorphism. In Haskell type classes can be used for both types
(see http://haskell.org/haskellwiki/OOP_vs_type_classes for some
examples). In Scala dynamic polymorphism is achieved through sub typing,
static polymorphism mostly through implicits.

Now with type classes you can extend existing types with new dynamically
resolved functionality to outside of their definition site. This can not
be achieved with inheritance/implementation as the type hierarchy is
static. Something like scoped interface injection could be a solution.
It would be resolved similarly to implicits, but could introduce new
sub/super type relationships locally. I would really be interested if
someone knows a language which supports such a feature, it's somewhat
akin to dynamic multi methods but instead work on interface basis.

Re: [scala] usefulness of OOP

> I was watching a Google Tech talk by Martin Odersky, in which he says
> that functional programmers do not understand the usefulness of OOP,
> specifically, the ability to extend classes by overriding methods.
> However, as far as I can tell, he does not support this claim later in
> the talk. As a counter-argument, I know that in OCaml, OOP is
> available (the "O" part), but is widely viewed as a failed experiment
> (not "failed" in a pejorative sense, but even its creator does not use
> the objective extensions). What can overriding methods do that
> higher-order functions can not do as well or better?
>

The crucial thing is to be able to implement methods (and, in the case
of Scala, types)
in subclasses. That way, the unknown part of an abstraction can be
left open in a class to be filled in later in subclasses. Functional
programmers indeed usually don't get this, and think higher-order
methods or ML functors are a sufficient replacement. But the crucial
difference is this:

An implementation of an abstract {def, val, type} can refer to other
members of its superclass. But an argument to a higher order method or
functor cannot refer to
the result of the application. So open recursion with abstraction is
supported in OOP but it requires elaborate and rather tedious
boilerplate in FP (such as the encodings of classes in TAPL (*).

To get a demonstration what difference this can make, I invite you to
try to do this little task, which was originally proposed by Corky
Cartwright at a WG 2.8 meeting (**):

The task is to write an interpreter for a little functional language -
lambda calculus with n-argument functions and integer arithmetic.
There are several means to represent
variables and environments in such an interpreter. For instance,
variables could be strings and environments association lists, or
variables could be DeBruijn numbers, and environments simple stacks.
The question is this -- how much of your interpreter can you re-use if
you change your decision how to represent variables and environments?

Corky put this up as a challenge in the meeting because he noted that
this was rather easy in Scheme, but almost impossible in GJ (or Java
today). So are static types hindering re-use? People at the meeting
came up with three different solutions, one in SML, one in Haskell,
and one in Scala. The Scala solution used a simple abstract class for
the interpreter where environment type, variable type and environment
access were kept abstract. Abstract members were then implemented in
different ways for DeBruijn and association list interpreters. The
Haskell solution used a big type class (with six functional
dependencies, if I remember correctly). The ML solution used functors
with sharing constraints. It was about 1 1/2 times the length of the
other two solutions. Also, everyone but the most experienced ML
programmers found it significantly harder to understand than the other
two solutions. But it's really better if you try this out for
yourself...

Re: [scala] usefulness of OOP

On Tue, Apr 28, 2009 at 3:03 AM, FFT <[hidden email]> wrote:
> I was watching a Google Tech talk by Martin Odersky, in which he says
> that functional programmers do not understand the usefulness of OOP,
> specifically, the ability to extend classes by overriding methods.
> However, as far as I can tell, he does not support this claim later in
> the talk. As a counter-argument, I know that in OCaml, OOP is
> available (the "O" part), but is widely viewed as a failed experiment
> (not "failed" in a pejorative sense, but even its creator does not use
> the objective extensions). What can overriding methods do that
> higher-order functions can not do as well or better?

Part of the usefulness of OOP shows even when comparing Java to C#:
Java supports closures with anonymous inner classes, whereas in C#
only delegates (=functions) may close over the surrounding scope.
Being used to programming with closures, I felt that very limiting in
C# and ended up passing several delegates to the constructor of a
generic helper class (instead of creating named subclasses for each
case which probably would have been more natural).

On Tue, Apr 28, 2009 at 3:03 AM, FFT <[hidden email]> wrote:> I was watching a Google Tech talk by Martin Odersky, in which he says> that functional programmers do not understand the usefulness of OOP,
> specifically, the ability to extend classes by overriding methods.> However, as far as I can tell, he does not support this claim later in> the talk. As a counter-argument, I know that in OCaml, OOP is
> available (the "O" part), but is widely viewed as a failed experiment> (not "failed" in a pejorative sense, but even its creator does not use> the objective extensions). What can overriding methods do that
> higher-order functions can not do as well or better?>

The crucial thing is to be able to implement methods (and, in the caseof Scala, types)in subclasses. That way, the unknown part of an abstraction can be
left open in a class to be filled in later in subclasses. Functionalprogrammers indeed usually don't get this, and think higher-ordermethods or ML functors are a sufficient replacement. But the crucialdifference is this:

An implementation of an abstract {def, val, type} can refer to othermembers of its superclass. But an argument to a higher order method orfunctor cannot refer tothe result of the application. So open recursion with abstraction is
supported in OOP but it requires elaborate and rather tediousboilerplate in FP (such as the encodings of classes in TAPL (*).

To get a demonstration what difference this can make, I invite you totry to do this little task, which was originally proposed by Corky
Cartwright at a WG 2.8 meeting (**):

The task is to write an interpreter for a little functional language - lambda calculus with n-argument functions and integer arithmetic.There are several means to represent
variables and environments in such an interpreter. For instance,variables could be strings and environments association lists, orvariables could be DeBruijn numbers, and environments simple stacks.The question is this -- how much of your interpreter can you re-use if
you change your decision how to represent variables and environments?

Corky put this up as a challenge in the meeting because he noted thatthis was rather easy in Scheme, but almost impossible in GJ (or Java
today). So are static types hindering re-use? People at the meetingcame up with three different solutions, one in SML, one in Haskell,and one in Scala. The Scala solution used a simple abstract class forthe interpreter where environment type, variable type and environment
access were kept abstract. Abstract members were then implemented indifferent ways for DeBruijn and association list interpreters. TheHaskell solution used a big type class (with six functionaldependencies, if I remember correctly). The ML solution used functors
with sharing constraints. It was about 1 1/2 times the length of theother two solutions. Also, everyone but the most experienced MLprogrammers found it significantly harder to understand than the othertwo solutions. But it's really better if you try this out for
yourself...

Cheers

-- Martin

(*) Benjamin Pierce: Types And Programming Languages(**) IFIP Working Group for Functional Programming

>> To get a demonstration what difference this can make, I invite you to
>> try to do this little task, which was originally proposed by Corky
>> Cartwright at a WG 2.8 meeting (**):
>>
>> The task is to write an interpreter for a little functional language -
>> lambda calculus with n-argument functions and integer arithmetic.
>
>
> This sounds very interesting, Martin! Are the solutions people came up with
> documented anywhere that we could look at?
> On Tue, Apr 28, 2009 at 5:23 AM, martin odersky <[hidden email]>
> wrote:
>>
>> On Tue, Apr 28, 2009 at 3:03 AM, FFT <[hidden email]> wrote:
>> > I was watching a Google Tech talk by Martin Odersky, in which he says
>> > that functional programmers do not understand the usefulness of OOP,
>> > specifically, the ability to extend classes by overriding methods.
>> > However, as far as I can tell, he does not support this claim later in
>> > the talk. As a counter-argument, I know that in OCaml, OOP is
>> > available (the "O" part), but is widely viewed as a failed experiment
>> > (not "failed" in a pejorative sense, but even its creator does not use
>> > the objective extensions). What can overriding methods do that
>> > higher-order functions can not do as well or better?
>> >
>> The crucial thing is to be able to implement methods (and, in the case
>> of Scala, types)
>> in subclasses. That way, the unknown part of an abstraction can be
>> left open in a class to be filled in later in subclasses. Functional
>> programmers indeed usually don't get this, and think higher-order
>> methods or ML functors are a sufficient replacement. But the crucial
>> difference is this:
>>
>> An implementation of an abstract {def, val, type} can refer to other
>> members of its superclass. But an argument to a higher order method or
>> functor cannot refer to
>> the result of the application. So open recursion with abstraction is
>> supported in OOP but it requires elaborate and rather tedious
>> boilerplate in FP (such as the encodings of classes in TAPL (*).
>>
>> To get a demonstration what difference this can make, I invite you to
>> try to do this little task, which was originally proposed by Corky
>> Cartwright at a WG 2.8 meeting (**):
>>
>> The task is to write an interpreter for a little functional language -
>> lambda calculus with n-argument functions and integer arithmetic.
>> There are several means to represent
>> variables and environments in such an interpreter. For instance,
>> variables could be strings and environments association lists, or
>> variables could be DeBruijn numbers, and environments simple stacks.
>> The question is this -- how much of your interpreter can you re-use if
>> you change your decision how to represent variables and environments?
>>
>> Corky put this up as a challenge in the meeting because he noted that
>> this was rather easy in Scheme, but almost impossible in GJ (or Java
>> today). So are static types hindering re-use? People at the meeting
>> came up with three different solutions, one in SML, one in Haskell,
>> and one in Scala. The Scala solution used a simple abstract class for
>> the interpreter where environment type, variable type and environment
>> access were kept abstract. Abstract members were then implemented in
>> different ways for DeBruijn and association list interpreters. The
>> Haskell solution used a big type class (with six functional
>> dependencies, if I remember correctly). The ML solution used functors
>> with sharing constraints. It was about 1 1/2 times the length of the
>> other two solutions. Also, everyone but the most experienced ML
>> programmers found it significantly harder to understand than the other
>> two solutions. But it's really better if you try this out for
>> yourself...
>>
>> Cheers
>>
>> -- Martin
>>
>> (*) Benjamin Pierce: Types And Programming Languages
>> (**) IFIP Working Group for Functional Programming
>
>

Re: [scala] usefulness of OOP

> On Tue, Apr 28, 2009 at 2:23 AM, martin odersky <[hidden email]> wrote:
>> The ML solution used functors
>> with sharing constraints. It was about 1 1/2 times the length of the
>> other two solutions.
>
> If we are going to compare the lengths of code with such accuracy, a
> more precise problem definition could be helpful or, better yet, the
> original implementation to convert from (Scheme or Scala?)
>
> What's the syntax and semantics of the language being interpreted? Is
> the idea to have two implementations sharing code, while minimizing
> the total code size?
>

The task is to write two interpreters, one with variables x being
DeBruijn indices and one with them being names.
You should go for maximal sharing, i.e. factor out commonalities into
a common class/typeclass/functor/whatever, so that there remains no
duplication of code in the two solutions.

Re: [scala] usefulness of OOP

On Tue, Apr 28, 2009 at 8:31 PM, FFT <[hidden email]> wrote:
> On Tue, Apr 28, 2009 at 2:23 AM, martin odersky <[hidden email]> wrote:
>> The ML solution used functors
>> with sharing constraints. It was about 1 1/2 times the length of the
>> other two solutions.
>
> If we are going to compare the lengths of code with such accuracy, a
> more precise problem definition could be helpful or, better yet, the
> original implementation to convert from (Scheme or Scala?)
>
> What's the syntax and semantics of the language being interpreted? Is
> the idea to have two implementations sharing code, while minimizing
> the total code size?
>

The task is to write two interpreters, one with variables x being
DeBruijn indices and one with them being names.
You should go for maximal sharing, i.e. factor out commonalities into
a common class/typeclass/functor/whatever, so that there remains no
duplication of code in the two solutions.

Re: [scala] usefulness of OOP

On Tue, Apr 28, 2009 at 8:50 PM, Ricky Clarkson
<[hidden email]> wrote:
> Martin,
> Do you have a simpler such problem? I'd like to see what you mean for
> myself, but there's too much in there that I would need to learn beforehand.
> Ricky.
>
Not really. The problem is that any such discussion requires problems
of a certain size. You can't justify the usefulness of OOP on a
whiteboard (in any case, I can't). You need problems approaching real
size scenarios.

But in any case the solutions to the problem Corky gave are quite
manageable -- they were all under 60 lines AFAIRC.

Re: [scala] usefulness of OOP

Abstract members were then implemented in
different ways for DeBruijn and association list interpreters. The
Haskell solution used a big type class (with six functional
dependencies, if I remember correctly).

On Tue, Apr 28, 2009 at 3:03 AM, FFT <[hidden email]> wrote:
> I was watching a Google Tech talk by Martin Odersky, in which he says
> that functional programmers do not understand the usefulness of OOP,
> specifically, the ability to extend classes by overriding methods.
> However, as far as I can tell, he does not support this claim later in
> the talk. As a counter-argument, I know that in OCaml, OOP is
> available (the "O" part), but is widely viewed as a failed experiment
> (not "failed" in a pejorative sense, but even its creator does not use
> the objective extensions). What can overriding methods do that
> higher-order functions can not do as well or better?
>

The crucial thing is to be able to implement methods (and, in the case
of Scala, types)
in subclasses. That way, the unknown part of an abstraction can be
left open in a class to be filled in later in subclasses. Functional
programmers indeed usually don't get this, and think higher-order
methods or ML functors are a sufficient replacement. But the crucial
difference is this:

An implementation of an abstract {def, val, type} can refer to other
members of its superclass. But an argument to a higher order method or
functor cannot refer to
the result of the application. So open recursion with abstraction is
supported in OOP but it requires elaborate and rather tedious
boilerplate in FP (such as the encodings of classes in TAPL (*).

To get a demonstration what difference this can make, I invite you to
try to do this little task, which was originally proposed by Corky
Cartwright at a WG 2.8 meeting (**):

The task is to write an interpreter for a little functional language -
lambda calculus with n-argument functions and integer arithmetic.
There are several means to represent
variables and environments in such an interpreter. For instance,
variables could be strings and environments association lists, or
variables could be DeBruijn numbers, and environments simple stacks.
The question is this -- how much of your interpreter can you re-use if
you change your decision how to represent variables and environments?

Corky put this up as a challenge in the meeting because he noted that
this was rather easy in Scheme, but almost impossible in GJ (or Java
today). So are static types hindering re-use? People at the meeting
came up with three different solutions, one in SML, one in Haskell,
and one in Scala. The Scala solution used a simple abstract class for
the interpreter where environment type, variable type and environment
access were kept abstract. Abstract members were then implemented in
different ways for DeBruijn and association list interpreters. The
Haskell solution used a big type class (with six functional
dependencies, if I remember correctly). The ML solution used functors
with sharing constraints. It was about 1 1/2 times the length of the
other two solutions. Also, everyone but the most experienced ML
programmers found it significantly harder to understand than the other
two solutions. But it's really better if you try this out for
yourself...

Re: [scala] usefulness of OOP

I'm not objecting to the size of solutions; I'll happily rattle out a couple of thousand lines of code to demonstrate a point to myself, but I wonder if the same result could be obtained with a more approachable problem. Something of Programming in Scala's academic level.

On Tue, Apr 28, 2009 at 8:50 PM, Ricky Clarkson
<[hidden email]> wrote:
> Martin,
> Do you have a simpler such problem? I'd like to see what you mean for
> myself, but there's too much in there that I would need to learn beforehand.
> Ricky.
>

Not really. The problem is that any such discussion requires problems
of a certain size. You can't justify the usefulness of OOP on a
whiteboard (in any case, I can't). You need problems approaching real
size scenarios.

But in any case the solutions to the problem Corky gave are quite
manageable -- they were all under 60 lines AFAIRC.

Re: [scala] usefulness of OOP

On Tue, Apr 28, 2009 at 10:51 PM, Daryoush Mehrtash <[hidden email]> wrote:
> I am not sure I follow. So what is wrong with this:
>
>>
>> Abstract members were then implemented in
>> different ways for DeBruijn and association list interpreters. The
>> Haskell solution used a big type class (with six functional
>> dependencies, if I remember correctly).
>
>
Nothing. Did I imply that something was wrong with it?

Re: [scala] usefulness of OOP

> > To get a demonstration what difference this can make, I invite you to
> > try to do this little task, which was originally proposed by Corky
> > Cartwright at a WG 2.8 meeting (**):
> >
> > The task is to write an interpreter for a little functional language -
> > lambda calculus with n-argument functions and integer arithmetic.
> > There are several means to represent
> > variables and environments in such an interpreter. For instance,
> > variables could be strings and environments association lists, or
> > variables could be DeBruijn numbers, and environments simple stacks.
> > The question is this -- how much of your interpreter can you re-use if
> > you change your decision how to represent variables and environments?
> >
> > Corky put this up as a challenge in the meeting because he noted that
> > this was rather easy in Scheme, but almost impossible in GJ (or Java
> > today). So are static types hindering re-use? People at the meeting
> > came up with three different solutions, one in SML, one in Haskell,
> > and one in Scala. The Scala solution used a simple abstract class for
> > the interpreter where environment type, variable type and environment
> > access were kept abstract. Abstract members were then implemented in
> > different ways for DeBruijn and association list interpreters. The
> > Haskell solution used a big type class (with six functional
> > dependencies, if I remember correctly). The ML solution used functors
> > with sharing constraints. It was about 1 1/2 times the length of the
> > other two solutions. Also, everyone but the most experienced ML
> > programmers found it significantly harder to understand than the other
> > two solutions. But it's really better if you try this out for
> > yourself...

Apologies for joining this late (in case I missed what I'm looking for
already) but are the solutions available anywhere and has anyone added an
OCaml solution?

Re: [scala] usefulness of OOP

On Tue, Apr 28, 2009 at 8:31 PM, FFT <[hidden email]> wrote:
> On Tue, Apr 28, 2009 at 2:23 AM, martin odersky <[hidden email]> wrote:
>> The ML solution used functors
>> with sharing constraints. It was about 1 1/2 times the length of the
>> other two solutions.
>
> If we are going to compare the lengths of code with such accuracy, a
> more precise problem definition could be helpful or, better yet, the
> original implementation to convert from (Scheme or Scala?)
>
> What's the syntax and semantics of the language being interpreted? Is
> the idea to have two implementations sharing code, while minimizing
> the total code size?
>

The task is to write two interpreters, one with variables x being
DeBruijn indices and one with them being names.
You should go for maximal sharing, i.e. factor out commonalities into
a common class/typeclass/functor/whatever, so that there remains no
duplication of code in the two solutions.