How does a mixin compare to role or interface in languages that do not have multiple inheritance?
You can just declare by convention that a freestanding clone(T x) -> T function should exist for it to be 'cloneable'.
It actually does have specific applications. That Wikipedia article shows a good example of polymorphic method chaining. In a former life, I worked with Microsoft’s Active Template Library, which is entirely based on this pattern.
static
auto create(const char* data) -> Result<String>
Types are a lot more ergonomic on the left - the return type of a function and the type of a variable are very important for understanding and skimming code. When the return type is on the right, it is physically very far from the name of the object and I have to scan the entire line with my eyes to get the same amount of information I would get by just looking at the left column and scrolling down if it were on the left. I am pretty sure in another 20 years types on the right will be regarded as one of the ergonomic fails of current language design. At least, if have to do this, put the type right under the object name, like so: static auto
create(const char* data)
-> Result<String>
Future readers will thank you.Having both left and right types is stupid, but as a whole right types are easier to deal with
In BSD of yore and modern contemporaries, one could often perform `grep '^function'` and end up finding the source file quite easily. I think it also makes using ctags(1) a bit easier too, but not entirely sure on that bit.
C-style type declarations were always the most painful part of reading C.
void foo(auto& t) { t.bar(); }
which can be called with any class that has the .bar() method anyway.
An interesting option in this space is rpp [1], which bills itself as a “Minimal Rust-inspired C++20 STL replacement”
So does the clone...
std::optional<T&>
Can't have optional references in C++. Use either std::reference_wrapper, or just a pointerA signature resembles a class declaration in that it specifies member functions. A signature is never instantiated. Rather any class which has those member functions conforms to the signature, and a signature-typed pointer can point to instances of that class. Thus signatures bring about quack-like-a-duck polymorphism not requiring inheritance.
signature communicator {
size_t send(const unsigned char *buf, size_t size);
size_t recv(const unsigned char *buf, size_t size);
};
class foo {
size_t send(const unsigned char *buf, size_t size);
size_t recv(const unsigned char *buf, size_t size);
};
foo f;
communicator *c = &f; // valid: foo conforms to communicator signature
(Not sure if these member functions need to be virtual? I would have to dig up the Signatures docs.)This feature was removed because the implementation was becoming hard to maintain, or some reason like that.
You can see it's pretty crazy from a C++ point of view, because c->recv(...) can be called through this pointer and it has to work for absolutely any object whose class conforms to the signature. And classes don't know they are conforming to any signature; nothing is declared in them for that.
C++ polymorphism normally depends on declaration relationships through which implementation details like vtable positions can be inferred.