The idea is, that it decouples state from behavior, while a class tries to group that together. Other people can implement traits later for your struct. (I think Clojure has something similar.) They do not need to subclass your struct and in fact cannot even. This design encourages and kind of forces composition over inheritance.
I would not name it a class, because I don't want people to fall back into thinking: "Ah I know! Inheritance!".
Well, having classes doesn't mean that you will necessarily use inheritance. There are programmers (ab)using it a lot, but for me, like for many others, classes are primarily a way to organize code: they provide a convinient way of representing something and specify functions that only make sense in the context of that something, while ensuring that you don't accidentally re-use those function for something else or lose track of which functions are meant for which component. They also provide a way to make collaboration easier, as you can agree on classes' interfaces and then each one goes on to implement it's own classes without having to worry about implementation details of other classes. It is true that you usually also have inheritance with classes, but I'm unsure if having it is a requirement to call something a class. IIRC from a theory perspective, classes are just an abstraction of some concepts, and the fact that a class' instance is called an object reflects this.
I think the person you're replying to tried to address that point that classes are primarily a way to organise code when other possibly equally good or better options exist like modules. An F# module might (for example) look like below.
module Hello =
let say() = "hi" // returns the string "hi"
There are mechanisms to encapsulate implementation details (private functions), to have multiple modules for different "domains" and specifying public contracts.
A class seems to imply more than that: each class specifies how to create an object with a constructor (where an object is something with the class's methods except modifying some state only owned by and accessible by the object itself).
But in Rust you've got constructors as well. The only thing that really seems to be missing is inheritance. But I understand that one might say that classes without the possibility of using inheritance don't look fully right.
> a constructor is a special type of function called to create an object.
Now, I don't think Wikipedia is always the authority on everything, but this is how I view them as well. A constructor is kinda like a callback that the language runtime invokes when an something is created. For example, in C++:
class Foo {
public:
Foo() {
// your code goes here
}
};
int main() {
Foo a; // constructor invoked here
}
(please excuse formatting, there is no unified C++ style so I just picked one)
or in Ruby:
class Foo
def initialize
# your code goes here
end
end
Foo.new # constructor invoked here
These "constructors" in Rust don't work like that at all. They are not special member functions that are invoked when something is created; they are the syntax to create something.
I think this is where things get muddy. On one hand, I think that there is still a function call going on under the hood, even if the syntax hides that. On the other, if you need some preprocessing before assigning the values to your struct's fields, you can still define a special member function that does whatever you need to figure out what the correct values are. In my view, what Rust is actually missing is the default constructor, because it will not initialize variables to some default value for you.
If you define a function that does some preprocessing before creating an instance in Rust, it is not a special member function that the language understands. It’s just a regular old function that happens to return an instance.
I do agree that it can be useful when discussing code to refer to these style functions with a more specific term, like a constructor, but that’s a colloquialism, and when discussing language features, being precise is important.
Classes are about data abstraction and encapsulation, which have nothing to do with implementation inheritance. They're about providing an interface that preserves any required invariants and does not depend directly on how the data is represented. A "structure" that either preserves useful invariants or is intended to admit of multiple possible representations that nonetheless expose the same outward behavior is effectively a class, whether you call it one or not.
I think the discussion of what to call that is a bit pointless. For some people through their Java/C++/whatever-tinted glasses, these things will be classes. To others they might be called something else. You personally call them "classes". I personally do not. Rust the language does not. Lots of people behind the development of the language thought that structs and traits are better names.
I appreciate the programming language design behind them and hope, that Rust will not devolve into an ecosystem, where everyone thinks that they must put everything into classes or similar, needlessly maintaining state therein, requiring users to mutate that state through accessors and whatnot, when simply a couple of functions (and I mean strictly functions, not procedures) would have done the job.
I never stated, that I personally think classes necessarily mean inheritance. But guess who thinks so. Lots and lots of developers working with mainstream languages, where frequently inheritance is made use of, in combination with what those languages call a "class". That is why I am saying, that I don't want those people to fall back into their previous thinking and would not want to call them classes. It gives many many people the wrong ideas.
What other people call it is their own choice. I am merely stating my own preference here and probably the preference of the language designers, whom I mostly deem to be quite a lot more competent in drawing the distinction than myself.
> requiring users to mutate that state through accessors
There are plenty of cases where this makes sense, such as when working with sub-word data (bitfields), which is common in the embedded domain and often found as part of efficient code more generally. In fact, it may be more rare to have actual structs where one definitely wants to provide actual access (e.g. via pointers/refs) to the underlying data, and thus cannot just rely on getters/setters.
I would not name it a class, because I don't want people to fall back into thinking: "Ah I know! Inheritance!".