Mutable enums

Steven Schveighoffer schveiguy at yahoo.com
Thu Nov 17 10:23:58 PST 2011


On Thu, 17 Nov 2011 12:31:58 -0500, Timon Gehr <timon.gehr at 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


More information about the Digitalmars-d-learn mailing list