digitalmars.D.learn - How to check if an array is a manifest constant?

• simendsjo (31/31) Apr 03 2011 The behavior for manifest constant arrays is different from regular arra...
• =?UTF-8?B?QWxla3NhbmRhciBSdcW+acSNacSH?= (18/49) Apr 03 2011 As far as I understand, manifest constants and enums only share the
• Jonathan M Davis (12/48) Apr 03 2011 There should be _no_ difference between arrays which are manifest consta...
• bearophile (5/7) Apr 03 2011 I'd like in DMD a way to know if something is a compile-time constant. T...
• Jonathan M Davis (7/15) Apr 03 2011 To what end? Why would you care? It matters whether a value is mutable, ...
• simendsjo (15/15) Apr 04 2011 But there is a difference in how they behave, and I have no way of check...
• Jonathan M Davis (19/37) Apr 04 2011 Okay. I just re-read the appropriate section in TDPL, and it's clear fro...
• simendsjo (22/23) Apr 04 2011 The same reason I'd like to check if it's const/immutable; if an algorit...
• Jonathan M Davis (31/63) Apr 04 2011 Apparently, part of the point of using enums is to have them be replaced...
• Jonathan M Davis (27/32) Apr 03 2011 They're the same and they're not. A named enum creates a new type of sor...
```The behavior for manifest constant arrays is different from regular arrays and
const/immutable
arrays. The problem is that typeof() returns T[]. How can I see if the array is
a manifest
constant?

void g(int[] x) { }

const c = [1,2,3];
static assert(is(typeof(c) == const(int[])));
// cannot convert const(int[]) to int[]
static assert(!__traits(compiles, g(c)));
auto carr = c;
static assert(is(typeof(carr) == const(int[])));
assert(carr.ptr == c.ptr); // referenced

immutable i = [1,2,3];
static assert(is(typeof(i) == immutable(int[])));
// cannot convert immutable(int[]) to int[]
static assert(!__traits(compiles, g(i)));
auto iarr = i;
static assert(is(typeof(iarr) == immutable(int[])));
assert(iarr.ptr == i.ptr); // referenced

enum e = [1,2,3];
// e is reported as int[] even if it's an enum
static assert(is(typeof(e) == int[]));
//static assert(is(typeof(e) == enum)); // not an enum (as expected)
// it can be passed to funtions taking dynamic arrays
void f(int[] x) {
assert(e.ptr != x.ptr); // then the content is copied
}
f(e);
// the behavior is different from other assignments
// as the content is copied
auto earr = e;
assert(earr.ptr != e.ptr); // content is copied
```
Apr 03 2011
```As far as I understand, manifest constants and enums only share the
same keyword (enum) and are completely different things.
Enumerations (like enum A { a,b, c}) define new type, while manifest
constants (like enum N =3D 42;) are just constant values with type
inferred from value (unless specified after enum keyword).

On Sun, Apr 3, 2011 at 5:29 PM, simendsjo <simen.endsjo pandavre.com> wrote=
:
The behavior for manifest constant arrays is different from regular array=

s and const/immutable
arrays. The problem is that typeof() returns T[]. How can I see if the ar=

ray is a manifest
constant?

=C2=A0 =C2=A0 =C2=A0 =C2=A0void g(int[] x) { }

=C2=A0 =C2=A0 =C2=A0 =C2=A0const c =3D [1,2,3];
=C2=A0 =C2=A0 =C2=A0 =C2=A0static assert(is(typeof(c) =3D=3D const(int[])=

));
=C2=A0 =C2=A0 =C2=A0 =C2=A0// cannot convert const(int[]) to int[]
=C2=A0 =C2=A0 =C2=A0 =C2=A0static assert(!__traits(compiles, g(c)));
=C2=A0 =C2=A0 =C2=A0 =C2=A0auto carr =3D c;
=C2=A0 =C2=A0 =C2=A0 =C2=A0static assert(is(typeof(carr) =3D=3D const(int=

[])));
=C2=A0 =C2=A0 =C2=A0 =C2=A0assert(carr.ptr =3D=3D c.ptr); // referenced

=C2=A0 =C2=A0 =C2=A0 =C2=A0immutable i =3D [1,2,3];
=C2=A0 =C2=A0 =C2=A0 =C2=A0static assert(is(typeof(i) =3D=3D immutable(in=

t[])));
=C2=A0 =C2=A0 =C2=A0 =C2=A0// cannot convert immutable(int[]) to int[]
=C2=A0 =C2=A0 =C2=A0 =C2=A0static assert(!__traits(compiles, g(i)));
=C2=A0 =C2=A0 =C2=A0 =C2=A0auto iarr =3D i;
=C2=A0 =C2=A0 =C2=A0 =C2=A0static assert(is(typeof(iarr) =3D=3D immutable=

(int[])));
=C2=A0 =C2=A0 =C2=A0 =C2=A0assert(iarr.ptr =3D=3D i.ptr); // referenced

=C2=A0 =C2=A0 =C2=A0 =C2=A0enum e =3D [1,2,3];
=C2=A0 =C2=A0 =C2=A0 =C2=A0// e is reported as int[] even if it's an enum
=C2=A0 =C2=A0 =C2=A0 =C2=A0static assert(is(typeof(e) =3D=3D int[]));
=C2=A0 =C2=A0 =C2=A0 =C2=A0//static assert(is(typeof(e) =3D=3D enum)); //=

not an enum (as expected)
=C2=A0 =C2=A0 =C2=A0 =C2=A0// it can be passed to funtions taking dynamic=

arrays
=C2=A0 =C2=A0 =C2=A0 =C2=A0void f(int[] x) {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0assert(e.ptr !=3D =

x.ptr); // then the content is copied
=C2=A0 =C2=A0 =C2=A0 =C2=A0}
=C2=A0 =C2=A0 =C2=A0 =C2=A0f(e);
=C2=A0 =C2=A0 =C2=A0 =C2=A0// the behavior is different from other assign=

ments
=C2=A0 =C2=A0 =C2=A0 =C2=A0// as the content is copied
=C2=A0 =C2=A0 =C2=A0 =C2=A0auto earr =3D e;
=C2=A0 =C2=A0 =C2=A0 =C2=A0assert(earr.ptr !=3D e.ptr); // content is cop=

ied

```
Apr 03 2011
```On 2011-04-03 08:29, simendsjo wrote:
The behavior for manifest constant arrays is different from regular arrays
and const/immutable arrays. The problem is that typeof() returns T[]. How
can I see if the array is a manifest constant?

void g(int[] x) { }

const c = [1,2,3];
static assert(is(typeof(c) == const(int[])));
// cannot convert const(int[]) to int[]
static assert(!__traits(compiles, g(c)));
auto carr = c;
static assert(is(typeof(carr) == const(int[])));
assert(carr.ptr == c.ptr); // referenced

immutable i = [1,2,3];
static assert(is(typeof(i) == immutable(int[])));
// cannot convert immutable(int[]) to int[]
static assert(!__traits(compiles, g(i)));
auto iarr = i;
static assert(is(typeof(iarr) == immutable(int[])));
assert(iarr.ptr == i.ptr); // referenced

enum e = [1,2,3];
// e is reported as int[] even if it's an enum
static assert(is(typeof(e) == int[]));
//static assert(is(typeof(e) == enum)); // not an enum (as expected)
// it can be passed to funtions taking dynamic arrays
void f(int[] x) {
assert(e.ptr != x.ptr); // then the content is copied
}
f(e);
// the behavior is different from other assignments
// as the content is copied
auto earr = e;
assert(earr.ptr != e.ptr); // content is copied

There should be _no_ difference between arrays which are manifest constants
and regular arrays which are immutable except that they're computed at compile
time. However, there is currently a bug in CTFE which makes it so that an
array is copied _every_ time that it is accessed in CTFE (which, among other
things, causes a massive memory leak). I don't remember what the bug report is
for it, but Don is currently overhauling CTFE so that this won't be the case
anymore. So, this _should_ be fixed by the next release.

But there should be no need to worry about whether something is a manifest
constant or not. If there is, you're either doing something funny/wrong, or
it's because of a bug like the one that Don is fixing.

- Jonathan M Davis
```
Apr 03 2011
```Jonathan M Davis:

But there should be no need to worry about whether something is a manifest
constant or not.

I'd like in DMD a way to know if something is a compile-time constant. There is
a GCC extension that sometimes is able to do it, named __builtin_constant_p:
http://www.delorie.com/gnu/docs/gcc/gcc_81.html#IDX629

Bye,
bearophile
```
Apr 03 2011
```On 2011-04-03 17:25, bearophile wrote:
Jonathan M Davis:
But there should be no need to worry about whether something is a
manifest constant or not.

I'd like in DMD a way to know if something is a compile-time constant.
There is a GCC extension that sometimes is able to do it, named
__builtin_constant_p:
http://www.delorie.com/gnu/docs/gcc/gcc_81.html#IDX629

To what end? Why would you care? It matters whether a value is mutable, const,
or immutable, but what does it matter if it was calculated at compile time or
not? Unless it's a property, it's definitely going to have been calculated
before you use it. The only reason that I see that it matters at the moment is
due to bugs in dmd. Once those are fixed, it should be irrelevant.

- Jonathan M Davis
```
Apr 03 2011
```But there is a difference in how they behave, and I have no way of checking
this behavior.
Consider the following little snippet:

void f(int[] a) {
a = -1;
}

void main() {
int[] a = [1,2,3];
static assert(is(typeof(a) == int[]));
f(a);
assert(a == -1); // a passed by reference, a changed

enum b = [1,2,3];
static assert(is(typeof(b) == int[])); // a regular int[] you say?
f(b);
assert(b == -1); // b passed by value, b unchanged
}
```
Apr 04 2011
```On 2011-04-04 01:16, simendsjo wrote:
But there is a difference in how they behave, and I have no way of checking
this behavior. Consider the following little snippet:

void f(int[] a) {
a = -1;
}

void main() {
int[] a = [1,2,3];
static assert(is(typeof(a) == int[]));
f(a);
assert(a == -1); // a passed by reference, a changed

enum b = [1,2,3];
static assert(is(typeof(b) == int[])); // a regular int[] you say?
f(b);
assert(b == -1); // b passed by value, b unchanged
}

Okay. I just re-read the appropriate section in TDPL, and it's clear from the
book that it's definitely intended that a new copy of the enum value be
created every time that it's used (I was under the impression that that was
buggy behavior, but apparently that's not true - though the fact that
accessing any array during CTFE results in a copy of that array _is_ buggy
behavior and should be fixed by Don before the next release).

Regardless of that, however, enum values shouldn't be used in any place where
they're going to be altered. So, passing such a value to a function which is
intended to alter the value that it's passed to is just plain a bug on the
part of the caller. It shouldn't matter to the function being called.

That being the case, I don't see why you would need to determine whether a
value that you're dealing with is an enum or not using template constraints or
static if or whatnot. You should know whether the variable that you're using
is an enum or not. If it is, don't alter it until you've set it to a variable
- then you alter the variable.

What use case do you have for wanting to know whether a variable is an enum or
not?

- Jonathan M Davis
```
Apr 04 2011
``` What use case do you have for wanting to know whether a variable is an enum or
not?

The same reason I'd like to check if it's const/immutable; if an algorithm
requires a
modifiable array.

void sortInPlace(int[] array) {
array.sort;
}

void main() {
int[] a = [3,2,1];
sortInPlace(a);
assert(a == [1,2,3]);

auto i = [3,2,1].idup;
//sortInPlace(i); // Fails at compile time

enum e = [3,2,1];
sortInPlace(e);
assert(e == [1,2,3]); // fails at runtime
}

I can check the type for const or immutable with template constraits or static
if's, but I
cannot check for enum.
I can use ref int[] as a parameter to get a compile time error, but that's
often don't want to reassign the parameter.

Cannot the type of enum e =  be immutable(int[])? Or is that wrong?
Or am I missing something crucial because of CTFE or other stuff? I've just
started looking
into D2, so theres a good possibility my reasoning is wrong.
```
Apr 04 2011
```On 2011-04-04 03:11, simendsjo wrote:
What use case do you have for wanting to know whether a variable is an
enum or not?

The same reason I'd like to check if it's const/immutable; if an algorithm
requires a modifiable array.

void sortInPlace(int[] array) {
array.sort;
}

void main() {
int[] a = [3,2,1];
sortInPlace(a);
assert(a == [1,2,3]);

auto i = [3,2,1].idup;
//sortInPlace(i); // Fails at compile time

enum e = [3,2,1];
sortInPlace(e);
assert(e == [1,2,3]); // fails at runtime
}

I can check the type for const or immutable with template constraits or
static if's, but I cannot check for enum.
I can use ref int[] as a parameter to get a compile time error, but that's
misleading as I often don't want to reassign the parameter.

Cannot the type of enum e =  be immutable(int[])? Or is that wrong?
Or am I missing something crucial because of CTFE or other stuff? I've just
started looking into D2, so theres a good possibility my reasoning is
wrong.

Apparently, part of the point of using enums is to have them be replaced with
the value without having any kind of address. So, they're _supposed_ to be a
copy and therefore don't have to be const or immutable.

Generally, it should be clear whether a function alters its arguments or not.
You can't use const or immutable arrays with a function which alters its array
argument or the elements of its array argument, because the array itself can't
be altered. In the case of enums, it _can_ be altered, because when you use
it, you get a copy. It literally copies and pastes the value of the enum where
you use it. So, there's _nothing_ wrong with passing an enum which is an array
to a function which alters the elements of its array argument. It's perfectly
legal. It's just generally a bad idea, since it's a temporary.

There's no need to check whether a function's argument is an enum anymore than
there's a need to check whether the argument is a temporary. Both are
perfectly legal, just generally pointless. If a slice of the array is returned
or saved in a global variable or whatnot, then it's not pointless. But if it's
just altering the function's argument, then it is. But the function doesn't
need to worry about it. It's still perfectly legal. It's up to the caller to
actually pass an array that's worth altering. And since the function should be
clear on whether it alters its arguments, it shouldn't be a problem that it's
up to the caller to use it correctly with regards to temporaries and enums -
just like it's up to the caller not to be stupid and pass any other array that
it doesn't actually want to alter.

So, really there's no reason to stop an enum from working with a function that
alters the elements of an array. All temporaries have the same issue. If you
really want to prevent it, then just make the argument a ref. It also makes it
clear that you're altering the array. If you don't want to make it a ref, then
just make the documentation clear, and it's up to the caller to use the
function appropriately. For instance, it should be obvious to the caller that
passing an enum to a function like sortInPlace would be just stupid.

- Jonathan M Davis
```
Apr 04 2011    Jonathan M Davis <jmdavisProg gmx.com> writes:
```On 2011-04-03 11:03, Aleksandar Ru=C5=BEi=C4=8Di=C4=87 wrote:
As far as I understand, manifest constants and enums only share the
same keyword (enum) and are completely different things.
Enumerations (like enum A { a,b, c}) define new type, while manifest
constants (like enum N =3D 42;) are just constant values with type
inferred from value (unless specified after enum keyword).

They're the same and they're not. A named enum creates a new type of sorts =
and=20
namespaces the values in it, whereas a manifest constant does not create a =
new=20
type and its values (be it one or many) go directly in the namespace that i=
t's=20
declared in. But even a named enum doesn't exactly create a new type. It's=
=20
really its base type everywhere it's used, but extra restrictions are put o=
n=20
it to help ensure that only valid values are used with it. For example, wit=
h=20
std.datetime.Month, you either have to use Month.jan, Month.feb, etc. or ca=
st=20
an integral value to a Month - e.g. cast(Month)12. However, it's still only=
a=20
ubyte when it's compiled in, because Month is an enum of the type ubyte.

So, manifest constants and named enums are not quite the same thing, but=20
they're not drastically differente either. Their values act essentially the=
=20
same way. They're just referenced differently, and you can refer to the nam=
e=20
of a named enum, using it as a type, whereas there is no name for a manifes=
t=20
constant. Their values are pretty much identical when they're used though.

=2D Jonathan M Davis
```
Apr 03 2011