Date: Tue, 15 Jun 2021 09:18:38 -0700
Hi all,
Had an idea for a language feature that I'd like to float.
At the moment, an overloaded operator->() eventually resolves to a pointer
of arbitrary type, before calling some method or accessing a data member
from the type of that pointer.
class SmartPointer {
public:
Pointee* operator->();
};
SmartPointer s;
s->f(); // Resolves to a Pointee* p, then calls Pointee::*f(p).
I would like to change this, so that instead of immediately
calling Pointee::*f(p), we look for a method in the current class scope and
if found, call that instead:
class SmartPointer {
public:
Pointee* operator->();
template<typename R, typename... Args>
T operator->(Pointee* p, R (Pointee::*f)(Args...));
};
SmartPointer s;
s->f(); // Resolves to s.operator-><Pointee>(s->operator(), &Pointee::f);
The motivation here is to allow something that looks very like a monad.
This secondary overload would provide the bind functionality of the monad,
composing the member function of the other class into the monadic context.
The real-life example that motivated this is the clunkiness of return types
in a serialization structure (Thrift structs, to be exact). At present, if
a Thrift field is marked optional, the accessor method returns an optional
reference wrapper for the type of that field. When there is a hierarchy of
optional fields, this tends to lead to code that looks like:
if (c.field1_ref().has_value() &&
c.field1_ref()->field2_ref().has_value() &&
c.field1_ref()->field2_ref()->field3_ref().has_value() {
... do something
with c.field1_ref()->field2_ref()->field3_ref().value() ...
}
Each level of the hierarchy has to be checked before moving onto the next,
or the expression will throw when a field is not present.
The above overload would allow the reference wrapper to recursively wrap
the return types of the child methods in an optional reference wrapper,
making a call to:
c.field1_ref()->field2_ref()->field3_ref().has_value()
safe regardless of whether the fields are missing or not.
This would also allow other functionality that wants to intercept and
potentially redirect smart pointer function calls like:
* calling the method on a different thread
* calling the method on a different machine over RPC
* logging function call statistics
* experimental diversions on new code being tested
Had an idea for a language feature that I'd like to float.
At the moment, an overloaded operator->() eventually resolves to a pointer
of arbitrary type, before calling some method or accessing a data member
from the type of that pointer.
class SmartPointer {
public:
Pointee* operator->();
};
SmartPointer s;
s->f(); // Resolves to a Pointee* p, then calls Pointee::*f(p).
I would like to change this, so that instead of immediately
calling Pointee::*f(p), we look for a method in the current class scope and
if found, call that instead:
class SmartPointer {
public:
Pointee* operator->();
template<typename R, typename... Args>
T operator->(Pointee* p, R (Pointee::*f)(Args...));
};
SmartPointer s;
s->f(); // Resolves to s.operator-><Pointee>(s->operator(), &Pointee::f);
The motivation here is to allow something that looks very like a monad.
This secondary overload would provide the bind functionality of the monad,
composing the member function of the other class into the monadic context.
The real-life example that motivated this is the clunkiness of return types
in a serialization structure (Thrift structs, to be exact). At present, if
a Thrift field is marked optional, the accessor method returns an optional
reference wrapper for the type of that field. When there is a hierarchy of
optional fields, this tends to lead to code that looks like:
if (c.field1_ref().has_value() &&
c.field1_ref()->field2_ref().has_value() &&
c.field1_ref()->field2_ref()->field3_ref().has_value() {
... do something
with c.field1_ref()->field2_ref()->field3_ref().value() ...
}
Each level of the hierarchy has to be checked before moving onto the next,
or the expression will throw when a field is not present.
The above overload would allow the reference wrapper to recursively wrap
the return types of the child methods in an optional reference wrapper,
making a call to:
c.field1_ref()->field2_ref()->field3_ref().has_value()
safe regardless of whether the fields are missing or not.
This would also allow other functionality that wants to intercept and
potentially redirect smart pointer function calls like:
* calling the method on a different thread
* calling the method on a different machine over RPC
* logging function call statistics
* experimental diversions on new code being tested
Received on 2021-06-15 11:18:52