On Thu, 17 Nov 2011 12:31:58 -0500, Timon Gehr <timon.g...@gmx.ch> wrote:

On 11/17/2011 03:19 PM, Steven Schveighoffer wrote:


What does writelnInferConst!T do? I'm afraid I'm not getting what you
are saying.

I was thinking writeln should do this:

void writeln(T...)(const T args) {...}

As you pointed out, this cannot print types that have a non-const toString method (caching the result could be a perfectly valid reason for that.)

Caching string representation IMO is not a significant use case. Not only that, but toString should be deprecated anyways in favor of a stream-based system.

writelnInferConst finds out which parameters can be treated as const and still be printed so that the correct version of writeln may be called.

For example:

class Foo{ // can be printed if const
     string toString()const{return "Foo";}
}

class Bar{ // cannot be printed if const
     string cache;
     string toString(){return cache!is null?cache:(cache="Bar");}
}

template hasConstToString(T){
enum hasConstToString = is(typeof((const T t){return t.toString();}));
}

template writelnInferConstImpl(T...){
     static if(!T.length) alias T X;
     else static if(hasConstToString!(T[0])){
             alias T[0] _;
             alias TypeTuple!(const(_),writelnInferConst!(T[1..$])) X;
     }else
         alias TypeTuple!(T[0],writelnInferConst!(T[1..$])) X;
}
template writelnInferConst(T...){alias writelnInferConstImpl!T.X writelnInferConst;} // (bug 6966)


static assert(is(writelnInferConst!(Foo,Bar,Foo,Foo,Bar)==TypeTuple!(const(Foo),Bar,const(Foo),const(Foo),Bar)));

If your goal is to reduce template bloat, I think this is not the solution.

But also note that this still does not guarantee const. I don't really see the point of doing all these templates if you aren't going to guarantee writeln doesn't modify the data.


The issue with all this is, IFTI doesn't work that way:

void foo(T: short)(T t) {}

void main()
{
foo(1);
}

testifti.d(5): Error: template testifti.foo(T : short) does not match
any function template declaration
testifti.d(5): Error: template testifti.foo(T : short) cannot deduce
template function from argument types !()(int)

IFTI decides the types of literals before trying to find a proper
template to instantiate. Any possibility to intercept the decision of
literal type or of instantiation would be useful. I think that it's
better suited to the constraints, because there is more power there. But
I'm not sure. If you can find a more straightforward way, I'm all for it.

In any case, I need to update the bug report, because the general case
is if foo has an overload. For instance:

foo(short s);
foo(wstring w);

foo2 should be able to call both with 1 and "hello" without issue.

My driving use case to create the enhancement was creating a wrapper
type that intercepted function calls. I planned to use opDispatch, but
it didn't quite work with literals.

Ok, I see the problem. My proposed IFTI template mechanism would save the day.

It would look like this (static foreach would have to be replaced by a recursive mixin template because Walter encountered implementation difficulties).


template OverloadsOf(alias symbol){ // should this be in std.traits?
alias TypeTuple!(__traits(getOverloads, __traits(parent,symbol), __traits(identifier,symbol))) OverloadsOf;
}

auto wrapper(alias foo)(ParameterTypeTuple!foo args){
     return foo(args);
}
template opDispatch(string op,T...)(T){
     static foreach(foo; OverloadsOf!(mixin(op))){
         alias wrapper!foo opDispatch;
     }
static if(OverloadsOf!(mixin(op)).length==0) { // we are dealing with a template function
         auto opDispatch(T args){
             return foo(args);
         }
     }
}

Pardon my saying so, but this looks horrendous. Not to mention that I don't think it would work. IFTI instantiates templates, it does not look inside instantiated templates for overloads.

BTW, your proposed IFTI template mechanism, do you have it stated anywhere? Maybe it fixes the problem I mentioned.

Seems rather odd you should have to jump through these hoops to get the
compiler to use ROM space. But I concede that I did not know of this
trick. It does not sway my opinion that CTFE should produce ROM-stored
references, and library function should be used for runtime-constructed
references.


CTFE should produce ROM-stored data iff it is used during run time, I agree on that. However if the enum is typed as mutable, it should create a copy of the ROM-stored data.

Well, this is closer than I thought we were to an agreement. I would agree with this, as long as it could be implicitly cast to immutable or const.

i.e.:

enum foo = [1, 2, 3];

immutable(int)[] a = foo; // no allocation
const(int)[] b = foo; // no allocation

-Steve

Reply via email to