Bug 4427 – __traits should have isFunction, isVariable, etc
Status
RESOLVED
Resolution
WORKSFORME
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-07-04T18:59:00Z
Last change time
2017-07-02T02:49:31Z
Assigned to
nobody
Creator
issues.dlang
Comments
Comment #0 by issues.dlang — 2010-07-04T18:59:56Z
At present, __traits has some nice stuff that will let you check things like whether a function is abstract, or whether something is of an integral type. It will even let you get all of the member functions and variables of a class. However, there is no way at present (as far as I can tell) to determine whether something is a function or a variable. There isn't a way to determine if something is a type either, let alone whether it's a class, struct, array, or scalar type. Most of what's there seems to be to ask about the attributes of a particular expression, variable, or type rather than telling you what it _is_. In particular, I think that we need these __traits:
isArray
isClass
isFunction
isStruct
isType
isVariable
Comment #1 by simen.kjaras — 2010-07-05T07:52:08Z
> isArray
std.traits has isArray
> isClass
This is easily done with is( T == class ).
> isFunction
This is easily done with is( T == function ).
> isStruct
This is easily done with is( T == struct ).
> isType
is( T )?
> isVariable
(!is( T ) && is( typeof( T )))?
Comment #2 by issues.dlang — 2010-07-05T18:12:14Z
Good points, though would == function check when it was a function pointer rather than a function? In either case, I think that you should be able to check these in a consistent manner, which you can't do right now. With things spread out between built-in constructs, __traits, and std.traits, it can be a bit of a mess to figure out how to do something with compile-time reflection. Even if something like isType were simply translated to is(T), I think that having it would still be quite valuable since it would make the various compile-time reflection facilities more consistent and uniform.
Comment #3 by simen.kjaras — 2010-07-06T04:29:56Z
I agree. Many of these could easily be turned into templates in std.traits, and perhaps they should.
template isClass( T ) {
enum isClass = is( T == class );
}
unittest {
interface I {}
class A {}
class B( T ) {}
class C : B!int, I {}
struct S {}
static assert( isClass!A );
static assert( isClass!( B!int ) );
static assert( isClass!C );
static assert( !isClass!I );
static assert( !isClass!S );
static assert( !isClass!int );
static assert( !isClass!( int* ) );
}
template isInterface( T ) {
enum isInterface = is( T == interface );
}
unittest {
interface I {}
class A {}
class B( T ) {}
class C : B!int, I {}
struct S {}
static assert( !isInterface!A );
static assert( !isInterface!( B!int ) );
static assert( !isInterface!C );
static assert( isInterface!I );
static assert( !isInterface!S );
static assert( !isInterface!int );
static assert( !isInterface!( int* ) );
}
template isStruct( T ) {
enum isStruct = is( T == struct );
}
unittest {
interface I {}
class A {}
class B( T ) {}
class C : B!int, I {}
struct S {}
static assert( !isStruct!A );
static assert( !isStruct!( B!int ) );
static assert( !isStruct!C );
static assert( !isStruct!I );
static assert( isStruct!S );
static assert( !isStruct!int );
static assert( !isStruct!( int* ) );
}
template isType( T ) {
enum isType = true;
}
template isType( alias T ) {
enum isType = false;
}
unittest {
struct S {
alias int foo;
}
static assert( isType!int );
static assert( isType!float );
static assert( isType!string );
//static assert( isType!S ); // Bugzilla 4431
static assert( isType!( S.foo ) );
static assert( !isType!4 );
static assert( !isType!"Hello world!" );
}
I'm not entirely sure what you want isVariable to do. Does it check if something can be assigned to (i.e. is variable), or are immutable and const 'variables' also variables?
Comment #4 by issues.dlang — 2010-07-06T10:05:58Z
I would expect that immutable and const variables would still be variables, just not mutable ones. If you wanted to know whether they were const or immutable, you could do a separate test for that on top of checking whether something was a variable, just like you'd do if you wanted to know whether it were static.
Personally, I've been trying to figure out how to get the list of non-static member variables out of a class at compile-time, and it's been a bit of a pain. And for what I'm doing with them, I wouldn't care whether they were immutable or const.
Comment #5 by doob — 2010-07-07T04:02:46Z
(In reply to comment #4)
> I would expect that immutable and const variables would still be variables,
> just not mutable ones. If you wanted to know whether they were const or
> immutable, you could do a separate test for that on top of checking whether
> something was a variable, just like you'd do if you wanted to know whether it
> were static.
>
> Personally, I've been trying to figure out how to get the list of non-static
> member variables out of a class at compile-time, and it's been a bit of a pain.
> And for what I'm doing with them, I wouldn't care whether they were immutable
> or const.
You can use object.tupleof to get a list of member variables of out a class at compile time. You can also have a look at http://www.dsource.org/projects/orange/browser/orange/util/Reflection.d (look for the templates/functions containing "field") to get some ideas to implement helper templates/functions.
Comment #6 by alanb — 2012-11-16T14:07:14Z
(In reply to comment #2)
> Good points, though would == function check when it was a function pointer
> rather than a function? In either case, I think that you should be able to
> check these in a consistent manner, which you can't do right now. With things
> spread out between built-in constructs, __traits, and std.traits, it can be a
> bit of a mess to figure out how to do something with compile-time reflection.
> Even if something like isType were simply translated to is(T), I think that
> having it would still be quite valuable since it would make the various
> compile-time reflection facilities more consistent and uniform.
I wasted an hour on this very issue because it's not obvious in the least how to do something like isStruct() for a template constraint.
I don't mind using is( T == struct ), so long how to do such a thing (and other tests) is documented in an obvious place that someone is going to look at, like in the templates constraint section. That section currently has nothing in it of much help other than showing how to constrain a few basic types.
Comment #7 by issues.dlang — 2012-11-16T15:46:47Z
I had forgotten that I created this enhancement request, though I don't know how valid it is at this point given how powerful is expressions are (though how to fully use them isn't well enough known).
> I wasted an hour on this very issue because it's not obvious in the least how
> to do something like isStruct() for a template constraint.
> I don't mind using is( T == struct ), so long how to do such a thing (and
> other tests) is documented in an obvious place that someone is going to look
> at, like in the templates constraint section. That section currently has
> nothing in it of much help other than showing how to constrain a few basic
> types.
It's explained in the section on is expressions:
http://dlang.org/expression.html#IsExpression
However, that documentation is fairly sparse, and given the extreme flexibility and power (and therefore complication) of is expressions, we could really use a solid tutorial on them on the site. Phillippe Segaud has an extension tutorial on templates in general on github though:
https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/dtemplates.pdf
Comment #8 by alanb — 2012-11-17T08:31:39Z
(In reply to comment #7)
> I had forgotten that I created this enhancement request, though I don't know
> how valid it is at this point given how powerful is expressions are (though how
> to fully use them isn't well enough known).
>
> > I wasted an hour on this very issue because it's not obvious in the least how
> > to do something like isStruct() for a template constraint.
>
> > I don't mind using is( T == struct ), so long how to do such a thing (and
> > other tests) is documented in an obvious place that someone is going to look
> > at, like in the templates constraint section. That section currently has
> > nothing in it of much help other than showing how to constrain a few basic
> > types.
>
> It's explained in the section on is expressions:
>
> http://dlang.org/expression.html#IsExpression
>
> However, that documentation is fairly sparse, and given the extreme flexibility
> and power (and therefore complication) of is expressions, we could really use a
> solid tutorial on them on the site. Phillippe Segaud has an extension tutorial
> on templates in general on github though:
>
> https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/dtemplates.pdf
Thanks for the response! I have no idea how I skipped the section on Expressions, probably because at the time I was too new with D to understand what it was good for. lot's to read up on in there. Looks like it covers everything I can imagine is needed.
Yes it seems that with availability of expressions the enhancement request is somewhat redundant, and like you said, making people aware of it may be what's needed most.
Comment #9 by bugzilla — 2012-11-17T13:40:36Z
> Many of these could easily be turned into templates
The is ==struct and __traits are not really intended to be user-facing. They are intended to be embedded into templates which then can present a simple, straightforward user interface.
Sometimes those templates do need to work hard internally to get the information, but being able to is all that's relevant.
Comment #10 by turkeyman — 2012-11-24T14:49:05Z
(In reply to comment #9)
> > Many of these could easily be turned into templates
>
> The is ==struct and __traits are not really intended to be user-facing. They
> are intended to be embedded into templates which then can present a simple,
> straightforward user interface.
>
> Sometimes those templates do need to work hard internally to get the
> information, but being able to is all that's relevant.
Well with this in mind, perhaps we can complete the suite of std.traits? There are a lot missing. I'd certainly like to clean up that aspect of my code before I depart, as it's the most confusing and unreadable section by far. Particularly for new-comers who haven't taken the time to wrangle those sorts of problems yet (who I will be leaving it to) :/
Comment #11 by andrej.mitrovich — 2013-01-09T14:30:51Z
I've lost track here, what's left to implement that requires the compiler's help by exposing a new __trait?
Comment #12 by turkeyman — 2013-01-12T03:18:49Z
(In reply to comment #11)
> I've lost track here, what's left to implement that requires the compiler's
> help by exposing a new __trait?
I think the __trait's were more or less good now (at least for me personally), and Kenji had a bug/task where he was fleshing out std.traits. I'm not sure where that landed. I copied his example/prototype code locally and used that, not sure if it was ever completed/merged/documented.
Sorry, I've been a major advocate for this stuff, and I'm currently AWOL. Back in 2-3 more weeks and I'll start making noise again ;)
Comment #13 by andrej.mitrovich — 2013-01-12T11:54:22Z
Jonathan can you give us an updated on what's still missing?
Comment #14 by alanb — 2013-03-29T00:06:50Z
(In reply to comment #13)
I would like to see something like isNullable(T) that evaluates to true if the type value can be assigned a null.
Eg,
struct S { ... }
S* s;
class C { ... }
isNullable( S ) is false
isNullable( typeof(s) ) is true
isNullable( C ) is true
--rt
Comment #15 by dlang-bugzilla — 2017-07-02T02:49:31Z