March 20, 2012
Andrei Alexandrescu wrote:
> like printing money is for a government: very tempting, with apparently good short-term benefits, but with devastating cumulative effects.

RON PAUL 2012!!!

sorry, I couldn't help myself.


> Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. Nobody will care to think about and come with idioms that use the language to do great things, if they know a language feature could be always added that makes things "nicer".

You can be creative with a sledge hammer, or you can be creative with a jack hammer. D is already a bulldozer, but that doesn't mean it shouldn't become a wreaking ball.

;-)


March 20, 2012
On Tue, 20 Mar 2012 11:17:02 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> Perhaps we should add a field of type Variant[string].

1. Variant is not (and shouldn't be IMO) part of druntime.
2. This is *static* data that should be available at compile time.  D's runtime wasting cycles filling in static data (including lots of heap allocations) seems like a big enough detriment that compiler help is warranted.

>> This is an already ridiculously hackish approach, and
>> it *does not* work for anything besides trivial applications. It is
>> completly unreasonable to expect everything to be done in a library; the
>> compiler exists for a reason and at some point you have to draw the
>> line.
>
> 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.

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.

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?"

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.

> Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity. Nobody will care to think about and come with idioms that use the language to do great things, if they know a language feature could be always added that makes things "nicer".

I have to disagree for this instance, the barrier to creating reflection data from compile-time info is very large.  If anything, this *expands* the ability to create, since you now have a new way to pass information from compiler to runtime.

-Steve
March 20, 2012
On 3/20/12 10:52 AM, Jacob Carlborg wrote:
> On 2012-03-20 16:17, Andrei Alexandrescu wrote:
>> On 3/20/12 12:50 AM, Kapps wrote:
>
>> Perhaps we should add a field of type Variant[string].
>
> No, not Variant[string] again.

Why? I thought it was agreed that that's a good idea for exceptions.

>> I'm not saying this particular feature should or should not be in the
>> language, but I wish our community exercised considerably more restraint
>> when it comes about adding new language features.
>
> See my reply to one of your other posts:
>
> http://forum.dlang.org/thread/bccwycoexxykfgxvedix@forum.dlang.org?page=9#post-jk9gk8:242t7k:241:40digitalmars.com

I understand the intention there, but my point stands: let's first explore doing it in the language, and advocate a new feature only when that fails. We've been too trigger-happy about proposing features even for the most trivial inconveniences.


Andrei


March 20, 2012
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.

> 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.

> 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.

> 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?

>> Also, as I mentioned, the availability of the easy escape hatch of
>> adding a language feature thwarts creativity. Nobody will care to
>> think about and come with idioms that use the language to do great
>> things, if they know a language feature could be always added that
>> makes things "nicer".
>
> I have to disagree for this instance, the barrier to creating reflection
> data from compile-time info is very large. If anything, this *expands*
> the ability to create, since you now have a new way to pass information
> from compiler to runtime.

I hope I'll be convinced.


Andrei
March 20, 2012
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:
>
>> Perhaps we should add a field of type Variant[string].
>
> 1. Variant is not (and shouldn't be IMO) part of druntime.
> 2. This is *static* data that should be available at compile time. D's
> runtime wasting cycles filling in static data (including lots of heap
> allocations) seems like a big enough detriment that compiler help is
> warranted.

Forgot to mention - I snipped these points because I agree with them.

Andrei

March 20, 2012
On Tuesday, 20 March 2012 at 15:17:04 UTC, Andrei Alexandrescu wrote:
> Also, as I mentioned, the availability of the easy escape hatch of adding a language feature thwarts creativity.

I agree entirely. Usually, when I see threads like this,
my response is "challenge accepted".

But, on this problem, my answer is, unfortunately,
"challenge failed".

I want to annotate declarations for my web.d, where
you can write a class and have D do a bunch of work
for you in creating all kinds of stuff.

Let me do up a quick example:

===
struct MyType {
   int num;
   string name;
   string desc;
   Element makeHtmlElement() {
      auto e = Element.make("div", desc).addClass("my-type");
      return e;
   }
}

class MySite : ApiProvider {
    MyType getSomething(int someNumber, string name, Text description) {
         return MyType(someNumber, name, description);
    }

    void savePhoneNumber(string name, string phoneNumber) {
        _checkLoggedIn();
        ensureGoodPost();
        _doSave();
    }

    void _doSave() { yada yada yada }
}
===


Now, when you go to mysite.com/get-something, it will
generate a form like this:

      <form method="GET">
  Some Number: ____________
         Name: ____________
  Description: ____________
               ____________
               ____________

              [Get Something]
       </form>



It pulls this info from the D code - it uses an alias
template param to the method, then parses .stringof
to get the names and default params. (It then mixes
in the default to get a D type, which doesn't work
on custom types since they aren't in the right scope,
but hey, it works in a lot of cases.)



When possible, it uses the type of the parameter
to specialize the form. This comes from ParameterTypeTuple.

Here, it recognizes struct Text{} as being a textarea.
tbh, I'd prefer to use @note(Textarea(rows)), but this
works, and alias this to string makes it pretty natural
to work with too.



Moreover, I wrote method="GET". It pulls this from the
method name. Since it starts with get, it doesn't require
http post for it.



So far, so good. Let's look at the next method, savePhoneNumber.
This !startsWith("get"), so it generates a POST form, with
the same kind of thing:

        Name: _________
Phone Number: _________
     [Save Phone Number]


Hey, it works. But, I'd like to do even better. Could
we do validation?

Well, yeah, I think we could.

struct PhoneNumber {
     enum _validationRegex = "[0-9]+";
}

Boom.

What about an example text, though? You could use
that same enum method, but you would need a different
type for each example.

If you have two "string name" and in one case, you want
it to be "e.g. Bob Smith" and in the other, you want
"e.g. Downtown Office", you'd have to make separate
structs for them, despite it just being strings in
every other way.


That's one big case where the compile time annotation
comes through:

void savePhoneNumber
    @note(ExampleText("e.g. Downtown Office")
        string name,
    PhoneNumber phoneNumber)
{ }


To do that with a mixin, you might:

mixin(ExampleText!(savePhoneNumber, "name", "downtown"));
void savePhoneNumber(string name, ...) {...}

and have that yield:

enum _attribute_DsavePhoneNumberMangle_param_name_FILE_LINE_type = ExampleText("downtown");



ok, this is a bit of a pain in the ass, but I think it'd
work... (the file_line_type stuff is so you can have multiple
things of the same type. Moderately fragile! But, it'd work.)


The pain gets bad down the line though. Renaming things means
repetition. Separate declarations might get lost as you
shuffle the order around. But, not too awful...


Until you get into more functions. Enter arsd.web.prepareReflection
and makeJavascriptApi:

foreach(member; __traits(allMembers, yourclass))
    // build a runtime map and corresponding bindings for other languages



Should our enum be included here? Should this include code
to detect the annotations and translate them to the
native target language? How much code is this going to take?

What if I use a third party lib? Will it have to be hacked to
ignore these extra names too?


Well, we can work around this too. web.d has a convention
where static if(name[0] == '_') { don't process }. (This
is actually a workaround for a lack of __traits(getProtection)
though. We already have D keywords that do this: public
and/or export. But, there's currently no way to check for these,
so I settled for a naming convention.

This is what _doSave() demonstrates in the example.

I'm hoping to do a dmd pull request to add getProtection at
some point though.)

We could all agree on a naming convention, in theory. In
practice, I don't know. If I could check export || public,
I might drop the underscore.



Another problem is how do we get this data? We have
an alias of the method... but not it's parent. Well,
there's __traits(getParent). I think we could actually
do that.

But the idea of a parent reminds me of another problem.
This is a class, the method is virtual.

What if a subclass overrides it and wants to tweak
the annotation?


How will we handle annotation inheritance? Overloading
is kinda solved via mangleof (I think, I haven't tried
this yet, but in principle it would work), but inheritance
is a whole other bag.


Perhaps we do ClassName_methodName and in the search go
up the base class tree?


I don't know... I think we *could* make it work at this
point, but it depends on an agreed naming convention,
where we (essentially) embed little DSLs in member names,
packing all kinds of info in there to work correctly.

Piles upon piles of string processing code that we'd
all have to agree on for reflection work, with
complications around almost every corner. If we
solve overloading and inheritance, what will be
next?



Embedding info directly in names is the easiest,
but a bit problematic too:

getSomething()


What if I want it to be http GET, but be named
say, "something-viewer"?

Currently, I implement that as two functions:

getSomething() for machines to access and
alias getSomething somethingViewer;
for human users.


It isn't ideal, but again, it works.
(The ensureGoodPost() function does a runtime
check against CSRF. That's a potential candidate
for an annotation too, but the exception works
perfectly fine too, so meh.)




Another thing I'd like, in the same vein as
the ExampleText, is Hideable. Again, not really
a type, though it could be with enough special
case code added throughout to handle it.

But, this would be a parameter that, if given,
is hidden instead of showed:

void changeName(@note(Hide) int id, string name) {}

link to change-name?id=1, and then you don't have
to show the ID in the automatically generated form.

Don't want to always do this though:

send-message?message=example+message

we *want* that to be editable...


(In practice, right now, I make the form another
function and modify it myself. That's several
lines for something that could be done generically
though, which is pain.)







Well, I was going to go on longer, but I think we
have enough here to draw a conclusion.

Can we do it? Well, I kinda think we can. Hell,
I already do like 3/4 of what I want in web.d

With the power of D, we could make all kinds of
weird stuff encoded as strings, stored as variable
names.


But, it is hard to use at most levels. Writing the
annotations is a long, repetitive process. Processing
them takes a lot of fragile code.

Even /ignoring/ them takes a lot code, and that's
what, to me, pushes it over into compiler territory.

Compiler provided annotations are opt-in and backward
compatible. If you want them, they're there, and if
you don't, they aren't in the way like magic enums
would be.
March 20, 2012
On 03/20/2012 05:31 PM, Adam D. Ruppe wrote:
>
> Even /ignoring/ them takes a lot code, and that's
> what, to me, pushes it over into compiler territory.

vote++
March 20, 2012
Andrei Alexandrescu wrote:
> On 3/20/12 10:52 AM, Jacob Carlborg wrote:
>> On 2012-03-20 16:17, Andrei Alexandrescu wrote:
>>> On 3/20/12 12:50 AM, Kapps wrote:
>>
>>> Perhaps we should add a field of type Variant[string].
>>
>> No, not Variant[string] again.
>
> Why? I thought it was agreed that that's a good idea for exceptions.

Please, do not transform D into a dynamic language.
March 20, 2012
On 3/20/12 2:04 PM, Piotr Szturmaj wrote:
> Andrei Alexandrescu wrote:
>> On 3/20/12 10:52 AM, Jacob Carlborg wrote:
>>> On 2012-03-20 16:17, Andrei Alexandrescu wrote:
>>>> On 3/20/12 12:50 AM, Kapps wrote:
>>>
>>>> Perhaps we should add a field of type Variant[string].
>>>
>>> No, not Variant[string] again.
>>
>> Why? I thought it was agreed that that's a good idea for exceptions.
>
> Please, do not transform D into a dynamic language.

Where's the "dynamic languages rok" crowd when you need it :o).

Andrei
March 20, 2012
Le 20/03/2012 16:17, Andrei Alexandrescu a écrit :
> On 3/20/12 12:50 AM, Kapps wrote:
>> On Monday, 19 March 2012 at 21:00:32 UTC, Andrei Alexandrescu wrote:
>>> On 3/19/12 3:55 PM, F i L wrote:
>>>> I think this could get tricky for the compiler to confidently use given
>>>> that the mixed in enums can collide with existing members (although not
>>>> likely). Also, if objects are not identified as being unique marked (in
>>>> the compilers eyes), what specific attribute post-fixes will it be
>>>> searching for on enums members?
>>>
>>> Not a big issue, the name could always contain a uuid which makes
>>> collision practically impossibile.
>>>
>>> Andrei
>>
>> And with parameters? Or how about run-time reflection, which is
>> something that should be added eventually for attributes as well (that
>> is, typeid(Blah).getCustomAttributes())? We can't manually add things
>> into the TypeInfo.
>
> Perhaps we should add a field of type Variant[string].
>
>> This is an already ridiculously hackish approach, and
>> it *does not* work for anything besides trivial applications. It is
>> completly unreasonable to expect everything to be done in a library; the
>> compiler exists for a reason and at some point you have to draw the
>> line.
>
> 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.
>
> Also, as I mentioned, the availability of the easy escape hatch of
> adding a language feature thwarts creativity. Nobody will care to think
> about and come with idioms that use the language to do great things, if
> they know a language feature could be always added that makes things
> "nicer".
>
> I'm not saying this particular feature should or should not be in the
> language, but I wish our community exercised considerably more restraint
> when it comes about adding new language features.
>

That feature has been added to java with great benefit. I think the underlying need here is AOP. Adding annotation to java had great benefice in introducing AOP capabilities to the language.

See :
http://projectlombok.org/

Considering that D has great compile time capabilities, this is somewhere we want to go.

Additionnaly, this is something that remove other capabilities, and replace them by lib support. For example, with @synchronized, I could specify the phobos that I want that method or class to be synchronized, and the lib is able to add the needed code to ensure that functionality at compile time.

I have to say that the whole idea of attaching property to instance doesn't make any sense to me - Walter make a good point on that I think, so I will not repeat his arguments.