mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
Continuing to flesh this out
This commit is contained in:
parent
0bb4772d03
commit
304df4ff1b
@ -6,6 +6,9 @@ category:
|
|||||||
tags: [python]
|
tags: [python]
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Other languages have done similar things (interfaces in Java), but think the Rust comparison is
|
||||||
|
useful because both languages are "system."
|
||||||
|
|
||||||
# Simple Example
|
# Simple Example
|
||||||
|
|
||||||
Accept parameter types, return known type.
|
Accept parameter types, return known type.
|
||||||
@ -20,6 +23,8 @@ Same parameter signature, but return different types - `AsRef`
|
|||||||
|
|
||||||
# Arbitrary `self`
|
# Arbitrary `self`
|
||||||
|
|
||||||
|
Forms the basis for Rust's async system, but used very rarely aside from that.
|
||||||
|
|
||||||
[`std::enable_shared_from_this`](https://en.cppreference.com/w/cpp/memory/enable_shared_from_this)
|
[`std::enable_shared_from_this`](https://en.cppreference.com/w/cpp/memory/enable_shared_from_this)
|
||||||
|
|
||||||
`enable_unique_from_this` doesn't make a whole lot of sense, but Rust can do it:
|
`enable_unique_from_this` doesn't make a whole lot of sense, but Rust can do it:
|
||||||
@ -102,7 +107,8 @@ impl MyTrait for Box<MyStruct> {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Just have to make sure that `MyTrait` is in scope all the time, and that's not fun. Ultimately, Rust
|
Just have to make sure that `MyTrait` is in scope all the time, and that's not fun. Ultimately, Rust
|
||||||
kinda already has UFCS.
|
kinda already has UFCS. It's only "kinda" because you have to bring it in scope, and it's
|
||||||
|
potentially unclear when it's being used (extension traits), but it does get the basic job done.
|
||||||
|
|
||||||
# Default implementation
|
# Default implementation
|
||||||
|
|
||||||
@ -154,7 +160,7 @@ Shouldn't be too hard - `T::some_method()` should be compilable.
|
|||||||
|
|
||||||
`noexcept`, etc.
|
`noexcept`, etc.
|
||||||
|
|
||||||
# Local trait implementation of remote types?
|
# Local trait implementation of remote data type?
|
||||||
|
|
||||||
AKA "extension methods". UFCS can accomplish this, and could use free functions to handle instead,
|
AKA "extension methods". UFCS can accomplish this, and could use free functions to handle instead,
|
||||||
but having the IDE auto-complete `.<the next thing>` is exceedingly useful, as opposed to memorizing
|
but having the IDE auto-complete `.<the next thing>` is exceedingly useful, as opposed to memorizing
|
||||||
@ -162,7 +168,60 @@ what functions are necessary for conversion. We're not changing what's possible,
|
|||||||
easier for humans.
|
easier for humans.
|
||||||
|
|
||||||
Likely requires sub-classing the remote class. Implicit conversions don't _really_ work because they
|
Likely requires sub-classing the remote class. Implicit conversions don't _really_ work because they
|
||||||
must be defined on the remote type.
|
must be defined on the remote type (not true: `operator Local` must be defined on remote, but
|
||||||
|
`Local` could have a `Local(const Remote&)` implicit constructor). Could maybe use wrapper classes
|
||||||
|
that have single-arg (implicit) constructors, and get away with it as long as the wrapper knows it's
|
||||||
|
not safe to modify the internals. That said, wrapper can only use the public interface unless
|
||||||
|
declared friend (which is no different to Rust).
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#include <concepts>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class SomeRemoteClass {};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept MyConcept = requires (T a) {
|
||||||
|
{ a.do_something() } -> std::same_as<std::uint64_t>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note: It's unsafe to move `SomeRemoteClass`, so we accept by reference
|
||||||
|
// Requiring SomeRemoteClass be copy-constructible would also be OK.
|
||||||
|
class LocalImpl {
|
||||||
|
public:
|
||||||
|
LocalImpl(const SomeRemoteClass &remote): remote_{remote} {};
|
||||||
|
std::uint64_t do_something() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const SomeRemoteClass &remote_;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto auto_func(MyConcept auto value) {
|
||||||
|
auto x = value.do_something();
|
||||||
|
}
|
||||||
|
|
||||||
|
void regular_func(LocalImpl value) {
|
||||||
|
auto x = value.do_something();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
SomeRemoteClass x {};
|
||||||
|
|
||||||
|
// This isn't OK because `auto` doesn't automatically convert to `LocalImpl`
|
||||||
|
//auto_func(x);
|
||||||
|
|
||||||
|
// This _is_ OK because we explicitly declare the class we want (`LocalImpl`) and `SomeRemoteClass`
|
||||||
|
// is implicitly converted. Just so happens that `LocalImpl` implements `MyConcept`.
|
||||||
|
regular_func(x);
|
||||||
|
|
||||||
|
// We could extend the conversion pattern using specializations of `LocalImpl`, or maybe use
|
||||||
|
// `std::variant` to hold different internal types, but there's still a disconnect between
|
||||||
|
// what we actually want to fulfill (`MyConcept`) and how that's implemented for remote types
|
||||||
|
// (using the `LocalImpl` wrapper and implicit conversions).
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Rust makes this weird because you have to `use ClientExt` to bring the methods in scope, but the
|
Rust makes this weird because you have to `use ClientExt` to bring the methods in scope, but the
|
||||||
trait name might not show up because `impl ClientExt for RemoteStruct` is defined elsewhere.
|
trait name might not show up because `impl ClientExt for RemoteStruct` is defined elsewhere.
|
||||||
|
Loading…
Reference in New Issue
Block a user