10 ms·
simply cause objects to return a new version of themselves with the suitable updated state That's what Clojure does (and what lots of other functional language
by kyllo 12y ago
simply cause objects to return a new version of themselves with the suitable updated state
That's what Clojure does (and what lots of other functional languages do), only they're not "objects," they're just data structures.
Again, if you're not using mutability or inheritance, then why do you need objects at all? What do objects buy you, compared to data types + functions?
In the absence of those features, isn't an object class really just a module with a data type definition and some functions in it?
- tel 12y agoIt depends on what "object" means to you. Turns out this is very, very complex. A deep answer has a lot to do with laziness, F-algebras, totality, dependent types, yada yada yada. In particular, the tip of this iceberg is the difficulty of comparing functions for equality. Does any of this matter? Maybe not. Structs with recursion can get you 90% of what you want (just ask OCaml). One thing you might miss is the ability to do late binding and open recursion—up to you whether or not you care.
- kyllo 12y agoOne thing you might miss is the ability to do late binding and open recursion In the absence of objects, that's what `letrec` is for. Scheme, OCaml, and SML all have it. In Haskell `let` is `letrec` by default. Clojure has `letfn`. C has forward declarations. Without these features you wouldn't be able to write mutually recursive functions.
- tel 12y agoYou can emulate late binding in these languages (though the required types are quite clever) but letrec does not do this directly! In particular, letrec is closed immediately—you cannot extend it later. In particular, you don't actually need or want letrec to encode open recursion. That's most of the fun :)
- kyllo 12y agoOk, so my question was, why you need objects at all if you're deciding that your objects should be immutable, and if I'm understanding you correctly, your response is essentially that you need objects if you want inheritance. Because the extensible open recursion you're talking about only matters in a situation where you're working with base classes and subclasses having different implementations of the same method name and needing dynamic dispatch to determine which one gets called at runtime. Clojure's hierarchical multimethod system is an interesting alternative approach to this that I think fulfills the semantics you're talking about. I guess you could argue that this is a sort of immutable object system, it's just not called that. http://clojure.org/runtime_polymorphism http://clojure.org/runtime_polymorphism
- tel 12y agoFirstly, "object" as a term is really hard to stick a pin in. It's slippery and hard to talk about, so I'm kind of trying to avoid it. Secondly, "objects" can imply open-recursion which can be used to implement inheritance. That said, inheritance isn't the only thing open recursion is good for and inheritance can be implemented without open recursion. "Object"s can also imply codata like structures as compared to data like structures. The distinction is blurry to the point of indistinguishability in essentially all languages, but it's important in theorem proving and math and thus shows up in dependently typed languages. Thirdly, dynamic dispatch is one way to achieve open recursion but it's not the only way. I don't know if dynamic dispatch is useful for things other than open recursion, so offhand I would say "dynamic dispatch => open recursion is being used" but not the other way around. Clojure's multimethod system, given that it's an implementation of dynamic dispatch, implies open recursion and thus has at least one factor which some people associate with objects. It's immutable (at least to the degree which Clojure is immutable) so I'm willing to call it an "immutable object system", yes. But with all of the caveats I just listed!