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;
}
----

Reply via email to