Earlier quoted context omitted.
Classes do not imply inheritance. Classes are a means of defining an interface, albeit a heavy one. The statement that it is better to separate data and behavior is far from self-evident IMO, and I would be very interested to understand why this is such a deeply held belief. Seriously, why?
It's not always true, by any stretch of the imagination. Closures couple data and behavior and most (though not all) functional programmers consider closures to be pretty central to FP. I'd add that closures are hard to use in that way without allocating, which is why I think one potentially reasonable argument against coupling data and behavior is performance-driven, but that's a more subtle argument that ignores co…
Classes Considered Harmful [pdf]
121–129 of 129 posts
Re: Classes Considered Harmful [pdf]
#122Re: Classes Considered Harmful [pdf]
#123Earlier quoted context omitted.
I'm not familiar enough with the internals of how Rust handles v-tables and the like in light of its other features to answer that competently. In practice, one defines an interface in C++ by having a (hopefully) stateless class with pure virtual method declarations, and then classes derived from this class must implement these methods (in order to instantiate them anyway). In Rust one defines a data structure (eithe…
The big difference is that when you have a trait object in Rust, it's a double pointer: a pointer to the vtable, and a pointer to the data. In C++, in my understanding, you'd have a single pointer to both the vtable and data laid out next to each other.
What you describe for C++ is typically the case (and I've written completely unsafe, non-portable code that exploits this fact before), but I'm unsure whether that's required by the standard.
Re: Classes Considered Harmful [pdf]
#124Earlier quoted context omitted.
It is a convenient extra piece of flexibility. When you want to extend code in the future, inheritance can make it easier.
Sorry, not buying that one. There's nothing in inheritance that makes extending code easier. You either design for extension or not, has nothing to do with OOP.
A good, thoughtful design is better, of course.
Re: Classes Considered Harmful [pdf]
#125Earlier quoted context omitted.
OOP isn't the solution to every problem. Your proposed replacement to inheritance would would work nicely in some cases. As far as I can tell, it doesn't address the use case of generic classes at all, at least in a type-safe way.
Generics and OOP are orthogonal, one does not depend on the other. So let's say you declare your vtbl struct with a generic parameter, what's the difference?
Re: Classes Considered Harmful [pdf]
#126Earlier quoted context omitted.
It's not always true, by any stretch of the imagination. Closures couple data and behavior and most (though not all) functional programmers consider closures to be pretty central to FP. I'd add that closures are hard to use in that way without allocating, which is why I think one potentially reasonable argument against coupling data and behavior is performance-driven, but that's a more subtle argument that ignores co…
> Closures couple data and behavior The use of closures in functional programming is an implementation detail, not a fundamental aspect of the underlying theory, and closures only "couple" data and behavior in the very literal sense that it is a function that happens to point to some data under the hood, not in the syntactic or semantic sense we're referring to when we say that OOP classes couple behavior and data. A…
Re: Classes Considered Harmful [pdf]
#127Earlier quoted context omitted.
> Closures couple data and behavior The use of closures in functional programming is an implementation detail, not a fundamental aspect of the underlying theory, and closures only "couple" data and behavior in the very literal sense that it is a function that happens to point to some data under the hood, not in the syntactic or semantic sense we're referring to when we say that OOP classes couple behavior and data. A…
Purity seems to be totally orthogonal to this question, to me. I'm referring to the ability to return thunks from within called functions, such that the data are totally encapsulated in the closure (are not passed in explicitly and cannot be retrieved manually). That seems to be coupling data and behavior to me, since you can't run the function without the data it was coupled with at construction time. Whether that's…
Ah, well there's the confusion. A language with semantically impure closures emphatically does not reproduce the semantics of the lambda calculus unless you restrict yourself to only pure, immutable variables. But if you reproduce the lambda calculus, there's no need for closures as we know them. It's just an implementation that happens to work well. You could supercompile the lambda-abstraction at the application site and avoid having a closure. It's just not a good idea.
But I agree, in a language with mutable variable capture, you can reproduce the semantics of OOP by providing a bundle of functions closed over mutable references to the "object" data.
> a language that bills itself as functional that doesn't provide that capability natively
I'm not sure exactly what capability you're referring to. Could you clarify a little bit?
Re: Classes Considered Harmful [pdf]
#128Earlier quoted context omitted.
Purity seems to be totally orthogonal to this question, to me. I'm referring to the ability to return thunks from within called functions, such that the data are totally encapsulated in the closure (are not passed in explicitly and cannot be retrieved manually). That seems to be coupling data and behavior to me, since you can't run the function without the data it was coupled with at construction time. Whether that's…
> Purity seems to be totally orthogonal to this question, to me. Ah, well there's the confusion. A language with semantically impure closures emphatically does not reproduce the semantics of the lambda calculus unless you restrict yourself to only pure, immutable variables. But if you reproduce the lambda calculus, there's no need for closures as we know them. It's just an implementation that happens to work well. Yo…
(* foo.ml *)
let bar =
let foo = lambda x . lambda y .
if y == 0 then { getFoo : lambda z . 0 }
else { getFoo : lambda z . (x * z - x + z) / y }
end
in foo 3
(* bar.ml *)
include foo.ml
let y = bar 5
bar.getFoo(4)
It sure seems to me that bar is hiding the 3 from bar.ml (and there are much more complicated examples where foo.ml really can't get at the captured type, for instance), and at the same time it's capturing the value of 5. The function getFoo on bar is bound to it (the record type can desugar to more curried lambdas, if necessary, it's just tedious and this illustrates my point better).None of this seems to have anything to do with mutation, to me, though it certainly seems to have both information hiding and binding logic and data. The fact that it can be compiled not to use closures (using whole-program compilation) is immaterial; the same is true for the same program specified with objects in mutable languages (SML has both mutation and closures, and MLton does exactly that).
Re: Classes Considered Harmful [pdf]
#129I like this kind of critical papers but I cannot agree with the author in this case. I have studied this problem quite deeply while working on concept-oriented programming and concept-oriented data model ( http://conceptoriented.org/ ) for many years by also trying to minimize the number of basic constructs. Yet, my conclusion is that classes are actually needed. There are several major reasons for that. One of them…
we actually need two different relations: 1) membership relation, and 2) inheritance (or inclusion in more general case). No. You don't need OO at all, let alone bolt-on conceptual baggage like this. The notion of object oriented programming is completely misunderstood. It's not about objects and classes, it's all about messages. - Alan Kay[0] [0] From my fortune clone @ https://github.com/globalcitizen/taoup
Often cited, but somewhat meaningless without the context in which Kay originally made that statement.
One should instead consider that object-orientation is "… the insight that everything we can describe can be represented by the recursive composition of a single kind of behavioral building block that hides its combination of state and process inside itself and can be dealt with only through the exchange of messages." - Alan Kay
It is primarily an approach to representing complex problems and systems in code. It is an alternative to modular programming (procedures and subroutines) organized using functional decomposition (structured programming), or an information or data-flow modeling approach. It is not primarily about organizing code.