March 20, 2012
Le 18/03/2012 05:49, Walter Bright a écrit :
> On 3/17/2012 9:12 PM, F i L wrote:
>> Walter Bright wrote:
>>> I also do not get why per-instance attributes even exist, as I agree
>>> that's
>>> what fields are for.
>>
>> Attributes are per-type (type properties, methods, etc), not
>> per-instance, and
>> only accessible (in C#) through type reflection (to my knowledge).
>> According to
>> http://msdn.microsoft.com/en-us/library/z919e8tw(v=vs.80).aspx
>> attribute objects
>> aren't constructed until reflected upon.
>
> My impression is it is just obfuscation around a simple lazy
> initialization pattern.
>
> While I can see the abstraction usefulness of compile time attribute
> metadata, I am having a hard time seeing what the gain is with runtime
> attributes over more traditional techniques.

The attribute itself doesn't do anything at runtime. But the attribute should be able to modify what is qualified before it is compiled.

With that model it is much simpler, it open the door to AOP, and it allow us to implement as lib many feature that would have required compiler support before.

AS mentioned deprecated, synchronized and override (including the recent propagation of @safe, pure, nothrow that have made so much noise) could have been implemented with no compiler changes with a good @property/@annotation support. This tells us quite a lot about its usefulness and how much powerful it is.

Probably as powerful as templates are, and close to nuclear power combined with template.
March 21, 2012
Sorry for not quoting, but I'm not sure who to quote...

I think people are over-thinking this issue. Adam's initial proposal was simply to be able to add compile-time checkable data to data structures and functions. I think this works well at this level. As he demonstrated, string mixins and ctfe only get you so far in this instance.

The idea that in order to replicate this functionality, you need to actually parse the D code to get what you want, is horrific. Relying on naming conventions for functionality is horrendous, especially when a simple @note(data1,data2=val) can solve all of the issues. And if they're only compile time, then it can all be discarded when you get to code-gen, and if you deliberately limit the scope of them, then you aren't fostering the "new language features will solve all my problems".

Looking at other languages is a good start for ideas, but ultimately we need a D-flavoured solution, and using simple `__trait`-inspectable annotations is a good way of doing it. As Teoh said, think of it as a hook into Typeinfo, allowing the programmer to alter it at compile time.

I don't care about Aspect-Oriented programming, or anything like that, I just want to be able write:

@note(GET,POST)
auto myClassFunction(arg1, arg2, arg3) { ... }

without having to use templates that break inheritance, or doing checks in the function for the request type, that could be handled in a library. There's already a mechanism for seeing what attributes that function has, so why can't I have some code that does this:

template hasAnnotation(alias data, string an) {
    enum hasAnnotation = __traits(hasAnnotation, data, an);
}

(Or something, my template-fu leave something to be desired, not the point though). It already looks like idiomatic D code.

Its not some big change that massively overhauls the way code is written, the same way annotations in Java haven't meant that people suddenly write Java completely differently. They do what they look like they do, they add some extra information to the "thing" in question that allow for some more advanced decision making.

Going back to the Web-based example, if I use an opDispatch system to forward requests to the appropriate controller, I can use compile-time reflection to generate checking code for the handlers, based , this means that a simple annotation makes reading the function code much simpler, since boiler-plate checking code has been removed, I can implement a white-list based policy for request-type access, rather than a blacklist that using isPost or isGet methods to check in-handler. This is more secure, since if I forget to add /any/ annotations, then it wont receive /any/ requests. Lo and behold, I can now have secure inter-controller communication without needing 1. a naming convention, 2. an access control list or 3. boilerplate code.

I could go on a similar rant about serialization, but I think my point is made.

deadalnix is talking about being able to re-write language features in terms of this system, but that's taking it too far, like a lot of people, he wants D to be all thing to all people. The original idea was to just to be able to add simple attributes to functions. Other people sought to extend this unnecessarily, but everything else is just templates, mixins and CTFE, nothing else.

The real discussion that need to be going on is: How far do notes extend? (can you have arbitrary expressions annotated?) What data can be packed into annotations? (Can i put any data into annotations, or only internal types?) Syntax details, obviously using the @-syntax, but specific naming, so @note, or @annotation? for example. Scoping/Collision, I don't think this will be an issue, but if two libraries are looking for the same annotation name, then there could be some issues.

I think there is merit in having a Java/C# @<myannotation>, but I don't think it is needed for D, everything that those annotations cover can be done using CTFE and mixins, with the minor addition above.

--
James Miller
March 21, 2012
On Wednesday, 21 March 2012 at 00:03:28 UTC, James Miller wrote:
> template hasAnnotation(alias data, string an) {
>     enum hasAnnotation = __traits(hasAnnotation, data, an);
> }

I'm actually thinking of identifying them by type. Types
are well established in the language - scoping, namespaces,
fields, and so on are all solved.

Querying them is solved too - we can look over a TypeTuple
and use is(typeof()) to get what we want.

(using types as names instead of strings is the idea that
came to me on my ride that prompted this thread - it is the
missing piece in what I wanted here. Strings can conflict,
but types already handle this.)


So you'd just very simply do:

struct MyAttribute { bool activated; }

// @note is just like doing internalTuple ~= MyAttribute(true)
// and MyAttribute is of course just a plain old struct
initializer
@note(MyAttribute(true)) int a;

To check it:

foreach(note; __traits(getNotes, member_a))
     static if(is(typeof(note) == MyAttribute) {
         // do what you want here, ignore types you don't know
     }


Of course, this is in a plain template. No implicit
stuff, no modifying the ast. This data only comes up
when you ask for it, and you ask for it in a plain
old mixin template or something like that - existing
language features.

> How far do notes extend?

I'd only put it on declarations (variables,
classes, structs, enums, members, and function
parameters.)

> What data can be packed into annotations?

Being able to use custom types is an
important part of my idea here.
March 21, 2012
On 2012-03-20 22:36, deadalnix wrote:

> It is more tricky if the property isn't a simple attribute to read.
> Again, consider what is done with this simple example :
> http://projectlombok.org/
>
> We have the opportunity here to introduce in D the concept of aspect
> oriented programming. This is HUGE. If you are afraid of the addition of
> a functionnality to the language, don"t worry, you are not just adding a
> functionnality, but a whole new paradigm.
>
> And, BTW, this would allow us to drop some functionalities that now can
> be provided by phobos (synchronized for example is an obvious one). Same
> goes for override, deprecated, and the fun thing is that we can
> implement our own to extends the language even more as lib.
>
> Even the propagation of pure, @safe, nothrow and const that has been
> discussed recently can be done with that feature.
>
> If you are worried about introducing language features (I am) you should
> definitively introduce that one, because lot of features has already
> been included just because that one is lacking.
>
> Adding compile time information to a type is the visible part of the
> iceberg. Really.

I couldn't agree more.

-- 
/Jacob Carlborg
March 21, 2012
On 2012-03-21 01:35, Adam D. Ruppe wrote:
> On Wednesday, 21 March 2012 at 00:03:28 UTC, James Miller wrote:
> So you'd just very simply do:
>
> struct MyAttribute { bool activated; }
>
> // @note is just like doing internalTuple ~= MyAttribute(true)
> // and MyAttribute is of course just a plain old struct
> initializer
> @note(MyAttribute(true)) int a;
>
> To check it:
>
> foreach(note; __traits(getNotes, member_a))
> static if(is(typeof(note) == MyAttribute) {
> // do what you want here, ignore types you don't know
> }

That's basically my initial proposal and how annotations work in Java.

>> What data can be packed into annotations?
>
> Being able to use custom types is an
> important part of my idea here.

I think any type that a template can take (as a value) + other attributes/annotations.

-- 
/Jacob Carlborg
March 21, 2012
On Wednesday, 21 March 2012 at 08:08:12 UTC, Jacob Carlborg wrote:
> On 2012-03-21 01:35, Adam D. Ruppe wrote:
>> On Wednesday, 21 March 2012 at 00:03:28 UTC, James Miller wrote:
>> So you'd just very simply do:
>>
>> struct MyAttribute { bool activated; }
>>
>> // @note is just like doing internalTuple ~= MyAttribute(true)
>> // and MyAttribute is of course just a plain old struct
>> initializer
>> @note(MyAttribute(true)) int a;
>>
>> To check it:
>>
>> foreach(note; __traits(getNotes, member_a))
>> static if(is(typeof(note) == MyAttribute) {
>> // do what you want here, ignore types you don't know
>> }
>
> That's basically my initial proposal and how annotations work in Java.
>
>>> What data can be packed into annotations?
>>
>> Being able to use custom types is an
>> important part of my idea here.
>
> I think any type that a template can take (as a value) + other attributes/annotations.

With the mixin improvement proposal any arbitrarily complex feature can be implemented in the library, appearing to enjoy first class syntax with just 1 extra character penalty vs the compiler.

#struct Foo
{
  @NonSerialized int x;
  @NonSerialized int y;
  int z;
}

Just imagine the next step, if the CTFE interface was based on AST:s instead of strings...

March 21, 2012
On Wednesday, 21 March 2012 at 08:29:23 UTC, Tove wrote:
> With the mixin improvement proposal any arbitrarily complex feature can be implemented in the library, appearing to enjoy first class syntax with just 1 extra character penalty vs the compiler.

My main concern with the library implementation isn't
syntax.

The big question is still: where will you put the
annotation data?
March 21, 2012
On Tue, 20 Mar 2012 12:16:41 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 3/20/12 11:09 AM, Steven Schveighoffer wrote:
>> On Tue, 20 Mar 2012 11:17:02 -0400, Andrei Alexandrescu
>> <SeeWebsiteForEmail@erdani.org> wrote:
>>> I'm afraid I disagree. A targeted language feature definitely makes a
>>> library approach inferior, by definition. But adding features is
>>> cheating, like printing money is for a government: very tempting, with
>>> apparently good short-term benefits, but with devastating cumulative
>>> effects.
>>
>> Not exactly. We could all be writing code in assembly if "adding
>> features" was always caustic.
>
> This is trivializing my point. Please.

Well, then let's not compare the hyperinflation of the economy to adding a compiler feature.  There are certainly good reasons to add compiler features, without devastating cumulative effects.

>> What is nice about adding this feature is it provides a custom solution
>> to hooking the compiler's TypeInfo generation. We are setting up the
>> compiler to give us hooks so we *don't* have to extend the compiler
>> every time we want new reflection features.
>
> There is something nice about every new feature.

Yes, but this nicety is not just syntax sugar or a shortcut, it's adding a whole new opportunity of communication through the compile-time/runtime barrier.

I think Adam Ruppe's post on how he tried to use library code to accomplish this is quite telling.  The comparison to OO programming in C vs. C++/D seems quite appropriate.  And I've written Xt widgets, so I can vouch for how shitty it is to do OO programming in C.

>> One of the oft-requested features of D is reflection capability. The
>> answer is generally that we have compile-time reflection, which can
>> theoretically be used to build runtime reflection. However, the rebuttal
>> I always come back with is "yeah, but why should I build at runtime that
>> which is obvious at compile time?"
>
> I thought there were discussions that didn't add runtime overhead.

I haven't seen that.  Perhaps a link?

>> Note that one library that did attempt runtime reflection capability
>> (flectioned) does all this at runtime, and does some really funky shit,
>> like opening /proc/self/map on Linux, or requiring you to pass an
>> OPTLINK map file. I don't look at these as "innovations" as much as I do
>> as workarounds.
>
> Maybe there's a better approach than flectioned. Consider the language is frozen solid. How would you solve problems with it?

I think the closest anyone has come is Jacob, with his orange library.  Maybe he can respond to this point.

-Steve
March 21, 2012
On Wednesday, 21 March 2012 at 08:08:12 UTC, Jacob Carlborg wrote:
> That's basically my initial proposal and how annotations work in Java.

Cool. I did not realize that.
March 21, 2012
On 2012-03-21 14:54, Steven Schveighoffer wrote:
> On Tue, 20 Mar 2012 12:16:41 -0400, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> Maybe there's a better approach than flectioned. Consider the language
>> is frozen solid. How would you solve problems with it?
>
> I think the closest anyone has come is Jacob, with his orange library.
> Maybe he can respond to this point.
>
> -Steve

With Orange I'm doing everything with compile time reflection. Flectioned was all about runtime reflection. It's possible to replace methods with flectioned at runtime and do a lot of crazy things.

In Orange I'm using mixins, tupleof and stringof to accomplish most of the compile time reflection. Example:

class Foo
{
    int a;
    int b;

    mixin NonSerialized!(b);
}

serialize(new Foo);

"mixin NonSerialized!(b);" is expanded to:

static const __nonSerialized = ["a"];

The fields are enumerated and serialized using tupleof. It also checks all structs and classes if they have "__nonSerialized" defined.

-- 
/Jacob Carlborg