View mode: basic / threaded / horizontal-split · Log in · Help
November 24, 2008
Unification and extension of compile-time reflection
Once upon a time, D did not have string mixins, or CTFE, or templates,
or any of the fun things we have today.  Even so, it was still
important to be able to access some information about types.  So
Walter made it possible to query some basic information - the
initialization value, minimum and maximum allowable values, byte size
and alignment etc. - directly from the types as properties.  Neat.

Then D got templates.  D's templates were based on C++'s, to an
extent, and therefore made use of specialization (and by corollary,
SFINAE) to determine which template to instantiate.  By their nature,
templates are a sort of way of introspecting types.  So now D has two
ways to find out things about types.  Okay.

It turned out that templates were not always powerful enough - or
sufficiently concise - to express some ideas.  So Walter came up with
the is() expression (originally the "iftype" statement which begat
"is()" and "static if") to query other, more interesting information
about types.  It's _kind of_ like template specialization but has some
extra features that specialization doesn't.  Now D has three ways to
find out things about types.  Hm.

Along comes D2, and with it, the __traits keyword.  __traits is
wonderful (except for the double-underscore name, anyway).  It's
extensible, flexible, and can answer queries about types and other
program objects in a way that would be extremely convoluted or cryptic
if templates or the is() expression were extended.

But now D programs have _four_ ways to ask questions about themselves.

Some of these methods overlap but with wildly different syntax.  Many
questions have to be composed out of these four disparate methods in
unintuitive manners.  Walter's "Templates Revisited" article says that
"[m]any useful aspects of C++ templates have been discovered rather
than designed," but in all honesty, this is exactly the situation with
D's compile-time introspection.  D's templates are better, yes, but
the problem has simply been promoted to a wider scope.

So what can we do?  I've been thinking about it and I think that
__traits, coupled with the new template constraints, can handle just
about everything.  Does that mean we ditch all the other syntax?  Not
necessarily - it's just that __traits can be the _backend_ for many
other features.

First of all __traits' name has to be revised.  The double-underscore
just isn't working for me.  I think it would be a fair tradeoff to
rename it "traits" and rename the std.traits and core.traits modules
something else.  Come on Walter, I know that adding keywords is
undesirable, but ffs, at some point _not_ adding keywords is just as
bad.  D does not have a very large user or codebase, and if you're
going to break backwards compatibility - _break it now_, before it's
too late.  (besides, some of the keyword mass will need to be
redistributed when imaginary/complex types are removed ;) )

Secondly - the type properties are cute but they're not very flexible.
They can interfere with fields and methods, and so the compiler has
to explicitly check that aggregate member names don't step on the
built-in property names.  I think that "T.prop" could just be replaced
with "traits(prop, T)".  traits(min, int), and so on.  Yes, it's
longer - but that's what templates are for, if you really want it
shorter: Min!(int).

Third, the is() expression is greatly overstepping its bounds now that
traits is around.  Why is there "is(T == class)", but
__traits(isAssociativeArray, T)?  The is(T) form can be replaced by
__traits(compiles).  The is(T : U) form can be replaced by
traits(convertible).  The is(T == U) forms can all be replaced by
traits(equivalent) and traits(isClass) and the like.  The strange is(T
U), is(T U : V), is(T U == V) forms.. I'm not sure what to do about
those.  The ones like is(T U == return) are an obvious abuse and
should be replaced with traits(returnType) or the like.

The fourth and final issue is template specialization.  This one
really does have too much inertia to remove.  So what I propose for
this is that is() -- now that it has the ability to perform just about
everything that template specialization can -- should become the
backend for template specializations.  That is, something like:

template Foo(T, U : V[K], K, V)
{
...
}

is just a shorter way of writing something like:

template Foo(T, U) if(is(U : V[K]))
{
...
}

I don't think template constraints currently introduce symbols into
the template body, but this would declare V and K as types within the
body of Foo.

But here's the kicker: even is() is not an entirely basic construct.
It's more or less a shortcut for more complex traits expressions
combined with the ability to alias traits to symbols.  That is, "is(U
: V[K])" is like the pseudocode "traits(isAssociativeArray, U) &&
alias traits(itemType, U) V && alias traits(indexType, U) K".  Of
course you can't put aliases in expressions, but the overall idea is
that this is() expression is the same as using isAssociativeArray and
then aliasing other traits as K and V.

Why do this?  Simplicity, generality, and consistency.  Once all this
is done, it becomes easy to see what questions can and can't be asked
about your code.  You only have to look in one place: traits.
Everything else is defined in terms of it.

...

So what do you think?
November 24, 2008
Re: Unification and extension of compile-time reflection
Reply to Jarrett,

> The strange is(T U), is(T U : V), is(T U == V) forms.. I'm not sure
> what to do about those.
> 

#2 & 3 are to allow compact type pattern matching. IIRC there not that good 
at it, but are better than nothing.

It's more or less what you bring up in you last point.

Any solution here should include the ability to ask "does type T match pattern 
P if the symbols A B and C (that are part of P) are defined correctly? If 
so, declared A, B and C as needed". You sort of hint at that ability near 
the end, but it needs to be explicit in the design goals.
November 25, 2008
Re: Unification and extension of compile-time reflection
On Mon, Nov 24, 2008 at 6:55 PM, BCS <ao@pathlink.com> wrote:
> Reply to Jarrett,
>
>> The strange is(T U), is(T U : V), is(T U == V) forms.. I'm not sure
>> what to do about those.
>>
>
> #2 & 3 are to allow compact type pattern matching. IIRC there not that good
> at it, but are better than nothing.
>
> It's more or less what you bring up in you last point.
>
> Any solution here should include the ability to ask "does type T match
> pattern P if the symbols A B and C (that are part of P) are defined
> correctly? If so, declared A, B and C as needed". You sort of hint at that
> ability near the end, but it needs to be explicit in the design goals.

OK, explicitly then: those forms remain.  ;)
November 25, 2008
Re: Unification and extension of compile-time reflection
Reply to Jarrett,

> ;)
> 

:b
November 25, 2008
Re: Unification and extension of compile-time reflection
Jarrett Billingsley escribió:
> Once upon a time, D did not have string mixins, or CTFE, or templates,
> or any of the fun things we have today.  Even so, it was still
> important to be able to access some information about types.  So
> Walter made it possible to query some basic information - the
> initialization value, minimum and maximum allowable values, byte size
> and alignment etc. - directly from the types as properties.  Neat.
> 
> Then D got templates.  D's templates were based on C++'s, to an
> extent, and therefore made use of specialization (and by corollary,
> SFINAE) to determine which template to instantiate.  By their nature,
> templates are a sort of way of introspecting types.  So now D has two
> ways to find out things about types.  Okay.
> 
> It turned out that templates were not always powerful enough - or
> sufficiently concise - to express some ideas.  So Walter came up with
> the is() expression (originally the "iftype" statement which begat
> "is()" and "static if") to query other, more interesting information
> about types.  It's _kind of_ like template specialization but has some
> extra features that specialization doesn't.  Now D has three ways to
> find out things about types.  Hm.
> 
> Along comes D2, and with it, the __traits keyword.  __traits is
> wonderful (except for the double-underscore name, anyway).  It's
> extensible, flexible, and can answer queries about types and other
> program objects in a way that would be extremely convoluted or cryptic
> if templates or the is() expression were extended.
> 
> But now D programs have _four_ ways to ask questions about themselves.
> 
> Some of these methods overlap but with wildly different syntax.  Many
> questions have to be composed out of these four disparate methods in
> unintuitive manners.  Walter's "Templates Revisited" article says that
> "[m]any useful aspects of C++ templates have been discovered rather
> than designed," but in all honesty, this is exactly the situation with
> D's compile-time introspection.  D's templates are better, yes, but
> the problem has simply been promoted to a wider scope.
> 
> So what can we do?  I've been thinking about it and I think that
> __traits, coupled with the new template constraints, can handle just
> about everything.  Does that mean we ditch all the other syntax?  Not
> necessarily - it's just that __traits can be the _backend_ for many
> other features.
> 
> First of all __traits' name has to be revised.  The double-underscore
> just isn't working for me.  I think it would be a fair tradeoff to
> rename it "traits" and rename the std.traits and core.traits modules
> something else.  Come on Walter, I know that adding keywords is
> undesirable, but ffs, at some point _not_ adding keywords is just as
> bad.  D does not have a very large user or codebase, and if you're
> going to break backwards compatibility - _break it now_, before it's
> too late.  (besides, some of the keyword mass will need to be
> redistributed when imaginary/complex types are removed ;) )
> 
> Secondly - the type properties are cute but they're not very flexible.
>  They can interfere with fields and methods, and so the compiler has
> to explicitly check that aggregate member names don't step on the
> built-in property names.  I think that "T.prop" could just be replaced
> with "traits(prop, T)".  traits(min, int), and so on.  Yes, it's
> longer - but that's what templates are for, if you really want it
> shorter: Min!(int).
> 
> Third, the is() expression is greatly overstepping its bounds now that
> traits is around.  Why is there "is(T == class)", but
> __traits(isAssociativeArray, T)?  The is(T) form can be replaced by
> __traits(compiles).  The is(T : U) form can be replaced by
> traits(convertible).  The is(T == U) forms can all be replaced by
> traits(equivalent) and traits(isClass) and the like.  The strange is(T
> U), is(T U : V), is(T U == V) forms.. I'm not sure what to do about
> those.  The ones like is(T U == return) are an obvious abuse and
> should be replaced with traits(returnType) or the like.
> 
> The fourth and final issue is template specialization.  This one
> really does have too much inertia to remove.  So what I propose for
> this is that is() -- now that it has the ability to perform just about
> everything that template specialization can -- should become the
> backend for template specializations.  That is, something like:
> 
> template Foo(T, U : V[K], K, V)
> {
> ...
> }
> 
> is just a shorter way of writing something like:
> 
> template Foo(T, U) if(is(U : V[K]))
> {
> ...
> }
> 
> I don't think template constraints currently introduce symbols into
> the template body, but this would declare V and K as types within the
> body of Foo.
> 
> But here's the kicker: even is() is not an entirely basic construct.
> It's more or less a shortcut for more complex traits expressions
> combined with the ability to alias traits to symbols.  That is, "is(U
> : V[K])" is like the pseudocode "traits(isAssociativeArray, U) &&
> alias traits(itemType, U) V && alias traits(indexType, U) K".  Of
> course you can't put aliases in expressions, but the overall idea is
> that this is() expression is the same as using isAssociativeArray and
> then aliasing other traits as K and V.
> 
> Why do this?  Simplicity, generality, and consistency.  Once all this
> is done, it becomes easy to see what questions can and can't be asked
> about your code.  You only have to look in one place: traits.
> Everything else is defined in terms of it.
> 
> ...
> 
> So what do you think?

I liked the way you wrote this. :-)

I think neither __traits nor a property is good enough for compile-time 
reflection. I think just one property is enough.

For example in Java you do:

someInstance.getClass()

and then you enter "the reflection world", which uses the same language 
as Java, but it's at a different level.

So:

var.reflect

or something like that would be awesome. Then you can do:

- something.reflect.methods
- something.reflect.isVirtual
- something.reflect.isAbstract
- something.reflect() // same as something.reflect.compileTimeValue
- something.reflect.fields
- etc.

So you just don't allow "reflect" (or whatever) as a field name (if you 
define it, it's an error, much like "sizeof"), but once you enter 
"reflect" the compiler can add as many name as it wants, nobody can 
override these. "reflect" is smart so that for an expression, it return 
a specific (compile-time) type; for classes, another (compile-time) 
type; for variables, another (compile-time) type; etc.
November 25, 2008
Re: Unification and extension of compile-time reflection
On Tue, Nov 25, 2008 at 11:48 AM, Ary Borenszweig <ary@esperanto.org.ar> wrote:
> Jarrett Billingsley escribió:
>>
>> Once upon a time, D did not have string mixins, or CTFE, or templates,
>> or any of the fun things we have today.  Even so, it was still
>> important to be able to access some information about types.  So
>> Walter made it possible to query some basic information - the
>> initialization value, minimum and maximum allowable values, byte size
>> and alignment etc. - directly from the types as properties.  Neat.
>>
>> Then D got templates.  D's templates were based on C++'s, to an
>> extent, and therefore made use of specialization (and by corollary,
>> SFINAE) to determine which template to instantiate.  By their nature,
>> templates are a sort of way of introspecting types.  So now D has two
>> ways to find out things about types.  Okay.
>>
>> It turned out that templates were not always powerful enough - or
>> sufficiently concise - to express some ideas.  So Walter came up with
>> the is() expression (originally the "iftype" statement which begat
>> "is()" and "static if") to query other, more interesting information
>> about types.  It's _kind of_ like template specialization but has some
>> extra features that specialization doesn't.  Now D has three ways to
>> find out things about types.  Hm.
>>
>> Along comes D2, and with it, the __traits keyword.  __traits is
>> wonderful (except for the double-underscore name, anyway).  It's
>> extensible, flexible, and can answer queries about types and other
>> program objects in a way that would be extremely convoluted or cryptic
>> if templates or the is() expression were extended.
>>
>> But now D programs have _four_ ways to ask questions about themselves.
>>
>> Some of these methods overlap but with wildly different syntax.  Many
>> questions have to be composed out of these four disparate methods in
>> unintuitive manners.  Walter's "Templates Revisited" article says that
>> "[m]any useful aspects of C++ templates have been discovered rather
>> than designed," but in all honesty, this is exactly the situation with
>> D's compile-time introspection.  D's templates are better, yes, but
>> the problem has simply been promoted to a wider scope.
>>
>> So what can we do?  I've been thinking about it and I think that
>> __traits, coupled with the new template constraints, can handle just
>> about everything.  Does that mean we ditch all the other syntax?  Not
>> necessarily - it's just that __traits can be the _backend_ for many
>> other features.
>>
>> First of all __traits' name has to be revised.  The double-underscore
>> just isn't working for me.  I think it would be a fair tradeoff to
>> rename it "traits" and rename the std.traits and core.traits modules
>> something else.  Come on Walter, I know that adding keywords is
>> undesirable, but ffs, at some point _not_ adding keywords is just as
>> bad.  D does not have a very large user or codebase, and if you're
>> going to break backwards compatibility - _break it now_, before it's
>> too late.  (besides, some of the keyword mass will need to be
>> redistributed when imaginary/complex types are removed ;) )
>>
>> Secondly - the type properties are cute but they're not very flexible.
>>  They can interfere with fields and methods, and so the compiler has
>> to explicitly check that aggregate member names don't step on the
>> built-in property names.  I think that "T.prop" could just be replaced
>> with "traits(prop, T)".  traits(min, int), and so on.  Yes, it's
>> longer - but that's what templates are for, if you really want it
>> shorter: Min!(int).
>>
>> Third, the is() expression is greatly overstepping its bounds now that
>> traits is around.  Why is there "is(T == class)", but
>> __traits(isAssociativeArray, T)?  The is(T) form can be replaced by
>> __traits(compiles).  The is(T : U) form can be replaced by
>> traits(convertible).  The is(T == U) forms can all be replaced by
>> traits(equivalent) and traits(isClass) and the like.  The strange is(T
>> U), is(T U : V), is(T U == V) forms.. I'm not sure what to do about
>> those.  The ones like is(T U == return) are an obvious abuse and
>> should be replaced with traits(returnType) or the like.
>>
>> The fourth and final issue is template specialization.  This one
>> really does have too much inertia to remove.  So what I propose for
>> this is that is() -- now that it has the ability to perform just about
>> everything that template specialization can -- should become the
>> backend for template specializations.  That is, something like:
>>
>> template Foo(T, U : V[K], K, V)
>> {
>> ...
>> }
>>
>> is just a shorter way of writing something like:
>>
>> template Foo(T, U) if(is(U : V[K]))
>> {
>> ...
>> }
>>
>> I don't think template constraints currently introduce symbols into
>> the template body, but this would declare V and K as types within the
>> body of Foo.
>>
>> But here's the kicker: even is() is not an entirely basic construct.
>> It's more or less a shortcut for more complex traits expressions
>> combined with the ability to alias traits to symbols.  That is, "is(U
>> : V[K])" is like the pseudocode "traits(isAssociativeArray, U) &&
>> alias traits(itemType, U) V && alias traits(indexType, U) K".  Of
>> course you can't put aliases in expressions, but the overall idea is
>> that this is() expression is the same as using isAssociativeArray and
>> then aliasing other traits as K and V.
>>
>> Why do this?  Simplicity, generality, and consistency.  Once all this
>> is done, it becomes easy to see what questions can and can't be asked
>> about your code.  You only have to look in one place: traits.
>> Everything else is defined in terms of it.
>>
>> ...
>>
>> So what do you think?
>
> I liked the way you wrote this. :-)
>
> I think neither __traits nor a property is good enough for compile-time
> reflection. I think just one property is enough.
>
> For example in Java you do:
>
> someInstance.getClass()
>
> and then you enter "the reflection world", which uses the same language as
> Java, but it's at a different level.
>
> So:
>
> var.reflect
>
> or something like that would be awesome. Then you can do:
>
> - something.reflect.methods
> - something.reflect.isVirtual
> - something.reflect.isAbstract
> - something.reflect() // same as something.reflect.compileTimeValue
> - something.reflect.fields
> - etc.
>
> So you just don't allow "reflect" (or whatever) as a field name (if you
> define it, it's an error, much like "sizeof"), but once you enter "reflect"
> the compiler can add as many name as it wants, nobody can override these.
> "reflect" is smart so that for an expression, it return a specific
> (compile-time) type; for classes, another (compile-time) type; for
> variables, another (compile-time) type; etc.

Or you could just call it traits.

something.traits.methods
something.traits.max
something.traits.sizeof
(1+34.).traits.typeof

I do like the general idea of unifying this stuff.  Can you make an
alias or variable of this .traits/.reflect type?  Can it return a
metaclass type of some sort so that an alias would be possible?  I.e.
alias t = something.traits;

--bb
November 25, 2008
Re: Unification and extension of compile-time reflection
Jarrett Billingsley wrote:
> Once upon a time, D did not have string mixins, or CTFE, or templates,
> or any of the fun things we have today.  Even so, it was still
> important to be able to access some information about types.  So
> Walter made it possible to query some basic information - the
> initialization value, minimum and maximum allowable values, byte size
> and alignment etc. - directly from the types as properties.  Neat.
> 
> Then D got templates.  D's templates were based on C++'s, to an
> extent, and therefore made use of specialization (and by corollary,
> SFINAE) to determine which template to instantiate.  By their nature,
> templates are a sort of way of introspecting types.  So now D has two
> ways to find out things about types.  Okay.
> 
> It turned out that templates were not always powerful enough - or
> sufficiently concise - to express some ideas.  So Walter came up with
> the is() expression (originally the "iftype" statement which begat
> "is()" and "static if") to query other, more interesting information
> about types.  It's _kind of_ like template specialization but has some
> extra features that specialization doesn't.  Now D has three ways to
> find out things about types.  Hm.
> 
> Along comes D2, and with it, the __traits keyword.  __traits is
> wonderful (except for the double-underscore name, anyway).  It's
> extensible, flexible, and can answer queries about types and other
> program objects in a way that would be extremely convoluted or cryptic
> if templates or the is() expression were extended.
> 
> But now D programs have _four_ ways to ask questions about themselves.

> Some of these methods overlap but with wildly different syntax.

You left out typeof/typeinfo/typeid. There's run-time typeinfo, as well 
as compile-time. This is just begging for unification. Consider that in 
a CTFE function, you only use run-time syntax, but it's actually 
occuring at compile time.
And since Object now contains a factory method, there's considerable 
potential for deep unification.
November 25, 2008
Re: Unification and extension of compile-time reflection
Jarrett Billingsley pisze:
> Once upon a time, D did not have string mixins, or CTFE, or templates,
> or any of the fun things we have today.  Even so, it was still
> important to be able to access some information about types.  So
> Walter made it possible to query some basic information - the
> initialization value, minimum and maximum allowable values, byte size
> and alignment etc. - directly from the types as properties.  Neat.
> 
> Then D got templates.  D's templates were based on C++'s, to an
> extent, and therefore made use of specialization (and by corollary,
> SFINAE) to determine which template to instantiate.  By their nature,
> templates are a sort of way of introspecting types.  So now D has two
> ways to find out things about types.  Okay.
> 
> It turned out that templates were not always powerful enough - or
> sufficiently concise - to express some ideas.  So Walter came up with
> the is() expression (originally the "iftype" statement which begat
> "is()" and "static if") to query other, more interesting information
> about types.  It's _kind of_ like template specialization but has some
> extra features that specialization doesn't.  Now D has three ways to
> find out things about types.  Hm.
> 
> Along comes D2, and with it, the __traits keyword.  __traits is
> wonderful (except for the double-underscore name, anyway).  It's
> extensible, flexible, and can answer queries about types and other
> program objects in a way that would be extremely convoluted or cryptic
> if templates or the is() expression were extended.
> 
> But now D programs have _four_ ways to ask questions about themselves.
> 
> Some of these methods overlap but with wildly different syntax.  Many
> questions have to be composed out of these four disparate methods in
> unintuitive manners.  Walter's "Templates Revisited" article says that
> "[m]any useful aspects of C++ templates have been discovered rather
> than designed," but in all honesty, this is exactly the situation with
> D's compile-time introspection.  D's templates are better, yes, but
> the problem has simply been promoted to a wider scope.
> 
> So what can we do?  I've been thinking about it and I think that
> __traits, coupled with the new template constraints, can handle just
> about everything.  Does that mean we ditch all the other syntax?  Not
> necessarily - it's just that __traits can be the _backend_ for many
> other features.
> 
> First of all __traits' name has to be revised.  The double-underscore
> just isn't working for me.  I think it would be a fair tradeoff to
> rename it "traits" and rename the std.traits and core.traits modules
> something else.  Come on Walter, I know that adding keywords is
> undesirable, but ffs, at some point _not_ adding keywords is just as
> bad.  D does not have a very large user or codebase, and if you're
> going to break backwards compatibility - _break it now_, before it's
> too late.  (besides, some of the keyword mass will need to be
> redistributed when imaginary/complex types are removed ;) )
> 
> Secondly - the type properties are cute but they're not very flexible.
>  They can interfere with fields and methods, and so the compiler has
> to explicitly check that aggregate member names don't step on the
> built-in property names.  I think that "T.prop" could just be replaced
> with "traits(prop, T)".  traits(min, int), and so on.  Yes, it's
> longer - but that's what templates are for, if you really want it
> shorter: Min!(int).
> 
> Third, the is() expression is greatly overstepping its bounds now that
> traits is around.  Why is there "is(T == class)", but
> __traits(isAssociativeArray, T)?  The is(T) form can be replaced by
> __traits(compiles).  The is(T : U) form can be replaced by
> traits(convertible).  The is(T == U) forms can all be replaced by
> traits(equivalent) and traits(isClass) and the like.  The strange is(T
> U), is(T U : V), is(T U == V) forms.. I'm not sure what to do about
> those.  The ones like is(T U == return) are an obvious abuse and
> should be replaced with traits(returnType) or the like.
> 
> The fourth and final issue is template specialization.  This one
> really does have too much inertia to remove.  So what I propose for
> this is that is() -- now that it has the ability to perform just about
> everything that template specialization can -- should become the
> backend for template specializations.  That is, something like:
> 
> template Foo(T, U : V[K], K, V)
> {
> ...
> }
> 
> is just a shorter way of writing something like:
> 
> template Foo(T, U) if(is(U : V[K]))
> {
> ...
> }
> 
> I don't think template constraints currently introduce symbols into
> the template body, but this would declare V and K as types within the
> body of Foo.
> 
> But here's the kicker: even is() is not an entirely basic construct.
> It's more or less a shortcut for more complex traits expressions
> combined with the ability to alias traits to symbols.  That is, "is(U
> : V[K])" is like the pseudocode "traits(isAssociativeArray, U) &&
> alias traits(itemType, U) V && alias traits(indexType, U) K".  Of
> course you can't put aliases in expressions, but the overall idea is
> that this is() expression is the same as using isAssociativeArray and
> then aliasing other traits as K and V.
> 
> Why do this?  Simplicity, generality, and consistency.  Once all this
> is done, it becomes easy to see what questions can and can't be asked
> about your code.  You only have to look in one place: traits.
> Everything else is defined in terms of it.
> 
> ...
> 
> So what do you think?

I completely agree that compile time introspection in D is very messy.

There are some other problems with CT introspection, which I have 
explained in my post some time ago:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=77654

In the same post I also proposed unified syntax for template 
specialization, static if, static assert and alias, while dropping 
completely is() expression for templates. Basically my proposal is about 
extending template pattern matching.

You have touched few other areas which needs to be rethought. But I 
think that just using traits will not work very good. It will be too 
explicit e.g.

Your proposal:
static if(is(traits(isAssociativeArray, T))) {
  traits(associativeArrayKeyType, K);
  traits(associativeArrayValueType, V);
}

Compared to my proposal:
static if (T V K : V[K]) {
  //V and K is already defined here
}

Anyway merging these two proposals will improve situation significantly.

BTW. I also hate underscores in keywords. :-P

Regards
Marcin Kuszczak
(aarti_pl)
November 25, 2008
Re: Unification and extension of compile-time reflection
Don Wrote:

>  > Some of these methods overlap but with wildly different syntax.
> 
> You left out typeof/typeinfo/typeid. There's run-time typeinfo, as well 
> as compile-time.

I'd like real uniform API for both rtti and ctti too (ctti code being subject to compile time evaluation). Template constraints could be expressed as contracts. All this declarative syntax can get very messy and unintuitive.
November 25, 2008
Re: Unification and extension of compile-time reflection
"Bill Baxter" <wbaxter@gmail.com> wrote in message 
news:mailman.54.1227583827.22690.digitalmars-d@puremagic.com...
On Tue, Nov 25, 2008 at 11:48 AM, Ary Borenszweig <ary@esperanto.org.ar> 
wrote:
>> I liked the way you wrote this. :-)
>>
>> I think neither __traits nor a property is good enough for compile-time
>> reflection. I think just one property is enough.
>>
>> For example in Java you do:
>>
>> someInstance.getClass()
>>
>> and then you enter "the reflection world", which uses the same language 
>> as
>> Java, but it's at a different level.
>>
>> So:
>>
>> var.reflect
>>
>> or something like that would be awesome. Then you can do:
>>
>> - something.reflect.methods
>> - something.reflect.isVirtual
>> - something.reflect.isAbstract
>> - something.reflect() // same as something.reflect.compileTimeValue
>> - something.reflect.fields
>> - etc.
>>
>> So you just don't allow "reflect" (or whatever) as a field name (if you
>> define it, it's an error, much like "sizeof"), but once you enter 
>> "reflect"
>> the compiler can add as many name as it wants, nobody can override these.
>> "reflect" is smart so that for an expression, it return a specific
>> (compile-time) type; for classes, another (compile-time) type; for
>> variables, another (compile-time) type; etc.
>
>Or you could just call it traits.
>
>something.traits.methods
>something.traits.max
>something.traits.sizeof
>(1+34.).traits.typeof
>
>I do like the general idea of unifying this stuff.  Can you make an
>alias or variable of this .traits/.reflect type?  Can it return a
>metaclass type of some sort so that an alias would be possible?  I.e.
>alias t = something.traits;
>

That would make it much easier to port over Java code that uses reflection. 
And even aside from that, I think it's a very nice and clean solution.
« First   ‹ Prev
1 2 3
Top | Discussion index | About this forum | D home