On Tue, Nov 25, 2008 at 11:48 AM, Ary Borenszweig <[EMAIL PROTECTED]> 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

Reply via email to