D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 20316 - array properties fail hasMember
Summary: array properties fail hasMember
Status: RESOLVED WONTFIX
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P1 regression
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-10-24 16:39 UTC by John Colvin
Modified: 2019-12-12 10:20 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description John Colvin 2019-10-24 16:39:01 UTC
pragma(msg, __traits(hasMember, int[], "length"));   // false
pragma(msg, __traits(hasMember, int[], "ptr"));      // false
pragma(msg, __traits(hasMember, int[], "capacity")); // false
pragma(msg, __traits(hasMember, int[], "sizeof"));   // true
pragma(msg, __traits(hasMember, int[], "alignof"));  // true
Comment 1 John Colvin 2019-10-24 17:40:25 UTC
This is a regression introduced in 2.065, before which .length and .ptr were found. AFAICT .capacity never worked
Comment 2 RazvanN 2019-10-30 09:30:19 UTC
The problem here is that (int[]).length is not a valid D construction:

static assert(__traits(compiles, (int[]).length));

will fail, therefore traits(hasMember) returns false.

length, ptr and capacity were thought to work solely on expressions, not on types (it doesn't make sense to get the pointer of a type) so I'm a bit confused of what the compiler should do here.

sizeof and alignof work because there are type properties.
Comment 3 RazvanN 2019-10-30 09:31:49 UTC
Note that if a variable is declared:

int[] a;

traits(hasMember) on a works properly.
Comment 4 RazvanN 2019-10-30 09:54:20 UTC
As for capacity, it is not listed on the list of properties for arrays and it is implemented as a druntime function. I guess this bug report opens the philosophical question of what hasMember actually means. For example, sizeof is not actually a member of any type, it is a property that may be queried; that property may be implemented as a function directly in the compiler or it may be a function in druntime or it may be an actual member of the int class; this all depends on how it was actually implemented, which is not something that the user cares.

In my opinion, hasMember should only work on aggregates, because there we are talking about actual scope declarations that have members. builtin types should all return false on hasMember queries because builtin types don't have any members, rather they have properties. If you want to see what properties a type has you can simply use traits(compiles).
Comment 5 Walter Bright 2019-12-12 10:17:15 UTC
I agree that hasMember should only work on aggregates. UFCS functions that syntactically look like members are still not members.
Comment 6 Walter Bright 2019-12-12 10:20:40 UTC
> traits(hasMember) on a works properly.

Meaning:

int[] array;
pragma(msg, __traits(hasMember, array, "length"));   // true
pragma(msg, __traits(hasMember, array, "ptr"));      // true
pragma(msg, __traits(hasMember, array, "capacity")); // true
pragma(msg, __traits(hasMember, array, "sizeof"));   // true
pragma(msg, __traits(hasMember, array, "alignof"));  // true

Gaahhh. It's probably far too late to change this behavior now.

Marking as WONTFIX.