www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Stripping away const/invariant in D 2.0

reply Daniel Keep <daniel.keep.lists gmail.com> writes:
I've been trying to work this out for a few hours now, and I'm drawing a
blank.  In D 2.0, there doesn't appear to be any way of deriving the
type of T given either (const T) or (invariant T).

This came up because of my templated join function which takes an array
of arrays, a separator, and joins all the arrays together.  For instance:

  ["foo","bar","baz"].join(", ") == "foo, bar, baz"

The problem is when the arguments are some combination of const and/or
invariant.  In order to efficiently do the join, it allocates a result
array large enough for the full result, then fills it in using slicing.
 Problem is, what type does it use?

Given:

  T[] join(T,U)(in T[][] parts, in U[] sep=null)

There doesn't appear to be any way to derive a mutable version of T or
U.  I've tried is( T V : const V ) and is( T V == const V ) as well as
various array tricks, but nothing seems to be working.  In the two "is"
cases, V is *always* the same type as T.

So unless I've completely missed something, I think one of the following
needs to be added:

1. Support for is( T U == const ) and is( T U == invariant ), where U
   becomes a mutable version of T,

2. a new __traits form: __traits(mutableTypeOf, T) or

3. a new `mutable` keyword that works analogously to const and
   invariant, except that it strips off const and invariant.

I also feel that these constructs should do this constness stripping
*only* one level deep (so mutable const(char)[][] is (const(char)[])[]
-- removing all levels of constness can be done using a recursive template.)

Thoughts (or maybe even corrections? :) )

	-- Daniel
Aug 28 2007
next sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Daniel Keep wrote:
 I've been trying to work this out for a few hours now, and I'm drawing a
 blank.  In D 2.0, there doesn't appear to be any way of deriving the
 type of T given either (const T) or (invariant T).
 
 This came up because of my templated join function which takes an array
 of arrays, a separator, and joins all the arrays together.  For instance:
 
   ["foo","bar","baz"].join(", ") == "foo, bar, baz"
 
 The problem is when the arguments are some combination of const and/or
 invariant.  In order to efficiently do the join, it allocates a result
 array large enough for the full result, then fills it in using slicing.
  Problem is, what type does it use?
 
 Given:
 
   T[] join(T,U)(in T[][] parts, in U[] sep=null)
 
 There doesn't appear to be any way to derive a mutable version of T or
 U.  I've tried is( T V : const V ) and is( T V == const V ) as well as
 various array tricks, but nothing seems to be working.  In the two "is"
 cases, V is *always* the same type as T.
 

Use "typeof(T)". For example if T is invariant char , then typeof(T) == char. typeof() kinda works like a declaration, so it removes the top level const/invariant. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 28 2007
next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Bruno Medeiros wrote:
 Use "typeof(T)". For example if T is invariant char , then typeof(T) ==
 char. typeof() kinda works like a declaration, so it removes the top
 level const/invariant.

That's... weird. But it works. Thanks very muchly :) I still think having something a little more... consistent with existing idioms would be good, though. -- Daniel
Aug 28 2007
prev sibling parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 I've been trying to work this out for a few hours now, and I'm drawing a
 blank.  In D 2.0, there doesn't appear to be any way of deriving the
 type of T given either (const T) or (invariant T).

Use "typeof(T)". For example if T is invariant char , then typeof(T) == char. typeof() kinda works like a declaration, so it removes the top level const/invariant.

This works for plan data like char (since const(char) really is the same type as char, if I understand it right - there's no 'tail' that could be const), but not for reference types: class T {} const(T) var; writefln(typeid(typeof(var))); produces const T However, I think templates are broken with regard to const, since: class T {} const(T) var; pragma(msg, typeof(var)); errors with consttest.d(14): Error: string expected for message, not 'const T' and template Foo(Q) { pragma(msg, Q); } class T {} const(T) var; Foo!(typeof(var)); errors with consttest.d(7): pragma msg string expected for message, not 'T'
Aug 28 2007
next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Christian Kamm wrote:
 I've been trying to work this out for a few hours now, and I'm drawing a
 blank.  In D 2.0, there doesn't appear to be any way of deriving the
 type of T given either (const T) or (invariant T).

char. typeof() kinda works like a declaration, so it removes the top level const/invariant.

This works for plan data like char (since const(char) really is the same type as char, if I understand it right - there's no 'tail' that could be const), but not for reference types: class T {} const(T) var; writefln(typeid(typeof(var))); produces const T However, I think templates are broken with regard to const, since: class T {} const(T) var; pragma(msg, typeof(var)); errors with consttest.d(14): Error: string expected for message, not 'const T' and template Foo(Q) { pragma(msg, Q); } class T {} const(T) var; Foo!(typeof(var)); errors with consttest.d(7): pragma msg string expected for message, not 'T'

Shouldn't those be typeof(var).stringof and Q.stringof? -- Daniel
Aug 28 2007
parent Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 However, I think templates are broken with regard to const, since:
 
 class T {}
 const(T) var;
 pragma(msg, typeof(var));
 errors with
 consttest.d(14): Error: string expected for message, not 'const T'
 
 and
 
 template Foo(Q) {
   pragma(msg, Q);
 }
 
 class T {}
 const(T) var;
 Foo!(typeof(var));
 errors with
 consttest.d(7): pragma msg string expected for message, not 'T'
 

Shouldn't those be typeof(var).stringof and Q.stringof?

Yes, I simply forgot about the existence of strongof for a moment. With that change you'd get "const T" instead of the first and "T" instead of the second error message. Christian
Aug 28 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Christian Kamm wrote:
 I've been trying to work this out for a few hours now, and I'm drawing a
 blank.  In D 2.0, there doesn't appear to be any way of deriving the
 type of T given either (const T) or (invariant T).

char. typeof() kinda works like a declaration, so it removes the top level const/invariant.

This works for plan data like char (since const(char) really is the same type as char, if I understand it right - there's no 'tail' that could be const), but not for reference types:

I know that, that's what I meant when I said it removes "the top level" const/invariant. Maybe not the best of terminology, it was just something that I had used before. And I haven't read about this new head/tail stuff yet. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 28 2007
parent Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
Bruno Medeiros wrote:
 Use "typeof(T)". For example if T is invariant char , then typeof(T) ==
 char. typeof() kinda works like a declaration, so it removes the top
 level const/invariant.
 



 This works for plan data like char (since const(char) really is the same
 type as char, if I understand it right - there's no 'tail' that could be
 const), but not for reference types:


 I know that, that's what I meant when I said it removes "the top level"
 const/invariant. Maybe not the best of terminology, it was just
 something that I had used before. And I haven't read about this new
 head/tail stuff yet.

Ah, I misunderstood then. Also, I didn't know that stripping of the 'top level' const would only happen in declarations, so Stewart Gordon's solution baffled me at first. Christian
Aug 28 2007
prev sibling parent "Stewart Gordon" <smjg_1998 yahoo.com> writes:
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
news:fb0o30$2fd4$1 digitalmars.com...
 I've been trying to work this out for a few hours now, and I'm drawing a
 blank.  In D 2.0, there doesn't appear to be any way of deriving the
 type of T given either (const T) or (invariant T).

  T[] join(T,U)(in T[][] parts, in U[] sep=null)

 There doesn't appear to be any way to derive a mutable version of T or
 U.

Here's some code that works: ---------- template unconst(T) { pragma(msg, "unconst(" ~ T.stringof ~ ")"); alias unc!(T).u unconst; pragma(msg, "unconst(" ~ T.stringof ~ ") -> " ~ unconst.stringof); } template unc(T) { T dummy; alias typeof(dummy) u; } template unc(T : T[]) { alias unc!(T).u[] u; } alias int[] arrayType1; alias const(int)[] arrayType2; alias invariant(int)[] arrayType3; alias const(int[]) arrayType4; alias const(const(int)[]) arrayType5; alias const(invariant(int)[]) arrayType6; alias invariant(int[]) arrayType7; alias invariant(const(int)[]) arrayType8; alias invariant(invariant(int)[]) arrayType9; unconst!(arrayType1) array1; static assert (is(typeof(array1) == int[])); unconst!(arrayType2) array2; static assert (is(typeof(array2) == int[])); unconst!(arrayType3) array3; static assert (is(typeof(array3) == int[])); unconst!(arrayType4) array4; static assert (is(typeof(array4) == int[])); unconst!(arrayType5) array5; static assert (is(typeof(array5) == int[])); unconst!(arrayType6) array6; static assert (is(typeof(array6) == int[])); unconst!(arrayType7) array7; static assert (is(typeof(array7) == int[])); unconst!(arrayType8) array8; static assert (is(typeof(array8) == int[])); unconst!(arrayType9) array9; static assert (is(typeof(array9) == int[])); ---------- Stewart.
Aug 28 2007