www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [inout][templates][opaque] Ignorance is strength

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;
}
----
Apr 25 2016