[inout][templates][opaque] Ignorance is strength
Iakh via Digitalmars-d
digitalmars-d at puremagic.com
Mon Apr 25 16:00:52 PDT 2016
Recent discussion about inout cause some thoughts on this. And
they bring me to opaque
types. We could put a type into temlate but there is no direct
way to limit information
about this type inside template.
There is no way to say that template uses only part info about
type or don't use it
at all or use it only in some places.
The idea is to say that parameter type T is only "forward
declaration".
So lets consider we have keyword "opaque" for such purpose. If
type T is opaque than
only address/ref could be used therefore lots of instances of
template based on opaque
T would generate same code.
----
struct Array(opaque T)
if (isPOD!T)
{
this()(size_t length) // Template inside template could use
full typeinfo about T
{
elemSize = sizeof(T);
//...
}
void emplaceBack(Args...)(Args args)
{
// allocate memory for one more element at the end and
call emplace ctor
// Here available full info about T as emplaceBack is
template.
}
ref T opIndex(size_t i) @trusted
{
return *cast(T*)elements[i * elemSize];
// reinterpret cast and dereferncing allowed in return
statement.
// It's illegal to create instances (there is no info
about ctor)
// You could use kind of factory-method
}
size_t elemSize;
size_t length;
size_t capacity;
void* elements;
static int someField; // Error: it is illegal to use static
fields or variables with "opaque" template params
}
----
In the Array!T method opIndex will generate same code for any
type. But if some
overloaded function will be called with ref/pointer to opaque T
within template, it would emit different code for different
instantiations:
----
void read(ref int a) { ... }
void read(ref double a) { ... }
void g(opaque T)(ref T a)
{
read(a);
}
int a;
g(a);
double b;
g(b);
----
So lets move step forward in our ignorance about types.
"opaque(Smth) T" means that inside of template T is lowered to
Smth:
----
ref T f(opaque(void) T)(ref T a); // Inside of function T is like
a void. But here is problems with refs. Maybe opaque(void) isn't
correct.
ref T f(opaque(const) T)(ref T a); // Inside of function T is
like a const
ref T f(opaque(const int) T)(ref T a); // Inside of function T is
cons int. So close to "inout". T could be const, mutable or
immutable int.
ref T f(opaque(IForwardRange) T)(ref T a); // Inside of function
T is interface.
----
Return value will be casted to original T. There is problem with
"ref void".
Sample with opaque(interface):
----
struct KindOfGeneric(opaque(IForwardRange) R)
{
R get() // in fact it is "IForwardRange get()" with magic in
call place
{
pragma(msg, R); // IForwardRange
return r;
}
R r; // Will be treated like IForwardRang r;
}
KindOfGeneric!(SomeRange) a = someFunc();
auto r = a.get(); // would generate: auto r =
cast(SomeRange)a.get();
----
Sample with opaque(const int):
----
// This is template-like code but it will generate one instance
ref T refToMaxInt(opaque(const int) T)(ref T a, ref T b)
{
pragma(msg, T); // const int
return (a > b) ? a : b;
}
----
More information about the Digitalmars-d
mailing list