Once created, objects and collections must be immutable.
Collections I understand, but what's the point of immutable objects? If you're eschewing mutability, why have objects at all? The whole point of objects is to encapsulate mutable state, together with methods for mutating that state.
If you said Once created, data structures must be immutable I would be more inclined to agree.
I program in Scala, so structs are not a thing (classes can extend/"inherit" AnyVal to be allocated on the stack, though, I think). Functions are nice, but from a pure syntax standpoint I often prefer methods because it limits the parantheses. It's especially neat when the methods take no arguments, like .toString.
But yeah, otherwise there's no difference, really.
Express your immutable objects with an interface like this
push : ('a queue, 'a) -> 'a queue
pop : 'a queue -> ('a queue, 'a) option
In other words, instead of mandating that state updates in objects occurs via global ambient state simply cause objects to return a new version of themselves with the suitable updated state. All your standard immutability tricks now apply. Objects maintain their meaning through their opaqueness/type-abstraction.
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?
It 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.
One 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.
You 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 :)
Ok, 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
Firstly, "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!
Collections I understand, but what's the point of immutable objects? If you're eschewing mutability, why have objects at all? The whole point of objects is to encapsulate mutable state, together with methods for mutating that state.
If you said Once created, data structures must be immutable I would be more inclined to agree.