Thread overview
Stripping away const/invariant in D 2.0
Aug 28, 2007
Daniel Keep
Aug 28, 2007
Bruno Medeiros
Aug 28, 2007
Daniel Keep
Aug 28, 2007
Christian Kamm
Aug 28, 2007
Daniel Keep
Aug 28, 2007
Christian Kamm
Aug 28, 2007
Bruno Medeiros
Aug 29, 2007
Christian Kamm
Aug 28, 2007
Stewart Gordon
August 28, 2007
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
August 28, 2007
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
August 28, 2007

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
August 28, 2007
>> 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'

August 28, 2007

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).
>> 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'
> 

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

	-- Daniel
August 28, 2007
>> 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
August 28, 2007
"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).
<snip>
>  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. 

August 28, 2007
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).
>> 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.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
August 29, 2007
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.
>>> 
Christian Kamm wrote:
>> 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:
>>
Bruno Medeiros wrote:
> 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