www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Custom attributes (again)

reply Manu <turkeyman gmail.com> writes:
I just want to add more real-world experience to the controversy.
I'm finding myself needing to use custom attributes almost every day.

I have numerous systems that need to scan the module for things marked
accordingly to automate bindings to their respective systems.

This is my current list of attributes I want to mark things with:
  Export to game engine
  Export to script language
  Import from game engine
  ** Import from script language (tentative, I'm sure I'll need it in a few
more days)
  Expose to editor (with additional properties; description, edit type, etc)
  Serialise (load/save game)
  Replay serialisation (a different kind of serialisation that works with
different data sets)

And others I've encountered in passing that I can't recall right now.

As you can imagine, any attempt to 'work around' the lack of an attribute
system, ie, (ab)using enums, etc as have been suggested, leads to a big
mess in the context of all these requirements.
Management of such lists of stuff in disconnected places in code is time
consuming, thoroughly annoying, error-prone, difficult to maintain, and
leaves programmers with the bitter taste of C++.
Alternatively, wrapping virtually every single declaration made in mixin()
and declaring everything as strings is even more nasty, and the contrast
between mixin() declarations and 'normal' declarations looks completely
stupid. (Totally unreadable + difficult to understand, breaks intellisense,
code completion, syntax hilighting, etc... ie, unusable)

Does anyone have a *realistic* suggestion for emulating custom attributes?
Something that doesn't have any(/many) of the side effects I mention?
I haven't come up with anything that's acceptable yet.

If not, I assert that D absolutely needs a custom attribute system. For us
here, this will enable D the single biggest advantage over using C++ in the
same context that I've identified so far.
D's meta-programming is amazing, but sadly, proving pointless to me right
now without being able to mark stuff appropriately. All the meta magic is
hovering just out of my grasp, due to the fact I have no way to indicate
what items should involve with what systems.
Currently, I have to maintain big registry tables of junk that must be
amended/updated any time anyone adds/changes anything... and I'm feeling
rather embarrassed when I tell the other non-D programmers that they just
need to update this table here... and here... and make sure that's in sync
too before their stuff will just 'magically' work ;)


patterns, I don't think there should be any mystery over how they should be
implemented.
Apr 05 2012
next sibling parent reply "Paulo Pinto" <pjmlp progtools.org> writes:
	charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Manu,

as a workaround would marker interfaces help to solve your problem for =
the time being?

This is just a suggestion for the time being, as I agree with you, =
attributes/annotations are quite handy.

--
Paulo

"Manu" <turkeyman gmail.com> wrote in message =
news:mailman.1363.1333627256.4860.digitalmars-d puremagic.com...
I just want to add more real-world experience to the controversy.
I'm finding myself needing to use custom attributes almost every day.=20

I have numerous systems that need to scan the module for things marked =
accordingly to automate bindings to their respective systems.

This is my current list of attributes I want to mark things with:
  Export to game engine
  Export to script language
  Import from game engine
  ** Import from script language (tentative, I'm sure I'll need it in a =
few more days)
  Expose to editor (with additional properties; description, edit type, =
etc)
  Serialise (load/save game)
  Replay serialisation (a different kind of serialisation that works =
with different data sets)

And others I've encountered in passing that I can't recall right now.

As you can imagine, any attempt to 'work around' the lack of an =
attribute system, ie, (ab)using enums, etc as have been suggested, leads =
to a big mess in the context of all these requirements.
Management of such lists of stuff in disconnected places in code is time =
consuming, thoroughly annoying, error-prone, difficult to maintain, and =
leaves programmers with the bitter taste of C++.
Alternatively, wrapping virtually every single declaration made in =
mixin() and declaring everything as strings is even more nasty, and the =
contrast between mixin() declarations and 'normal' declarations looks =
completely stupid. (Totally unreadable + difficult to understand, breaks =
intellisense, code completion, syntax hilighting, etc... ie, unusable)

Does anyone have a *realistic* suggestion for emulating custom =
attributes? Something that doesn't have any(/many) of the side effects I =
mention?
I haven't come up with anything that's acceptable yet.

If not, I assert that D absolutely needs a custom attribute system. For =
us here, this will enable D the single biggest advantage over using C++ =
in the same context that I've identified so far.
D's meta-programming is amazing, but sadly, proving pointless to me =
right now without being able to mark stuff appropriately. All the meta =
magic is hovering just out of my grasp, due to the fact I have no way to =
indicate what items should involve with what systems.
Currently, I have to maintain big registry tables of junk that must be =
amended/updated any time anyone adds/changes anything... and I'm feeling =
rather embarrassed when I tell the other non-D programmers that they =
just need to update this table here... and here... and make sure that's =
in sync too before their stuff will just 'magically' work ;)


patterns, I don't think there should be any mystery over how they should =
be implemented.
Apr 05 2012
next sibling parent Manu <turkeyman gmail.com> writes:
On 5 April 2012 15:04, Paulo Pinto <pjmlp progtools.org> wrote:

   as a workaround would marker interfaces help to solve your problem for
 the time being?
I don't think it'd suit my purposes implemented as an interface for a variety of reasons: I need to be able to attribute many different types of things; data members, static functions, methods, etc. I need to be able to annotate 'loose' things at module scope. The whole point of the system is that it doesn't enforce a rigid interface. From my examples above, these items could be basically anything, anywhere.
Apr 05 2012
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Paulo Pinto:


 design patterns, I don't think there should be any mystery over 
 how they should be implemented.
There are other interesting ways to conceive attributes. I think of them in a different way, more like user-defined ways to extend the static type system. Bye, bearophile
Apr 05 2012
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/5/2012 5:00 AM, Manu wrote:

I
 don't think there should be any mystery over how they should be implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Apr 05 2012
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 05/04/2012 19:35, Walter Bright a écrit :
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
They should be attached to declarations.
Apr 05 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/5/12 12:44 PM, deadalnix wrote:
 Le 05/04/2012 19:35, Walter Bright a écrit :
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
They should be attached to declarations.
The question was whether the declaration affects the type of the declared or not. Andrei
Apr 05 2012
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 05 Apr 2012 14:05:49 -0400, Andrei Alexandrescu  =

<SeeWebsiteForEmail erdani.org> wrote:

 On 4/5/12 12:44 PM, deadalnix wrote:
 Le 05/04/2012 19:35, Walter Bright a =C3=A9crit :
 On 4/5/2012 5:00 AM, Manu wrote:

n
 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk=
to
 many smart people about attributes. But I did find some confusion - =
are
 they best attached to the variable/function (i.e. "storage class"), =
or
 attached to the type ("type constructor")? I think the former.  =
 Attaching
 it to the type leads to all sorts of semantic issues.

 From your list of uses, it looks like attaching it to the variable o=
r
 function is an apropos solution.
They should be attached to declarations.
The question was whether the declaration affects the type of the =
 declared or not.
For user-defined attributes, no. This is metadata for the programmer/li= b = to decode. Obviously, compiler-defined attributes can. -Steve
Apr 05 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/05/2012 08:05 PM, Andrei Alexandrescu wrote:
 On 4/5/12 12:44 PM, deadalnix wrote:
 Le 05/04/2012 19:35, Walter Bright a écrit :
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
They should be attached to declarations.
The question was whether the declaration affects the type of the declared or not. Andrei
Ideally it would be powerful enough to allow changing the type, but most applications probably want the type to stay the same.
Apr 05 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/5/2012 11:32 AM, Timon Gehr wrote:
 Ideally it would be powerful enough to allow changing the type, but most
 applications probably want the type to stay the same.
Having it perturb the type implies a huge swamp of how that affects the semantics. You've got overloading, name mangling, type inference, implicit conversions, covariance, etc. All I can say is I see no way that can work with user defined semantics.
Apr 05 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 05/04/2012 20:51, Walter Bright a écrit :
 On 4/5/2012 11:32 AM, Timon Gehr wrote:
 Ideally it would be powerful enough to allow changing the type, but most
 applications probably want the type to stay the same.
Having it perturb the type implies a huge swamp of how that affects the semantics. You've got overloading, name mangling, type inference, implicit conversions, covariance, etc. All I can say is I see no way that can work with user defined semantics.
I did some hacking into dmd in that regard, and I can confirm this is pretty hard. The problem is already quite hard, but the lack of separation of concerns into dmd's ast make things even harder. I'm afraid we have to delay anything that do codeception in a first shot, which is really sad because this is promising. I still think this is somewhere we have to go at some point, but we will have to wait.
Apr 05 2012
prev sibling parent Manu <turkeyman gmail.com> writes:
On 5 April 2012 21:32, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/05/2012 08:05 PM, Andrei Alexandrescu wrote:

 On 4/5/12 12:44 PM, deadalnix wrote:

 Le 05/04/2012 19:35, Walter Bright a =C3=A9crit :

 On 4/5/2012 5:00 AM, Manu wrote:


 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk t=
o
 many smart people about attributes. But I did find some confusion - ar=
e
 they best attached to the variable/function (i.e. "storage class"), or
 attached to the type ("type constructor")? I think the former. Attachi=
ng
 it to the type leads to all sorts of semantic issues.

 From your list of uses, it looks like attaching it to the variable or
 function is an apropos solution.
They should be attached to declarations.
The question was whether the declaration affects the type of the declared or not. Andrei
Ideally it would be powerful enough to allow changing the type, but most applications probably want the type to stay the same.
Didn't someone already say there were existing language defined attributes that could be neatly implemented via libs if the feature were available? Which ones were they?
Apr 06 2012
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-05 19:35, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
specify with a fine grained control on what the attributes are attached to. foo FooBar bar () {} For example, is " foo" attached to "FooBar" or "bar". Java uses the Target annotation to specify this. -- /Jacob Carlborg
Apr 05 2012
next sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 05-04-2012 22:06, Jacob Carlborg wrote:
 On 2012-04-05 19:35, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
specify with a fine grained control on what the attributes are attached to. foo FooBar bar () {} For example, is " foo" attached to "FooBar" or "bar". Java uses the Target annotation to specify this.
attached to. How feasible this is with D's rather... loose attribute/modifier parsing, I don't know. -- - Alex
Apr 05 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 05/04/2012 22:06, Jacob Carlborg a écrit :
 On 2012-04-05 19:35, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
specify with a fine grained control on what the attributes are attached to. foo FooBar bar () {} For example, is " foo" attached to "FooBar" or "bar". Java uses the Target annotation to specify this.
This is bar's declaration.
Apr 05 2012
prev sibling next sibling parent "Kapps" <opantm2+spam gmail.com> writes:
On Thursday, 5 April 2012 at 17:36:31 UTC, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 design patterns, I
 don't think there should be any mystery over how they should 
 be implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
I'm not sure if I'm understanding this correctly, but by attaching to the type do you mean altering the type of the declaration such as shared or const do? If so, I am completely against attributes being able to do this; there's already better ways such as a struct with alias this. Another issue is that if runtime reflection gets added, it would be nice to be able to add attributes at runtime. This could cause things to break if the type itself is changed instead of getting attached to the declaration. Plus, attributes should not be invasive, they're just notes. The two main situations where I see attributes being used are: 1) Add some information about a declaration, such as NotSerialized on a field. 2) Add some information to a type, such as Serializable. If this can be done, with being able to pass compile-time value(s) to the attribute, all situations I have ever desired/seen/used attributes for would work nicely.
Apr 05 2012
prev sibling next sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 4/6/12 1:35 AM, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues.
I don't understand the difference between "storage class" and "type constructor". I guess I do. But my answer is the same as deadalnix: they are attached to declarations (at compile time). Can you give us an example of the confusion that arose? I can't understand it without examples. I think it should work like this: custom class Foo { custom void bar() { } void baz() { } } class Other {} __traits(hasAttribute, Foo, 'custom') --> true __traits(hasAttribute, Other, 'custom') --> false // I have no idea how to iterate the members of Foo, or get a reference to the "bar" method... I can't understand what __traits(getMember) returns from the docs...
Apr 05 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-06 05:30, Ary Manzana wrote:

 I don't understand the difference between "storage class" and "type
 constructor". I guess I do. But my answer is the same as deadalnix: they
 are attached to declarations (at compile time).

 Can you give us an example of the confusion that arose? I can't
 understand it without examples.

 I think it should work like this:

  custom
 class Foo {

   custom
 void bar() { }

 void baz() { }
 }

 class Other {}

 __traits(hasAttribute, Foo, 'custom') --> true
 __traits(hasAttribute, Other, 'custom') --> false

 // I have no idea how to iterate the members of Foo, or get a reference
 to the "bar" method... I can't understand what __traits(getMember)
 returns from the docs...
I would like to have the possibility to attach attributes to types and parameters as well. Some think like this: class Bar { not_null(Foo) bar ( custom int a) {} } Where not_null is attached to "Foo" and custom is attached to "a". -- /Jacob Carlborg
Apr 06 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 02:23 PM, Jacob Carlborg wrote:
 I would like to have the possibility to attach attributes to types and
 parameters as well. Some think like this:

 class Bar
 {
  not_null(Foo) bar ( custom int a) {}
 }

 Where  not_null is attached to "Foo" and  custom is attached to "a".
not_null cannot be attached to "Foo". It would have to create a new symbol not_null(Foo). And then, all the concerns Walter has raised apply.
Apr 06 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 14:31, Timon Gehr wrote:

  not_null cannot be attached to "Foo". It would have to create a new
 symbol  not_null(Foo). And then, all the concerns Walter has raised apply.
Hmm, I guess. But it would be nice to have :) -- /Jacob Carlborg
Apr 06 2012
prev sibling next sibling parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Jacob Carlborg wrote:
 I would like to have the possibility to attach attributes to types and
 parameters as well. Some think like this:

 class Bar
 {
  not_null(Foo) bar ( custom int a) {}
 }

 Where  not_null is attached to "Foo" and  custom is attached to "a".
Do you mean return type? I think your syntax has some serious disadvantages. Consider parameters and multiple attributes. For return types I'd like to see something like this: return: not_null return: MyAttr("foo") Foo bar( custom int a) {} return(not_null) return(MyAttr("foo"))
Apr 06 2012
next sibling parent reply Manu <turkeyman gmail.com> writes:
On 6 April 2012 15:38, Piotr Szturmaj <bncrbme jadamspam.pl> wrote:

 Jacob Carlborg wrote:

 I would like to have the possibility to attach attributes to types and
 parameters as well. Some think like this:

 class Bar
 {
  not_null(Foo) bar ( custom int a) {}
 }

 Where  not_null is attached to "Foo" and  custom is attached to "a".
Do you mean return type? I think your syntax has some serious disadvantages. Consider parameters and multiple attributes. For return types I'd like to see something like this: return: not_null return: MyAttr("foo") Foo bar( custom int a) {} return(not_null) return(MyAttr("foo"))
There's no need to attribute a return value. A) I think you're confusing it with attributing *types* again, and B) you can just attribute the function its self, and have access to precisely the same information. You can't attribute a return value, since attributes aren't transferred along with assignments, they are bound to their respective declaration.
Apr 06 2012
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 14:55, Manu wrote:
 On 6 April 2012 15:38, Piotr Szturmaj <bncrbme jadamspam.pl
 <mailto:bncrbme jadamspam.pl>> wrote:

     Jacob Carlborg wrote:

         I would like to have the possibility to attach attributes to
         types and
         parameters as well. Some think like this:

         class Bar
         {
          not_null(Foo) bar ( custom int a) {}
         }

         Where  not_null is attached to "Foo" and  custom is attached to "a".


     Do you mean return type? I think your syntax has some serious
     disadvantages. Consider parameters and multiple attributes.

     For return types I'd like to see something like this:

      return: not_null
      return: MyAttr("foo")
     Foo bar( custom int a) {}



      return(not_null)
      return(MyAttr("foo"))


 There's no need to attribute a return value. A) I think you're confusing
 it with attributing *types* again, and B) you can just attribute the
 function its self, and have access to precisely the same information.
 You can't attribute a return value, since attributes aren't transferred
 along with assignments, they are bound to their respective declaration.
It depends on what we want out of attributes. -- /Jacob Carlborg
Apr 06 2012
prev sibling parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Manu wrote:
 On 6 April 2012 15:38, Piotr Szturmaj <bncrbme jadamspam.pl
     For return types I'd like to see something like this:

      return: not_null
      return: MyAttr("foo")
     Foo bar( custom int a) {}



      return(not_null)
      return(MyAttr("foo"))


 There's no need to attribute a return value. A) I think you're confusing
 it with attributing *types* again, and B) you can just attribute the
 function its self, and have access to precisely the same information.
 You can't attribute a return value, since attributes aren't transferred
 along with assignments, they are bound to their respective declaration.
See http://msdn.microsoft.com/en-us/library/b3787ac0%28v=vs.80%29.aspx Attributes on return values are useful for RPC methods. For example: with attribute, one can specify how return value is serialized/marshalled. type _simultaneously_. I don't think we should limit D ones to functions and parameters.
Apr 06 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-06 14:38, Piotr Szturmaj wrote:

 Do you mean return type? I think your syntax has some serious
 disadvantages. Consider parameters and multiple attributes.

 For return types I'd like to see something like this:

  return: not_null
  return: MyAttr("foo")
 Foo bar( custom int a) {}



  return(not_null)
  return(MyAttr("foo"))
Hmm, or something like how Java does it. You attached this information when you declare the attribute: Retention(RetentionPolicy.RUNTIME) // Make this annotation accessible at runtime via reflection. Target({ElementType.METHOD}) // This annotation can only be applied to class methods. public interface Tweezable { } Or with another syntax: attribute target(type) struct not_null {} -- /Jacob Carlborg
Apr 06 2012
parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Jacob Carlborg wrote:
 On 2012-04-06 14:38, Piotr Szturmaj wrote:

 Do you mean return type? I think your syntax has some serious
 disadvantages. Consider parameters and multiple attributes.

 For return types I'd like to see something like this:

  return: not_null
  return: MyAttr("foo")
 Foo bar( custom int a) {}



  return(not_null)
  return(MyAttr("foo"))
Hmm, or something like how Java does it. You attached this information when you declare the attribute: Retention(RetentionPolicy.RUNTIME) // Make this annotation accessible at runtime via reflection. Target({ElementType.METHOD}) // This annotation can only be applied to class methods. public interface Tweezable { } Or with another syntax: attribute target(type) struct not_null {}
I think that target is a solution for simple types, but UDTs may use another one: struct MyAttr { template Attach(Symbol) { static if (!is(typeof(Symbol) == class) || !is(typeof(Symbol) : A)) static assert(0, "MyAttr must be attached to classes derived from class A"); } } This allows more complex target checking possible. Besides above example, some attributes can be mutually exclusive and __traits(hasAttribute, ...) may be used to check that.
Apr 06 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 06/04/2012 14:23, Jacob Carlborg a écrit :
 On 2012-04-06 05:30, Ary Manzana wrote:

 I don't understand the difference between "storage class" and "type
 constructor". I guess I do. But my answer is the same as deadalnix: they
 are attached to declarations (at compile time).

 Can you give us an example of the confusion that arose? I can't
 understand it without examples.

 I think it should work like this:

  custom
 class Foo {

   custom
 void bar() { }

 void baz() { }
 }

 class Other {}

 __traits(hasAttribute, Foo, 'custom') --> true
 __traits(hasAttribute, Other, 'custom') --> false

 // I have no idea how to iterate the members of Foo, or get a reference
 to the "bar" method... I can't understand what __traits(getMember)
 returns from the docs...
I would like to have the possibility to attach attributes to types and parameters as well. Some think like this: class Bar { not_null(Foo) bar ( custom int a) {} } Where not_null is attached to "Foo" and custom is attached to "a".
As foo isn't a declaration, I don't think it is attribute we want here. Or an extension, because it have a lot of consequences.
Apr 06 2012
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On 5 April 2012 20:35, Walter Bright <newshound2 digitalmars.com> wrote:

 On 4/5/2012 5:00 AM, Manu wrote:


 patterns, I
 don't think there should be any mystery over how they should be
 implemented.
At the Lang.NEXT conference over the last 3 days, I was able to talk to many smart people about attributes. But I did find some confusion - are they best attached to the variable/function (i.e. "storage class"), or attached to the type ("type constructor")? I think the former. Attaching it to the type leads to all sorts of semantic issues. From your list of uses, it looks like attaching it to the variable or function is an apropos solution.
Yes, most certainly the former. The latter is already possible with tricks (a trivial template for instance). An attribute/annotation should associate with select instances/declarations of things. I don't think it should affect the type, although this shows a conceptual problem when referring to existing attributes via the same terminology. Obviously one might consider 'const', 'pure', etc attributes themselves, and they clearly do affect the type. Perhaps that's the key distinction between an ' ' attribute(/'annotation'?), and a no-' ' attribute?
Apr 06 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 11:57 AM, Manu wrote:
 I don't think it should affect the type, although this shows a
 conceptual problem when referring to existing attributes via the same
 terminology. Obviously one might consider 'const', 'pure', etc
 attributes themselves, and they clearly do affect the type.
 Perhaps that's the key distinction between an ' '
 attribute(/'annotation'?), and a no-' ' attribute?
safe affects the type.
Apr 06 2012
parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 13:06, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/06/2012 11:57 AM, Manu wrote:

 I don't think it should affect the type, although this shows a
 conceptual problem when referring to existing attributes via the same
 terminology. Obviously one might consider 'const', 'pure', etc
 attributes themselves, and they clearly do affect the type.
 Perhaps that's the key distinction between an ' '
 attribute(/'annotation'?), and a no-' ' attribute?
safe affects the type.
I realise that, I'm just suggesting this is a possible solution to the confusion... if the distinction were to be made clearly. I guess it's impossible though, can't go claiming 'safe' from the global namespace :)
Apr 06 2012
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-05 14:00, Manu wrote:
 I just want to add more real-world experience to the controversy.
 I'm finding myself needing to use custom attributes almost every day.

 I have numerous systems that need to scan the module for things marked
 accordingly to automate bindings to their respective systems.
Yes, give us custom attributes now :) -- /Jacob Carlborg
Apr 05 2012
parent Mike Parker <aldacron gmail.com> writes:
On 4/6/2012 4:43 AM, Jacob Carlborg wrote:
 On 2012-04-05 14:00, Manu wrote:
 I just want to add more real-world experience to the controversy.
 I'm finding myself needing to use custom attributes almost every day.

 I have numerous systems that need to scan the module for things marked
 accordingly to automate bindings to their respective systems.
Yes, give us custom attributes now :)
Pretty please.
Apr 05 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/5/2012 5:00 AM, Manu wrote:

I
 don't think there should be any mystery over how they should be implemented.
I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
Apr 05 2012
next sibling parent reply "Kapps" <opantm2+spam gmail.com> writes:
On Friday, 6 April 2012 at 06:47:56 UTC, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

design patterns, I
 don't think there should be any mystery over how they should
be implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
I like it for the most part. One thing I'd like to see is placing multiple attributes both by using multiple attr()'s, and by using comma separated identifier/expression pairs inside a single attr. In other words, the following two declarations would be identical. attr(Description = "Blah", ReadOnly) int ID; attr(Description = "Blah") attr(ReadOnly) int ID; My only concerns: First, attr() is a little verbose / not exactly pretty. This isn't really a big issue, since attributes aren't exactly piled on and it makes it easy to tell what's going on. It is a little uglier than in other languages however. Secondly, from what I can tell it's an arbitrary key value combo. What would happen if you're working on a larger project and two unrelated libraries try to use the same attribute name to mean different things? With the module system this issue doesn't exist since you have to import it and can selectively/privately do so, but from what I understand the method you're proposing doesn't declare the attribute itself at all. Am I just misunderstanding this part?
Apr 06 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 12:17 AM, Kapps wrote:
 I like it for the most part. One thing I'd like to see is placing multiple
 attributes both by using multiple  attr()'s, and by using comma separated
 identifier/expression pairs inside a single  attr. In other words, the
following
 two declarations would be identical.

  attr(Description = "Blah", ReadOnly)
 int ID;

  attr(Description = "Blah")
  attr(ReadOnly)
 int ID;
Yes, that makes sense.
 My only concerns:

 First,  attr() is a little verbose / not exactly pretty. This isn't really a
big
 issue, since attributes aren't exactly piled on and it makes it easy to tell
 what's going on. It is a little uglier than in other languages however.
Could do: [[name = value]] I suppose. Not sure what's better.
 Secondly, from what I can tell it's an arbitrary key value combo. What would
 happen if you're working on a larger project and two unrelated libraries try to
 use the same attribute name to mean different things? With the module system
 this issue doesn't exist since you have to import it and can
 selectively/privately do so, but from what I understand the method you're
 proposing doesn't declare the attribute itself at all. Am I just
 misunderstanding this part?
Good question. I don't have experience using attributes, so I don't know if this would be a problem. Keep in mind that the attribute lookup will only be done for a particular symbol, there won't be any global lookup.
Apr 06 2012
next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 06-04-2012 09:32, Walter Bright wrote:
 On 4/6/2012 12:17 AM, Kapps wrote:
 I like it for the most part. One thing I'd like to see is placing
 multiple
 attributes both by using multiple  attr()'s, and by using comma separated
 identifier/expression pairs inside a single  attr. In other words, the
 following
 two declarations would be identical.

  attr(Description = "Blah", ReadOnly)
 int ID;

  attr(Description = "Blah")
  attr(ReadOnly)
 int ID;
Yes, that makes sense.
 My only concerns:

 First,  attr() is a little verbose / not exactly pretty. This isn't
 really a big
 issue, since attributes aren't exactly piled on and it makes it easy
 to tell
 what's going on. It is a little uglier than in other languages however.
Could do: [[name = value]] I suppose. Not sure what's better.
 Secondly, from what I can tell it's an arbitrary key value combo. What
 would
 happen if you're working on a larger project and two unrelated
 libraries try to
 use the same attribute name to mean different things? With the module
 system
 this issue doesn't exist since you have to import it and can
 selectively/privately do so, but from what I understand the method you're
 proposing doesn't declare the attribute itself at all. Am I just
 misunderstanding this part?
Good question. I don't have experience using attributes, so I don't know if this would be a problem. Keep in mind that the attribute lookup will only be done for a particular symbol, there won't be any global lookup.
It actually can be a problem. In .NET land, there are many attributes across many projects (and even in the framework itself) with the same names. It turns out that regular namespace lookup rules alleviate this problem. -- - Alex
Apr 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:
 It actually can be a problem. In .NET land, there are many attributes across
 many projects (and even in the framework itself) with the same names. It turns
 out that regular namespace lookup rules alleviate this problem.
Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
Apr 06 2012
next sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Fri, 06 Apr 2012 00:48:34 -0700
schrieb Walter Bright <newshound2 digitalmars.com>:

 On 4/6/2012 12:35 AM, Alex R=C3=B8nne Petersen wrote:
 It actually can be a problem. In .NET land, there are many
 attributes across many projects (and even in the framework itself)
 with the same names. It turns out that regular namespace lookup
 rules alleviate this problem.
=20 =20 Perhaps a better scheme is: =20 enum foo =3D 3; =20 ... =20 attr(foo) int x; =20 That way, foo will follow all the usual rules. =20
implementation? http://msdn.microsoft.com/en-US/library/48zeb25s(v=3Dvs.80).aspx http://msdn.microsoft.com/en-US/library/sw480ze8(v=3Dvs.100).aspx http://msdn.microsoft.com/en-US/library/z919e8tw(v=3Dvs.80).aspx "disambiguating targets" is necessary. Probably not needed in D): http://msdn.microsoft.com/en-US/library/b3787ac0(v=3Dvs.80).aspx Syntax in D would be different of course, but I see absolutely no need for the redundant (and ugly) attr. Declaring a custom attribute: --------- module std.something; struct Author { string name; public this(string name) { this.name =3D name; } } --------- Using it: --------- import std.something; //Usual namespace lookup rules apply to attributes /* * Author(param) calls the constructor of the Author struct and * attaches the struct instance to test. Probably Author (without * parenthesis) coud be made to mean std.something.Author.init=20 */ Author("Johannes Pfau") int test; --------- Using reflection to get that attribute: --------- if(__traits(hasAttribute, test, std.something.Author)) { Author[] authors =3D __traits(getAttribute, test, std.something.Author); } --------- An array is used here to support attaching the same attribute multiple times. Of course "auto authors =3D ..." should be usable here too.
Apr 06 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 2:41 AM, Johannes Pfau wrote:


 implementation?
Apr 06 2012
next sibling parent Johannes Pfau <nospam example.com> writes:
Am Fri, 06 Apr 2012 03:06:51 -0700
schrieb Walter Bright <newshound2 digitalmars.com>:

 On 4/6/2012 2:41 AM, Johannes Pfau wrote:


 implementation?
OK, but my post was only about the syntax, there's no runtime/compile time specific part in it (the struct's constructor has to be called using CTFE instead of at runtime, but that's the only difference I see)
Apr 06 2012
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/6/12 5:06 AM, Walter Bright wrote:
 On 4/6/2012 2:41 AM, Johannes Pfau wrote:


 implementation?
Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand). Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs. We should use them wherever appropriate. Andrei
Apr 06 2012
next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 06/04/2012 17:00, Andrei Alexandrescu a écrit :
 On 4/6/12 5:06 AM, Walter Bright wrote:
 On 4/6/2012 2:41 AM, Johannes Pfau wrote:


 implementation?
Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand). Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs. We should use them wherever appropriate. Andrei
Again, I rise the need of AOP. No need for runtime attribute or compiler magic if we have AOP that could interleave « clunky D code you wouldn't want to write by hand » without adding yet again another language feature.
Apr 06 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 05:00 PM, Andrei Alexandrescu wrote:
 On 4/6/12 5:06 AM, Walter Bright wrote:
 On 4/6/2012 2:41 AM, Johannes Pfau wrote:


 implementation?
Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand).
What would that look like?
 Lowerings have worked miracles for us in terms of keeping language
 semantics simple and reducing implementation bugs.
What do you have in mind here? All lowerings I am aware of are trivial ones and their implementation resulted in sloppy error handling (eg: foreach) for no clear benefit. Some of them (eg: with statement) have even made the implementation bug situation worse.
 We should use them
 wherever appropriate.


 Andrei
I don't think they are in this case. What will help reducing implementation bugs is that most of their implementation is already covered by the CTFE implementation.
Apr 06 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/6/12 10:09 AM, Timon Gehr wrote:
 Speaking of the distinction, it would be great if we arranged things
 such that attributes are a lowering to existing D (i.e. the compiler
 rewrites a nice attribute syntax into clunky D code you wouldn't want to
 write by hand).
What would that look like?
Essentially we want to associate with any symbol (be it a type, function, method, or whatnot) some extra information in the form of a tuple of key/value pairs. The value can be anything CTFE. How would one do that "by hand", albeit ugly and verbose? Once we get the desired functionality, we work back on a syntax for it. And we're done.
 Lowerings have worked miracles for us in terms of keeping language
 semantics simple and reducing implementation bugs.
What do you have in mind here?
All: foreach, scope, operator overloading - wherever we used lowerings it's been an unqualified success. I am only sorry we didn't use them more often and more systematically.
 All lowerings I am aware of are trivial ones and their implementation
 resulted in sloppy error handling (eg: foreach) for no clear benefit.
Defining foreach as a lowering clarifies to both the library author and the user what the expectations are.
 Some of them (eg: with statement) have even made the implementation bug
 situation worse.
"with" is not implemented via a lowering. Andrei
Apr 06 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 09:15 PM, Andrei Alexandrescu wrote:
 On 4/6/12 10:09 AM, Timon Gehr wrote:
 Speaking of the distinction, it would be great if we arranged things
 such that attributes are a lowering to existing D (i.e. the compiler
 rewrites a nice attribute syntax into clunky D code you wouldn't want to
 write by hand).
What would that look like?
Essentially we want to associate with any symbol (be it a type, function, method, or whatnot) some extra information in the form of a tuple of key/value pairs. The value can be anything CTFE. How would one do that "by hand", albeit ugly and verbose? Once we get the desired functionality, we work back on a syntax for it. And we're done.
There is no existing in-language solution whose only bad property is its ugliness, because it cannot be allowed to introduce additional symbols.
 Lowerings have worked miracles for us in terms of keeping language
 semantics simple and reducing implementation bugs.
What do you have in mind here?
All: foreach, scope, operator overloading - wherever we used lowerings it's been an unqualified success. I am only sorry we didn't use them more often and more systematically.
I think they have been applied where they were appropriate. What other existing language features would you rather have specified as a lowering?
 All lowerings I am aware of are trivial ones and their implementation
 resulted in sloppy error handling (eg: foreach) for no clear benefit.
Defining foreach as a lowering clarifies to both the library author and the user what the expectations are.
Agreed, using lowering custom overloading of language constructs is good. These usages have slipped my mind because they are so different from what we are discussing here. I was thinking about foreach over built in arrays. For example: foreach(double i,x; (int[]).init){} Error: cannot implicitly convert expression (i) of type double to ulong i.e. using lowering for implementation without any additional checks is not a good thing. Anyway, how does the argument apply to the custom attribute case? The specification of how custom attributes work is certainly simpler and more clear than the specification of how the 'code that is too ugly to be written by hand' is generated and getting it right should be comparably difficult for both. The solution that uses a lowering would need additional compiler support for hiding additionally generated symbols. This makes the lowering even harder to follow for someone who wants to get started on custom attributes. It just seems kludgy to me.
Apr 06 2012
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/6/12 2:47 PM, Timon Gehr wrote:
 There is no existing in-language solution whose only bad property is its
 ugliness, because it cannot be allowed to introduce additional symbols.
You can always assume fresh variables even though indeed there's no support for them. Just use __ as prefix and then combine with a cookie and the existing symbol name. There will be no clashes.
 All: foreach, scope, operator overloading - wherever we used lowerings
 it's been an unqualified success. I am only sorry we didn't use them
 more often and more systematically.
I forgot the new lambda syntax ("=>") was defined as a lowering and as a consequence is came virtually bug free.
 I think they have been applied where they were appropriate. What other
 existing language features would you rather have specified as a lowering?
Some array and associative array literals and operations. All object copying.
 Anyway, how does the argument apply to the custom attribute case? The
 specification of how custom attributes work is certainly simpler and
 more clear than the specification of how the 'code that is too ugly to
 be written by hand' is generated and getting it right should be
 comparably difficult for both. The solution that uses a lowering would
 need additional compiler support for hiding additionally generated
 symbols. This makes the lowering even harder to follow for someone who
 wants to get started on custom attributes. It just seems kludgy to me.
Expressing attributes in terms of what they do within attribute-less D is crucial to keeping both definition and implementation simple. Hidden symbols are a non-issue. Andrei
Apr 06 2012
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 11:00:25 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 4/6/12 5:06 AM, Walter Bright wrote:
 On 4/6/2012 2:41 AM, Johannes Pfau wrote:


 implementation?
Speaking of the distinction, it would be great if we arranged things such that attributes are a lowering to existing D (i.e. the compiler rewrites a nice attribute syntax into clunky D code you wouldn't want to write by hand). Lowerings have worked miracles for us in terms of keeping language semantics simple and reducing implementation bugs. We should use them wherever appropriate.
I don't think that applies here. We have no low-level mechanism to affect the compiler internals, which is where attribute metadata belongs. -Steve
Apr 06 2012
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 12:41, Johannes Pfau <nospam example.com> wrote:

 Am Fri, 06 Apr 2012 00:48:34 -0700
 schrieb Walter Bright <newshound2 digitalmars.com>:

 On 4/6/2012 12:35 AM, Alex R=C3=B8nne Petersen wrote:
 It actually can be a problem. In .NET land, there are many
 attributes across many projects (and even in the framework itself)
 with the same names. It turns out that regular namespace lookup
 rules alleviate this problem.
Perhaps a better scheme is: enum foo =3D 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
implementation? http://msdn.microsoft.com/en-US/library/48zeb25s(v=3Dvs.80).aspx http://msdn.microsoft.com/en-US/library/sw480ze8(v=3Dvs.100).aspx http://msdn.microsoft.com/en-US/library/z919e8tw(v=3Dvs.80).aspx "disambiguating targets" is necessary. Probably not needed in D): http://msdn.microsoft.com/en-US/library/b3787ac0(v=3Dvs.80).aspx Syntax in D would be different of course, but I see absolutely no need for the redundant (and ugly) attr. Declaring a custom attribute: --------- module std.something; struct Author { string name; public this(string name) { this.name =3D name; } } --------- Using it: --------- import std.something; //Usual namespace lookup rules apply to attributes /* * Author(param) calls the constructor of the Author struct and * attaches the struct instance to test. Probably Author (without * parenthesis) coud be made to mean std.something.Author.init */ Author("Johannes Pfau") int test; --------- Using reflection to get that attribute: --------- if(__traits(hasAttribute, test, std.something.Author)) { Author[] authors =3D __traits(getAttribute, test, std.something.Author); } --------- An array is used here to support attaching the same attribute multiple times. Of course "auto authors =3D ..." should be usable here too.
+1
Apr 06 2012
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 11:41 AM, Johannes Pfau wrote:
 Syntax in D would be different of course, but I see absolutely no need
 for the redundant (and ugly)  attr.

 Declaring a custom attribute:
 ---------
 module std.something;

 struct Author
 {
      string name;
      public this(string name)
      {
          this.name = name;
      }
 }
 ---------

 Using it:
 ---------
 import std.something; //Usual namespace lookup rules apply to attributes

 /*
   *  Author(param) calls the constructor of the Author struct and
   * attaches the struct instance to test. Probably  Author (without
   * parenthesis) coud be made to mean std.something.Author.init
   */
  Author("Johannes Pfau") int test;
 ---------



 Using reflection to get that attribute:
 ---------
 if(__traits(hasAttribute, test, std.something.Author))
 {
      Author[] authors = __traits(getAttribute, test,
          std.something.Author);
 }
 ---------

 An array is used here to support attaching the same attribute multiple
 times. Of course "auto authors = ..." should be usable here too.
This all seems very reasonable. I think this is how things should work. (maybe syntax will need to be different, because Walter does not seem to like the idea of un-reserving identifier.)
Apr 06 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 06/04/2012 11:41, Johannes Pfau a écrit :
 Am Fri, 06 Apr 2012 00:48:34 -0700
 schrieb Walter Bright<newshound2 digitalmars.com>:

 On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:
 It actually can be a problem. In .NET land, there are many
 attributes across many projects (and even in the framework itself)
 with the same names. It turns out that regular namespace lookup
 rules alleviate this problem.
Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
implementation? http://msdn.microsoft.com/en-US/library/48zeb25s(v=vs.80).aspx http://msdn.microsoft.com/en-US/library/sw480ze8(v=vs.100).aspx http://msdn.microsoft.com/en-US/library/z919e8tw(v=vs.80).aspx "disambiguating targets" is necessary. Probably not needed in D): http://msdn.microsoft.com/en-US/library/b3787ac0(v=vs.80).aspx Syntax in D would be different of course, but I see absolutely no need for the redundant (and ugly) attr. Declaring a custom attribute: --------- module std.something; struct Author { string name; public this(string name) { this.name = name; } } --------- Using it: --------- import std.something; //Usual namespace lookup rules apply to attributes /* * Author(param) calls the constructor of the Author struct and * attaches the struct instance to test. Probably Author (without * parenthesis) coud be made to mean std.something.Author.init */ Author("Johannes Pfau") int test; --------- Using reflection to get that attribute: --------- if(__traits(hasAttribute, test, std.something.Author)) { Author[] authors = __traits(getAttribute, test, std.something.Author); } --------- An array is used here to support attaching the same attribute multiple times. Of course "auto authors = ..." should be usable here too.
That is a really nice proposal !
Apr 06 2012
parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 15:13, deadalnix <deadalnix gmail.com> wrote:

 Le 06/04/2012 11:41, Johannes Pfau a =C3=A9crit :

  Am Fri, 06 Apr 2012 00:48:34 -0700
 schrieb Walter Bright<newshound2 digitalmars.**com<newshound2 digitalmar=
s.com>
:
On 4/6/2012 12:35 AM, Alex R=C3=B8nne Petersen wrote:
 It actually can be a problem. In .NET land, there are many
 attributes across many projects (and even in the framework itself)
 with the same names. It turns out that regular namespace lookup
 rules alleviate this problem.
Perhaps a better scheme is: enum foo =3D 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
implementation? http://msdn.microsoft.com/en-**US/library/48zeb25s(v=3Dvs.80).**aspx<htt=
p://msdn.microsoft.com/en-US/library/48zeb25s(v=3Dvs.80).aspx>
 http://msdn.microsoft.com/en-**US/library/sw480ze8(v=3Dvs.100).**aspx<ht=
tp://msdn.microsoft.com/en-US/library/sw480ze8(v=3Dvs.100).aspx>
 http://msdn.microsoft.com/en-**US/library/z919e8tw(v=3Dvs.80).**aspx<htt=
p://msdn.microsoft.com/en-US/library/z919e8tw(v=3Dvs.80).aspx>

  "disambiguating targets" is necessary. Probably not needed in D):
 http://msdn.microsoft.com/en-**US/library/b3787ac0(v=3Dvs.80).**aspx<htt=
p://msdn.microsoft.com/en-US/library/b3787ac0(v=3Dvs.80).aspx>
 Syntax in D would be different of course, but I see absolutely no need
 for the redundant (and ugly)  attr.

 Declaring a custom attribute:
 ---------
 module std.something;

 struct Author
 {
     string name;
     public this(string name)
     {
         this.name =3D name;
     }
 }
 ---------

 Using it:
 ---------
 import std.something; //Usual namespace lookup rules apply to attributes

 /*
  *  Author(param) calls the constructor of the Author struct and
  * attaches the struct instance to test. Probably  Author (without
  * parenthesis) coud be made to mean std.something.Author.init
  */
  Author("Johannes Pfau") int test;
 ---------



 Using reflection to get that attribute:
 ---------
 if(__traits(hasAttribute, test, std.something.Author))
 {
     Author[] authors =3D __traits(getAttribute, test,
         std.something.Author);
 }
 ---------

 An array is used here to support attaching the same attribute multiple
 times. Of course "auto authors =3D ..." should be usable here too.
That is a really nice proposal !
This is precisely how I have always imagined the system working. Walter: can you comment why you think this is not do-able, or not a good way to go about it?
Apr 06 2012
prev sibling next sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 4/6/12 3:48 PM, Walter Bright wrote:
 On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:
 It actually can be a problem. In .NET land, there are many attributes
 across
 many projects (and even in the framework itself) with the same names.
 It turns
 out that regular namespace lookup rules alleviate this problem.
Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
At least in .Net and Java it's something like this. 1. You declare your attributes. This is something good, because you have a place to say "This attribute is used for marking fields as non-serializable". The syntax in Java for declaring an attribute: public interface Foo { String xxx; int yyy; } In D maybe interface could be used to (in order to avoid introducing another keyword... or maybe use attribute instead): attribute Foo { string xxx; int yyy; } 2. You use them by using their names. What you are proposing if for attribute foo to be attr(foo). But in Java it's foo. So in Java you would use that attribute like this: Foo(xxx = "hello", yyy = 1); void func() {} Then you can get the "Foo" attribute in func, and ask for it's xxx and yyy. --- Now, your proposal is much simpler and it will become inconvenient in some cases. For example suppose you want to provide attributes for serialization (I guess the classic example). With your proposal it would be: /// This is actually an attribute. Use this together with serialized_name. enum serialize = 1; enum serialized_name = 2; attr(serialize = true, serialized_name = "Foo") int x; /// Marks a field to be serialized. attribute serialize { /// The name to be used. /// If not specified, the name of the member will be used instead. string name; } serialize(name = "Foo") int x; You can see the syntax is much cleaner. The attribute declaration also serves as documentation and to group attributes related to the serialization process. Now, to implement this is not very much difficult than what you proposed. 1. Introduce the syntax to define attributes. Piece of cake, since it's much more or less the syntax of a struct, but functions or nested types are not allowed. Parse them into an AttributeDecl or something like that. 2. When the compiler finds attr(field = value) it uses normal lookup rules to find "attr". Then it checks it's an attributes. Then all fields are check in turn to see if their type match. You can probably put there anything that's compile-time evaluatable, though usually primitive types and strings are enough. If a field is not specified, it's type.init will be used. 3. The syntax for querying is almost the same as you proposed: __traits(hasAttribute, x, serializable) // true __traits(getAttribtue, x, serializable, name) // "Foo" 4. Declare the core attributes in object.di or similar: safe, nothrow, etc. You can also document them. 5. Probably deprecate __traits(isSafe) and so on, since hasAttribute can be used for that.
Apr 06 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 2:50 AM, Ary Manzana wrote:
 The syntax in Java for declaring an attribute:

 public  interface Foo {
 String xxx;
 int yyy;
 }

 In D maybe  interface could be used to (in order to avoid introducing another
 keyword... or maybe use  attribute instead):

  attribute Foo {
 string xxx;
 int yyy;
 }
I don't see the need for creating a new kind of symbol.
 2. You use them by using their names. What you are proposing if for attribute
 foo to be  attr(foo). But in Java it's  foo.

 So in Java you would use that attribute like this:

  Foo(xxx = "hello", yyy = 1);
 void func() {}

 Then you can get the "Foo" attribute in func, and ask for it's xxx and yyy.
This is a runtime system.
 Now, your proposal is much simpler and it will become inconvenient in some
 cases. For example suppose you want to provide attributes for serialization (I
 guess the classic example). With your proposal it would be:

 /// This is actually an attribute. Use this together with serialized_name.
 enum serialize = 1;
 enum serialized_name = 2;

  attr(serialize = true, serialized_name = "Foo")
 int x;
No, it would be: enum serialize = true; enum serialize_name = "Foo"; attr(serialize, serialized_name) int x; There would be no initialization in the attr syntax.


 /// Marks a field to be serialized.
  attribute serialize {
 /// The name to be used.
 /// If not specified, the name of the member will be used instead.
 string name;
 }

  serialize(name = "Foo")
 int x;

 You can see the syntax is much cleaner. The attribute declaration also serves
as
 documentation and to group attributes related to the serialization process.
I don't see that it is cleaner - there's no particular reason why a new symbol type needs to be introduced.
 Now, to implement this is not very much difficult than what you proposed.

 1. Introduce the syntax to define attributes. Piece of cake, since it's much
 more or less the syntax of a struct, but functions or nested types are not
 allowed. Parse them into an AttributeDecl or something like that.
 2. When the compiler finds  attr(field = value) it uses normal lookup rules to
 find "attr". Then it checks it's an attributes. Then all fields are check in
 turn to see if their type match. You can probably put there anything that's
 compile-time evaluatable, though usually primitive types and strings are
enough.
 If a field is not specified, it's type.init will be used.
 3. The syntax for querying is almost the same as you proposed:

 __traits(hasAttribute, x, serializable) // true
 __traits(getAttribtue, x, serializable, name) // "Foo"

 4. Declare the core attributes in object.di or similar:  safe,  nothrow, etc.
 You can also document them.
 5. Probably deprecate __traits(isSafe) and so on, since hasAttribute can be
used
 for that.
safe, nothrow, etc., require a lot of semantic support in the compiler. They cannot pretend to be user defined attributes.
Apr 06 2012
next sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 4/6/12 6:12 PM, Walter Bright wrote:
 On 4/6/2012 2:50 AM, Ary Manzana wrote:
 The syntax in Java for declaring an attribute:

 public  interface Foo {
 String xxx;
 int yyy;
 }

 In D maybe  interface could be used to (in order to avoid introducing
 another
 keyword... or maybe use  attribute instead):

  attribute Foo {
 string xxx;
 int yyy;
 }
I don't see the need for creating a new kind of symbol.
 2. You use them by using their names. What you are proposing if for
 attribute
 foo to be  attr(foo). But in Java it's  foo.

 So in Java you would use that attribute like this:

  Foo(xxx = "hello", yyy = 1);
 void func() {}

 Then you can get the "Foo" attribute in func, and ask for it's xxx and
 yyy.
This is a runtime system.
Yes, but I'm thinking about a compile-time system (as I showed in the example usages below).
 Now, your proposal is much simpler and it will become inconvenient in
 some
 cases. For example suppose you want to provide attributes for
 serialization (I
 guess the classic example). With your proposal it would be:

 /// This is actually an attribute. Use this together with
 serialized_name.
 enum serialize = 1;
 enum serialized_name = 2;

  attr(serialize = true, serialized_name = "Foo")
 int x;
No, it would be: enum serialize = true; enum serialize_name = "Foo"; attr(serialize, serialized_name) int x; There would be no initialization in the attr syntax.
Hmmm... I didn't get that quite well. You are using the symbol's name as the attribute name? In my example I missed splitting it into two files: my_attributes.d: attribute serialize { } my_usage_of_it.d: import my_attributes; serialize(...)


 /// Marks a field to be serialized.
  attribute serialize {
 /// The name to be used.
 /// If not specified, the name of the member will be used instead.
 string name;
 }

  serialize(name = "Foo")
 int x;

 You can see the syntax is much cleaner. The attribute declaration also
 serves as
 documentation and to group attributes related to the serialization
 process.
I don't see that it is cleaner - there's no particular reason why a new symbol type needs to be introduced.
 Now, to implement this is not very much difficult than what you proposed.

 1. Introduce the syntax to define attributes. Piece of cake, since
 it's much
 more or less the syntax of a struct, but functions or nested types are
 not
 allowed. Parse them into an AttributeDecl or something like that.
 2. When the compiler finds  attr(field = value) it uses normal lookup
 rules to
 find "attr". Then it checks it's an attributes. Then all fields are
 check in
 turn to see if their type match. You can probably put there anything
 that's
 compile-time evaluatable, though usually primitive types and strings
 are enough.
 If a field is not specified, it's type.init will be used.
 3. The syntax for querying is almost the same as you proposed:

 __traits(hasAttribute, x, serializable) // true
 __traits(getAttribtue, x, serializable, name) // "Foo"

 4. Declare the core attributes in object.di or similar:  safe,
  nothrow, etc.
 You can also document them.
 5. Probably deprecate __traits(isSafe) and so on, since hasAttribute
 can be used
 for that.
safe, nothrow, etc., require a lot of semantic support in the compiler. They cannot pretend to be user defined attributes.
pretending to be an interface and has semantic support in the compiler.
Apr 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 3:27 AM, Ary Manzana wrote:
  safe,  nothrow, etc., require a lot of semantic support in the
 compiler. They cannot pretend to be user defined attributes.
pretending to be an interface and has semantic support in the compiler.
All the semantics of safe are in the compiler. None of it can be user defined. There's just no point to trying to make it user defined. It's like trying to make int user defined. IUnknown's semantics are nearly all user-defined.
Apr 06 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 12:53 PM, Walter Bright wrote:
 On 4/6/2012 3:27 AM, Ary Manzana wrote:
  safe,  nothrow, etc., require a lot of semantic support in the
 compiler. They cannot pretend to be user defined attributes.
pretending to be an interface and has semantic support in the compiler.
All the semantics of safe are in the compiler. None of it can be user defined. There's just no point to trying to make it user defined. It's like trying to make int user defined. IUnknown's semantics are nearly all user-defined.
The proposal is not to make the semantics of safe user defined. I think he proposes to make 'safe' a symbol that is looked up like an user defined symbol. Some languages do the same for the built-in integer type.
Apr 06 2012
parent Ary Manzana <ary esperanto.org.ar> writes:
On 4/6/12 7:09 PM, Timon Gehr wrote:
 On 04/06/2012 12:53 PM, Walter Bright wrote:
 On 4/6/2012 3:27 AM, Ary Manzana wrote:
  safe,  nothrow, etc., require a lot of semantic support in the
 compiler. They cannot pretend to be user defined attributes.
pretending to be an interface and has semantic support in the compiler.
All the semantics of safe are in the compiler. None of it can be user defined. There's just no point to trying to make it user defined. It's like trying to make int user defined. IUnknown's semantics are nearly all user-defined.
The proposal is not to make the semantics of safe user defined. I think he proposes to make 'safe' a symbol that is looked up like an user defined symbol. Some languages do the same for the built-in integer type.
The compiler does the same for TypeInfo, TypeInfo_ClassDeclaration or what ever, Object, etc. I'm just proposing safe to be seen as a user-defined attribute, but implemented in the compiler with special semantic. I'm saying it so that lookup rules become easier: just search. No special cases like "if the attribute name is safe". Of course, treat the special cases later inside the compiler code.
Apr 06 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 12:12 PM, Walter Bright wrote:
 On 4/6/2012 2:50 AM, Ary Manzana wrote:
 The syntax in Java for declaring an attribute:

 public  interface Foo {
 String xxx;
 int yyy;
 }

 In D maybe  interface could be used to (in order to avoid introducing
 another
 keyword... or maybe use  attribute instead):

  attribute Foo {
 string xxx;
 int yyy;
 }
I don't see the need for creating a new kind of symbol.
It would behave like a struct anyway. The issue is whether any struct should be allowed to be used as an attribute, or whether a runtime instance of an attribute can be created. Syntax could just as well be this: attribute struct Foo { // ... }
 2. You use them by using their names. What you are proposing if for
 attribute
 foo to be  attr(foo). But in Java it's  foo.

 So in Java you would use that attribute like this:

  Foo(xxx = "hello", yyy = 1);
 void func() {}

 Then you can get the "Foo" attribute in func, and ask for it's xxx and
 yyy.
This is a runtime system.
In Java, yes. But the general scheme works well even at compile time. It is possible to evaluate struct constructors at compile time. enum Foo attr = __traits(getAttribute, func, Foo);
 Now, your proposal is much simpler and it will become inconvenient in
 some
 cases. For example suppose you want to provide attributes for
 serialization (I
 guess the classic example). With your proposal it would be:

 /// This is actually an attribute. Use this together with
 serialized_name.
 enum serialize = 1;
 enum serialized_name = 2;

  attr(serialize = true, serialized_name = "Foo")
 int x;
No, it would be: enum serialize = true; enum serialize_name = "Foo"; attr(serialize, serialized_name) int x;
I don't see how that would work. Do you propose to define attributes based on the mapping of the name of random manifest constants to their value? That would be a kludgy hack.
 There would be no initialization in the  attr syntax.



 /// Marks a field to be serialized.
  attribute serialize {
 /// The name to be used.
 /// If not specified, the name of the member will be used instead.
 string name;
 }

  serialize(name = "Foo")
 int x;

 You can see the syntax is much cleaner. The attribute declaration also
 serves as
 documentation and to group attributes related to the serialization
 process.
I don't see that it is cleaner
I think it is cleaner on a conceptual level, even if the syntax was attr(serialize("Foo"))
 - there's no particular reason why a new
 symbol type needs to be introduced.
There is not strictly a need for a _new_ symbol type, but attribute lookup should definitely be symbol based and not string/value based. Why would there be any benefit in bypassing the module system for user defined attributes?
Apr 06 2012
parent Ary Manzana <ary esperanto.org.ar> writes:
On 4/6/12 6:29 PM, Timon Gehr wrote:
 On 04/06/2012 12:12 PM, Walter Bright wrote:
 On 4/6/2012 2:50 AM, Ary Manzana wrote:
 The syntax in Java for declaring an attribute:

 public  interface Foo {
 String xxx;
 int yyy;
 }

 In D maybe  interface could be used to (in order to avoid introducing
 another
 keyword... or maybe use  attribute instead):

  attribute Foo {
 string xxx;
 int yyy;
 }
I don't see the need for creating a new kind of symbol.
It would behave like a struct anyway. The issue is whether any struct should be allowed to be used as an attribute, or whether a runtime instance of an attribute can be created. Syntax could just as well be this: attribute struct Foo { // ... }
True, I struct can be fine. And I don't see any problem in using it in runtime. Though I'm sure nobody would like it to remain in the obj file if it's only used at compile time...
Apr 06 2012
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 13:12, Walter Bright <newshound2 digitalmars.com> wrote:

 On 4/6/2012 2:50 AM, Ary Manzana wrote:

 The syntax in Java for declaring an attribute:

 public  interface Foo {
 String xxx;
 int yyy;
 }

 In D maybe  interface could be used to (in order to avoid introducing
 another
 keyword... or maybe use  attribute instead):

  attribute Foo {
 string xxx;
 int yyy;
 }
I don't see the need for creating a new kind of symbol.
I don't think it's necessary to declare the struct as attribute explicitly, the ' ' can easily imply the usage all on its own in the declaration. The struct would remain a perfectly normal struct, and will be useful if you want to get a struct somewhere in the code to inspect details about the attribute. SomeStruct(blah) int x; .. SomeStruct s = __traits(getAttribute, SomeStruct, x); ... do some stuff with the information that x was attributed static if(s.thing == ??)
 2. You use them by using their names. What you are proposing if for
 attribute
 foo to be  attr(foo). But in Java it's  foo.

 So in Java you would use that attribute like this:

  Foo(xxx = "hello", yyy = 1);
 void func() {}

 Then you can get the "Foo" attribute in func, and ask for it's xxx and
 yyy.
This is a runtime system.
It doesn't need to be runtime. The syntax works perfectly at compile time? Now, your proposal is much simpler and it will become inconvenient in some
 cases. For example suppose you want to provide attributes for
 serialization (I
 guess the classic example). With your proposal it would be:

 /// This is actually an attribute. Use this together with serialized_name.
 enum serialize = 1;
 enum serialized_name = 2;

  attr(serialize = true, serialized_name = "Foo")
 int x;
No, it would be: enum serialize = true; enum serialize_name = "Foo"; attr(serialize, serialized_name) int x; There would be no initialization in the attr syntax.
Please don't. We've gone from a minor case of bracket spam now to a whole bunch of extra lines for every single member, and you've also removed the tight syntactical connection of the values from their attribute declaration (one of the most important details, its safety, when people update/edit classes). This is fast approaching the disconnected enum table which is the whole thing we're trying to avoid. There's also a namespace/scope problem here. 2 different systems from 2 different libraries will almost certainly use the 'serialise' attribute.
 /// Marks a field to be serialized.
  attribute serialize {
 /// The name to be used.
 /// If not specified, the name of the member will be used instead.
 string name;
 }

  serialize(name = "Foo")
 int x;

 You can see the syntax is much cleaner. The attribute declaration also
 serves as
 documentation and to group attributes related to the serialization
 process.
I don't see that it is cleaner - there's no particular reason why a new symbol type needs to be introduced.
See my point above, I don't think there's any need for a new symbol type... The compiler would just keep a little table of attributes alongside declarations, which you can query if you want to.
Apr 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 12:12, Walter Bright wrote:

 I don't see the need for creating a new kind of symbol.
If you create a new symbol, i.e. "Foo" then it would obey the normal look up rules.
 This is a runtime system.
Says who? It doesn't need to be in D.
 I don't see that it is cleaner - there's no particular reason why a new
 symbol type needs to be introduced.
For attributes with a single value this syntax sugar can be allowed (and is in Java): serialize("Foo") int x; I think that is clean. -- /Jacob Carlborg
Apr 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 11:50, Ary Manzana wrote:
 On 4/6/12 3:48 PM, Walter Bright wrote:
 On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:
 It actually can be a problem. In .NET land, there are many attributes
 across
 many projects (and even in the framework itself) with the same names.
 It turns
 out that regular namespace lookup rules alleviate this problem.
Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
At least in .Net and Java it's something like this. 1. You declare your attributes. This is something good, because you have a place to say "This attribute is used for marking fields as non-serializable".
This is much better, as I've said before. -- /Jacob Carlborg
Apr 06 2012
prev sibling next sibling parent reply Manu <turkeyman gmail.com> writes:
On 6 April 2012 10:48, Walter Bright <newshound2 digitalmars.com> wrote:

 On 4/6/2012 12:35 AM, Alex R=C3=B8nne Petersen wrote:

 It actually can be a problem. In .NET land, there are many attributes
 across
 many projects (and even in the framework itself) with the same names. It
 turns
 out that regular namespace lookup rules alleviate this problem.
Perhaps a better scheme is: enum foo =3D 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
What about: struct editor { this(string name, EditType, Colour =3D Colour.Default, string description= =3D null) { //... } blah blah blah } attr(editor("thing",...blah...)) I don't see the advantage over: editor(...) ?
Apr 06 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 3:23 AM, Manu wrote:
 What about:

 struct editor
 {
    this(string name, EditType, Colour = Colour.Default, string description =
null)
    {
      //...
    }

    blah blah blah
 }

  attr(editor("thing",...blah...))
Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?
 I don't see the advantage over:
  editor(...)

 ?
Name collisions with other attributes.
Apr 06 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 12:28 PM, Walter Bright wrote:
 On 4/6/2012 3:23 AM, Manu wrote:
 What about:

 struct editor
 {
 this(string name, EditType, Colour = Colour.Default, string
 description = null)
 {
 //...
 }

 blah blah blah
 }

  attr(editor("thing",...blah...))
Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?
Yes, allowing the arguments to be different is a crucial feature. Custom attributes are not a boolean thing, that is just the case for built-in ones. They are arbitrary data that is attached to a declaration and can then be used to build powerful semantics using compile time reflection.
 I don't see the advantage over:
  editor(...)

 ?
Name collisions with other attributes.
Which other attributes? Built-in ones? Otherwise, the D module system will be great at disambiguating the collisions as soon as inaccessible private symbols do not participate in symbol name collisions any more. Maybe we could just keep all the lower case attributes reserved in order to be future proof.
Apr 06 2012
parent Johannes Pfau <nospam example.com> writes:
Am Fri, 06 Apr 2012 12:43:27 +0200
schrieb Timon Gehr <timon.gehr gmx.ch>:

 On 04/06/2012 12:28 PM, Walter Bright wrote:
 On 4/6/2012 3:23 AM, Manu wrote:
 I don't see the advantage over:
  editor(...)

 ?
Name collisions with other attributes.
Which other attributes? Built-in ones? Otherwise, the D module system will be great at disambiguating the collisions as soon as inaccessible private symbols do not participate in symbol name collisions any more. Maybe we could just keep all the lower case attributes reserved in order to be future proof.
Or add a reserved pseudo-namespace (like e.g 'builtin') for compiler defined attributes and use normal namespace resolution for those: safe <=> builtin.safe
Apr 06 2012
prev sibling next sibling parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Walter Bright wrote:
 Are you really changing the arguments for every declaration? Or is it
 one set that is repeated everywhere?
The former.
 I don't see the advantage over:
  editor(...)

 ?
Name collisions with other attributes.
The same applies to other identifiers, like class named "class". NET has predefined attributes too, but they use the same syntax as the custom ones: [MyAttr(5)] int x; I think MyAttr(5) declaration looks more readable than attr(MyAttr(5)). To avoid name clashes, in case of using builtin name, qualified identifier should be used: myModule.pure pure void fn() {}
Apr 06 2012
parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Piotr Szturmaj wrote:
  myModule.pure
  pure
 void fn() {}
should be: myModule.safe safe void fn() {}
Apr 06 2012
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 13:28, Walter Bright <newshound2 digitalmars.com> wrote:

 On 4/6/2012 3:23 AM, Manu wrote:

 What about:

 struct editor
 {
   this(string name, EditType, Colour = Colour.Default, string description
 = null)
   {
     //...
   }

   blah blah blah
 }

  attr(editor("thing",...blah..**.))
Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?
Of course, what's the point otherwise? This is the very definition of annotation. Everything needs to be exposed in the editor differently. The power of attributes are that they are tightly syntactically bound to the items they attribute. Nobody can change any class/struct without having the syntax force them to make any necessary corrections to their attributes too. I don't see the advantage over:
  editor(...)

 ?
Name collisions with other attributes.
If they were declared as normal structs, they would follow normal namespace rules. company.lib.MyAttribute(...) should also be a valid expression. The only collisions are trusted, safe... I think programmers can handle a few reserved keywords. I already can't go and name a variable whatever I want for the same reason: int private = 10;
Apr 06 2012
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-06 12:28, Walter Bright wrote:

 Name collisions with other   attributes.
Just as we have today with keywords and symbols, I don't see the problem. -- /Jacob Carlborg
Apr 06 2012
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 6 April 2012 at 12:52:27 UTC, Jacob Carlborg wrote:
 Just as we have today with keywords and symbols, I don't see 
 the problem.
Things like safe aren't keywords though. They are just magic identifiers. Think of the implementation: switch(tok.ident) { case Id::safe: case Id::property: // etc for built ins default: // handle user ones here } If you were to define a struct safe {}, which is perfectly legal D, and try to use it, you won't get what you expect. It will trigger the case safe before it goes to the default. So, the user defined one will just be quietly hidden.
Apr 06 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 15:48, Adam D. Ruppe wrote:
 On Friday, 6 April 2012 at 12:52:27 UTC, Jacob Carlborg wrote:
 Just as we have today with keywords and symbols, I don't see the problem.
Things like safe aren't keywords though. They are just magic identifiers. Think of the implementation: switch(tok.ident) { case Id::safe: case Id::property: // etc for built ins default: // handle user ones here } If you were to define a struct safe {}, which is perfectly legal D, and try to use it, you won't get what you expect. It will trigger the case safe before it goes to the default. So, the user defined one will just be quietly hidden.
I mean that "int" is a keyword and "int" is in the same "scope" as the rest of the symbols. So if we allow custom attributes, like " foo", it's the same "problem" as with regular identifiers. Regular identifiers can conflict with keywords. -- /Jacob Carlborg
Apr 07 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 06/04/2012 12:28, Walter Bright a écrit :
 On 4/6/2012 3:23 AM, Manu wrote:
 What about:

 struct editor
 {
 this(string name, EditType, Colour = Colour.Default, string
 description = null)
 {
 //...
 }

 blah blah blah
 }

  attr(editor("thing",...blah...))
Are you really changing the arguments for every declaration? Or is it one set that is repeated everywhere?
 I don't see the advantage over:
  editor(...)

 ?
Name collisions with other attributes.
That isn't a good argument IMO. We have type int and user defined types. I cannot do struct int {}. Same for safe or property or any other language defined property.
Apr 06 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 06/04/2012 12:23, Manu a écrit :
 On 6 April 2012 10:48, Walter Bright <newshound2 digitalmars.com
 <mailto:newshound2 digitalmars.com>> wrote:

     On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:

         It actually can be a problem. In .NET land, there are many
         attributes across
         many projects (and even in the framework itself) with the same
         names. It turns
         out that regular namespace lookup rules alleviate this problem.



     Perhaps a better scheme is:

        enum foo = 3;

        ...

         attr(foo) int x;

     That way, foo will follow all the usual rules.


 What about:

 struct editor
 {
    this(string name, EditType, Colour = Colour.Default, string
 description = null)
    {
      //...
    }

    blah blah blah
 }

  attr(editor("thing",...blah...))

 I don't see the advantage over:
  editor(...)

 ?
+1 I see no additional benefit for this. D have very good lookup rules for looking symbols into modules, so let's use them.
Apr 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 09:48, Walter Bright wrote:
 On 4/6/2012 12:35 AM, Alex Rønne Petersen wrote:
 It actually can be a problem. In .NET land, there are many attributes
 across
 many projects (and even in the framework itself) with the same names.
 It turns
 out that regular namespace lookup rules alleviate this problem.
Perhaps a better scheme is: enum foo = 3; ... attr(foo) int x; That way, foo will follow all the usual rules.
What would "3" do in this case? Be the value of the attribute? -- /Jacob Carlborg
Apr 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 09:32, Walter Bright wrote:
 Could do:

 [[name = value]]

 I suppose. Not sure what's better.
No. See my other reply. -- /Jacob Carlborg
Apr 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 09:17, Kapps wrote:

 Secondly, from what I can tell it's an arbitrary key value combo. What
 would happen if you're working on a larger project and two unrelated
 libraries try to use the same attribute name to mean different things?
 With the module system this issue doesn't exist since you have to import
 it and can selectively/privately do so, but from what I understand the
 method you're proposing doesn't declare the attribute itself at all. Am
 I just misunderstanding this part?
The way I'm thinking of attributes is that they are declared, somehow, in a module. Since it's declared in a module it would have the same rules any other declared symbol, with the possibility to use a fully qualified name. -- /Jacob Carlborg
Apr 06 2012
prev sibling next sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 06-04-2012 08:47, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
  > don't think there should be any mystery over how they should be
 implemented.

 I was thinking of something along the lines of what has been proposed
 here earlier:

  attr(identifier = expression)

 as a storage class, like:

  attr(foo = bar + 1) int x;

 and then:

 __traits(hasAttribute, x, foo)

 would return true, and:

 __traits(getAttribute, x, foo)

 would return the expression (bar+1). The expression would be
 compile-time only, evaluated at the point of declaration.

 The implementation is simple enough, just attach to each symbol an array
 of (identifier,expression) pairs.

 You could also omit the expression, and just have:

  attr(bar) int y;
I think this is mostly reasonable. I assume that it would be possible to use the comma operator to attach multiple values to it? I.e.: attr(foo = bar, baz) int x; My only other concern is what Kapps pointed out about larger projects and overlapping attribute names. -- - Alex
Apr 06 2012
prev sibling next sibling parent reply "Bernard Helyer" <b.helyer gmail.com> writes:
On Friday, 6 April 2012 at 06:47:56 UTC, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

design patterns, I
 don't think there should be any mystery over how they should
be implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
I like it. Perhaps attr(bar) could be equivalent to attr(bar = true) so you don't get any weird failure state for __traits(getAttribute?
Apr 06 2012
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 12:31 AM, Bernard Helyer wrote:
 I like it. Perhaps

  attr(bar)

 could be equivalent to

  attr(bar = true)

 so you don't get any weird failure state for __traits(getAttribute?
That's what the hasAttribute is for.
Apr 06 2012
prev sibling parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 06-04-2012 09:31, Bernard Helyer wrote:
 On Friday, 6 April 2012 at 06:47:56 UTC, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

design patterns, I
 don't think there should be any mystery over how they should
be implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
I like it. Perhaps attr(bar) could be equivalent to attr(bar = true) so you don't get any weird failure state for __traits(getAttribute?
While I understand the rationale, that seems a bit too "magic"... -- - Alex
Apr 06 2012
prev sibling next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 06-04-2012 08:47, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
  > don't think there should be any mystery over how they should be
 implemented.

 I was thinking of something along the lines of what has been proposed
 here earlier:

  attr(identifier = expression)

 as a storage class, like:

  attr(foo = bar + 1) int x;

 and then:

 __traits(hasAttribute, x, foo)

 would return true, and:

 __traits(getAttribute, x, foo)

 would return the expression (bar+1). The expression would be
 compile-time only, evaluated at the point of declaration.

 The implementation is simple enough, just attach to each symbol an array
 of (identifier,expression) pairs.

 You could also omit the expression, and just have:

  attr(bar) int y;
Also, by storage class do you mean it will work only on fields? Attributes are very useful on many different kinds of declarations, so if that's the case, I think that would be too limiting. -- - Alex
Apr 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 12:42 AM, Alex Rønne Petersen wrote:
 Also, by storage class do you mean it will work only on fields?
No. Storage classes work on fields, functions, and variables.
Apr 06 2012
next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 06-04-2012 09:47, Walter Bright wrote:
 On 4/6/2012 12:42 AM, Alex Rønne Petersen wrote:
 Also, by storage class do you mean it will work only on fields?
No. Storage classes work on fields, functions, and variables.
What about type declarations? I think those ought to be supported too. E.g. it makes sense to mark an entire type as attr(serializable) (or the inverse). -- - Alex
Apr 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too. E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
Apr 06 2012
next sibling parent reply =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 06-04-2012 09:54, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
To be clear, I don't want annotations on a type declaration to actually affect the type. Annotations are just that: Annotations. Nothing else. Does a design like that still give rise to the semantic issues you mentioned (it isn't clear what those are)? -- - Alex
Apr 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 1:15 AM, Alex Rønne Petersen wrote:
 On 06-04-2012 09:54, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
To be clear, I don't want annotations on a type declaration to actually affect the type. Annotations are just that: Annotations. Nothing else.
What would an annotation on a type mean if it does not affect the type? Would it just be baggage carried along? If so, how would that affect types inside of a template, where the type was passed as a type constructor? How would type inference work? Would an alias carry or drop the baggage? How would overloading work? How would covariance work? It's a maze of complex decisions.
 Does a design like that still give rise to the semantic issues you mentioned
(it
 isn't clear what those are)?
Yes. (I know Java does this. But Java has a trivial type system compared with D. It doesn't even have type aliases. It doesn't have type constructors. Etc.)
Apr 06 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 12:16 PM, Walter Bright wrote:
 On 4/6/2012 1:15 AM, Alex Rønne Petersen wrote:
 On 06-04-2012 09:54, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
To be clear, I don't want annotations on a type declaration to actually affect the type. Annotations are just that: Annotations. Nothing else.
What would an annotation on a type mean if it does not affect the type?
I don't get that either, it has to affect the type. It does not have any effects on the semantics of instances on the type though. Name mangling can stay the same though.
 Would it just be baggage carried along?
Yes.
 If so, how would that affect types inside of a template, where the type was
passed as a type
 constructor?
How do you pass a type as a type constructor?
 How would type inference work?
Just as it does now.
 Would an alias carry or drop the baggage?
Carry. An alias does not change the referenced symbol.
 How would overloading work?
 How would covariance work?
As they do now. Custom attributes don't have semantic meaning recognised by the compiler. They are just data.
 It's a maze of complex decisions.
I think you can add a list of annotations to the class in the AST that represents a declaration (the common superclass of all declarations) and everything will just work.
 Does a design like that still give rise to the semantic issues you
 mentioned (it
 isn't clear what those are)?
Yes. (I know Java does this. But Java has a trivial type system compared with D. It doesn't even have type aliases. It doesn't have type constructors. Etc.)
I think there is some sort of communication problem, because the feature that is being requested is quite simple. It would probably be valuable if you could point out the issues you see in detail (using example code.)
Apr 06 2012
parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 14:03, Timon Gehr <timon.gehr gmx.ch> wrote:
 It's a maze of complex decisions.

 I think you can add a list of annotations to the class in the AST that
 represents a declaration (the common superclass of all declarations) and
 everything will just work.
Yeah, I always imagined it being about that simple too... are you able to proof the concept? (I know Java does this. But Java has a trivial type system compared with
 D. It doesn't even have type aliases. It doesn't have type constructors.
 Etc.)
I think there is some sort of communication problem, because the feature that is being requested is quite simple. It would probably be valuable if you could point out the issues you see in detail (using example code.)
Indeed.
Apr 06 2012
prev sibling next sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 4/6/12 3:54 PM, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
What's the difference between "type constructor" and "storage class" beside the name?
Apr 06 2012
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 2:18 AM, Ary Manzana wrote:
 On 4/6/12 3:54 PM, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
What's the difference between "type constructor" and "storage class" beside the name?
static const(int)* foo; static is a storage class. const is a type constructor. There is no type 'static'.
Apr 06 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 12:17 PM, Walter Bright wrote:
 On 4/6/2012 2:18 AM, Ary Manzana wrote:
 On 4/6/12 3:54 PM, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
What's the difference between "type constructor" and "storage class" beside the name?
static const(int)* foo; static is a storage class. const is a type constructor. There is no type 'static'.
Still, the 'static' in static struct S{ // ... } Affects S. Correct?
Apr 06 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 06/04/2012 12:17, Walter Bright a écrit :
 On 4/6/2012 2:18 AM, Ary Manzana wrote:
 On 4/6/12 3:54 PM, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
What's the difference between "type constructor" and "storage class" beside the name?
static const(int)* foo; static is a storage class. const is a type constructor. There is no type 'static'.
Why can't attribute be attached on declaration ? By the way, this whole qualify the type or something is a big misfeature. annotation should be attached to the declared stuff. attr Bar foo() { return Bar(); } is qualifying « foo ». Qualifying bar make no sense whatsoever.
Apr 06 2012
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 04/06/12 11:18, Ary Manzana wrote:
 On 4/6/12 3:54 PM, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
What's the difference between "type constructor" and "storage class" beside the name?
attr(deprecated) struct T { int blah; } // every instance of S now marked with it. struct S { int blah; } attr(deprecated) S si; // just si marked; think "static S si;" etc I actually don't like the proposed scheme - it's both way to verbose and not nearly sufficient. I have to leave soon and don't have the time to fully describe the problems, but just a few key points: - Both of the above should work; the "storage class" is the more important part. Wouldn't just having the type-attributes automatically propagate (as a default "storage class") to the instances, w/o affecting the type in any way, be enough? - If the above would work, then there has to be a way to remove an attribute from some instances. - Attributes needs to be declared in some way, otherwise a typo will go undetected and you may not notice it until it's too late. Think " attr(serialisable)" etc - Attributes need to be mergeable, ie you really don't want to mark a significant number of symbols as serializable, exported-to-X, exported-to-Y etc. Something like "alias attr("serializable", "export_X", "export_Y") new_attr"; attr(new_attr) int i;" might work. - At the very least "__traits(getAttribute, x, foo)" needs to be something like "__traits( attr, x, foo); even better would be "x. attr("foo");". - Should attributes be strings? That would avoid clashes with keywords. OTOH that would mean that attribute definitions needs to use different syntax than plain structs. Hmm, maybe that would be a good thing anyway. - Namespaces. There needs to be a system NS and a compiler-specific NS. So that you can do things like attr(__GNU, "flatten", "hot") instead of "pragma(GNU_attribute, flatten, hot)". - Null/empty attributes, ie "alias attr() new_attr;", should work; necessary eg when the compiler lacks support for certain features. There are probably many more issues, these are just the few obvious ones that immediately come to mind. artur
Apr 06 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 09:54 AM, Walter Bright wrote:
 On 4/6/2012 12:49 AM, Alex Rønne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
I think what was discussed there is that attr(foo) int x; Wouldn't change the type of x. attr(foo) struct Foo{} Should add additional information to the type Foo. I don't see any issues with it, and not supporting it would be very strange.
Apr 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 2:54 AM, Timon Gehr wrote:
 Should add additional information to the type Foo. I don't see any issues with
 it, and not supporting it would be very strange.
How would: attr(foo) int x; int y; work? Are x and y the same type or not? Now, consider: auto c = b ? x : y; What type does c have? int or attr(foo)int ? And that's really just the beginning. How about: struct S(T) { T t; } Instantiate it with S!int and S!( attr(foo)int). Are those the same instantiation, or different? If the same, does S.t have the attribute or not? And, whatever you choose for the semantics, what is the sensible, intuitive rule for it?
Apr 06 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/06/2012 12:23 PM, Walter Bright wrote:
 On 4/6/2012 2:54 AM, Timon Gehr wrote:
 Should add additional information to the type Foo. I don't see any
 issues with
 it, and not supporting it would be very strange.
How would: attr(foo) int x; int y; work? Are x and y the same type or not?
Yes, they are. (But a future extension might leave this choice up to 'foo')
 Now, consider:

 auto c = b ? x : y;

 What type does c have? int or  attr(foo)int ? And that's really just the
 beginning. How about:

 struct S(T) {
 T t;
 }

 Instantiate it with S!int and S!( attr(foo)int). Are those the same
 instantiation, or different? If the same, does S.t have the attribute or
 not?
There is no such thing as an attr(foo) int, because attr is not a type constructor.
 And, whatever you choose for the semantics, what is the sensible,
 intuitive rule for it?
Custom attributes apply to the symbol declaration. Because any symbol is declared just once, there is never any ambiguity. There is no conceptual gap between attr(foo) int x; and attr(bar) struct S{...} Obviously attr(bar) changes S, but there is only one declaration of S.
Apr 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 3:49 AM, Timon Gehr wrote:
 On 04/06/2012 12:23 PM, Walter Bright wrote:
 On 4/6/2012 2:54 AM, Timon Gehr wrote:
 Should add additional information to the type Foo. I don't see any
 issues with
 it, and not supporting it would be very strange.
How would: attr(foo) int x; int y; work? Are x and y the same type or not?
Yes, they are. (But a future extension might leave this choice up to 'foo')
 Now, consider:

 auto c = b ? x : y;

 What type does c have? int or  attr(foo)int ? And that's really just the
 beginning. How about:

 struct S(T) {
 T t;
 }

 Instantiate it with S!int and S!( attr(foo)int). Are those the same
 instantiation, or different? If the same, does S.t have the attribute or
 not?
There is no such thing as an attr(foo) int, because attr is not a type constructor.
But you said it was added to the *type*.
Apr 09 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/10/2012 12:18 AM, Walter Bright wrote:
 On 4/6/2012 3:49 AM, Timon Gehr wrote:
 On 04/06/2012 12:23 PM, Walter Bright wrote:
 On 4/6/2012 2:54 AM, Timon Gehr wrote:
 Should add additional information to the type Foo. I don't see any
 issues with
 it, and not supporting it would be very strange.
How would: attr(foo) int x; int y; work? Are x and y the same type or not?
Yes, they are. (But a future extension might leave this choice up to 'foo')
 Now, consider:

 auto c = b ? x : y;

 What type does c have? int or  attr(foo)int ? And that's really just the
 beginning. How about:

 struct S(T) {
 T t;
 }

 Instantiate it with S!int and S!( attr(foo)int). Are those the same
 instantiation, or different? If the same, does S.t have the attribute or
 not?
There is no such thing as an attr(foo) int, because attr is not a type constructor.
But you said it was added to the *type*.
What I said was that it is added to the declaration. If the declaration happens to declare a type, then that must affect the type: attr(foo) struct Foo{} // annotate 'foo' attr(bar) Foo x; __traits(getAttributes, typeof(x)); // this will find 'foo', but no 'bar' __traits(getAttributes, x); // this will find 'bar', but not 'foo'
Apr 10 2012
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 10 Apr 2012 06:32:00 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/10/2012 12:18 AM, Walter Bright wrote:
 But you said it was added to the *type*.
What I said was that it is added to the declaration. If the declaration happens to declare a type, then that must affect the type: attr(foo) struct Foo{} // annotate 'foo' attr(bar) Foo x; __traits(getAttributes, typeof(x)); // this will find 'foo', but no 'bar' __traits(getAttributes, x); // this will find 'bar', but not 'foo'
I should clarify that it's *associated* with the type. It should not affect the type in how it functions, at all. For all usages of Foo except to get attributes associated with its declaration, it should be treated as if it doesn't have an attribute on it. So it doesn't affect how the type operates or how it's matched, etc. except in the capacity that you query its attributes. -Steve
Apr 10 2012
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 04/10/12 12:32, Timon Gehr wrote:
 On 04/10/2012 12:18 AM, Walter Bright wrote:
 On 4/6/2012 3:49 AM, Timon Gehr wrote:
 On 04/06/2012 12:23 PM, Walter Bright wrote:
 On 4/6/2012 2:54 AM, Timon Gehr wrote:
 Should add additional information to the type Foo. I don't see any
 issues with
 it, and not supporting it would be very strange.
How would: attr(foo) int x; int y; work? Are x and y the same type or not?
Yes, they are. (But a future extension might leave this choice up to 'foo')
 Now, consider:

 auto c = b ? x : y;

 What type does c have? int or  attr(foo)int ? And that's really just the
 beginning. How about:

 struct S(T) {
 T t;
 }

 Instantiate it with S!int and S!( attr(foo)int). Are those the same
 instantiation, or different? If the same, does S.t have the attribute or
 not?
There is no such thing as an attr(foo) int, because attr is not a type constructor.
But you said it was added to the *type*.
What I said was that it is added to the declaration. If the declaration happens to declare a type, then that must affect the type: attr(foo) struct Foo{} // annotate 'foo' attr(bar) Foo x; __traits(getAttributes, typeof(x)); // this will find 'foo', but no 'bar' __traits(getAttributes, x); // this will find 'bar', but not 'foo'
The last one is the one i'm not sure about. What's the advantage of not reporting 'foo' for 'x'? "Inheriting" the attrs from the type seems attractive, what does separating the attributes achieve in practice? I'm assuming the type attributes do not influence the type in any way. While it would be great if one could also have type-changing attributes [1] in addition to the just annotating ones, i'm not going to propose that - there were too many too complicated proposals in these threads already... artur [1] think "shared" etc, or multiple string types.
Apr 10 2012
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On 6 April 2012 13:23, Walter Bright <newshound2 digitalmars.com> wrote:

 On 4/6/2012 2:54 AM, Timon Gehr wrote:

 Should add additional information to the type Foo. I don't see any issues
 with
 it, and not supporting it would be very strange.
How would: attr(foo) int x; int y; work? Are x and y the same type or not?
Yes they are the same type.
 Now, consider:

   auto c = b ? x : y;
c was not attributed, and has no attributes. blah auto c = b ? x : y; // NOW 'c' is attributed with 'blah', as useless as that is :) Attributes are on the declaration, and not passed around.
Apr 06 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/6/2012 4:20 AM, Manu wrote:
     On 4/6/2012 2:54 AM, Timon Gehr wrote:
          Should add additional information to the type Foo.
 Attributes are on the declaration, and not passed around.
Right, they are not added to the *type*.
Apr 09 2012
parent deadalnix <deadalnix gmail.com> writes:
Le 10/04/2012 00:19, Walter Bright a écrit :
 On 4/6/2012 4:20 AM, Manu wrote:
 On 4/6/2012 2:54 AM, Timon Gehr wrote:
 Should add additional information to the type Foo.
 Attributes are on the declaration, and not passed around.
Right, they are not added to the *type*.
No, they are not, or it will become a crazy mess.
Apr 10 2012
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 03:54:15 -0400, Walter Bright  =

<newshound2 digitalmars.com> wrote:

 On 4/6/2012 12:49 AM, Alex R=C3=B8nne Petersen wrote:
 What about type declarations? I think those ought to be supported too=
. =
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the  =
 inverse).
That would make it a "type constructor", not a storage class, which we=
=
 talked about earlier in the thread. I refer you to that discussion.
I think there is a huge misunderstanding here. A type constructor alters a type. Annotations are not type constructors= . for example: class C {} foo class D {} foo C c; foo2 D d; D d2 =3D d; In all these cases, the foo or foo2 affects the *declaration*, not the= = *type*. So: 1. D's type is not affected, it's still class D. But an annotation has = = been stored on the *symbol* D, such that it can be looked up later. 2. annotations on variables do *not* affect the type of the variable. T= he = assignment to d2 works fine. 3. The following symbols have annotations attached to them: C: none D: foo c: foo d: foo2 d2: none Note that d and d2 have no annotations attached even though they are of = = type D. Because the type isn't affected by annotations. An annotation is simply metadata, stored in the compiler, and looked up = = via compiler directives. Optionally (and I would encourage this), = TypeInfo would store annotations on type declarations for retrieval at = runtime. -Steve
Apr 06 2012
next sibling parent reply Manu <turkeyman gmail.com> writes:
On 6 April 2012 15:58, Steven Schveighoffer <schveiguy yahoo.com> wrote:

 On Fri, 06 Apr 2012 03:54:15 -0400, Walter Bright <
 newshound2 digitalmars.com> wrote:

  On 4/6/2012 12:49 AM, Alex R=C3=B8nne Petersen wrote:
 What about type declarations? I think those ought to be supported too.
 E.g. it
 makes sense to mark an entire type as  attr(serializable) (or the
 inverse).
That would make it a "type constructor", not a storage class, which we talked about earlier in the thread. I refer you to that discussion.
I think there is a huge misunderstanding here. A type constructor alters a type. Annotations are not type constructors. for example: class C {} foo class D {} foo C c; foo2 D d; D d2 =3D d; In all these cases, the foo or foo2 affects the *declaration*, not the *type*. So: 1. D's type is not affected, it's still class D. But an annotation has been stored on the *symbol* D, such that it can be looked up later. 2. annotations on variables do *not* affect the type of the variable. Th=
e
 assignment to d2 works fine.
 3. The following symbols have annotations attached to them:
  C: none
  D:  foo
  c:  foo
  d:  foo2
  d2: none

 Note that d and d2 have no annotations attached even though they are of
 type D.  Because the type isn't affected by annotations.
Just to clarify, typeof(d) and typeof(d2) (ie, both D's) are still annotated with foo, right? This is precisely how I imagine it to be. An annotation is simply metadata, stored in the compiler, and looked up via
 compiler directives.  Optionally (and I would encourage this), TypeInfo
 would store annotations on type declarations for retrieval at runtime.
I agree, and I would also encourage this.
Apr 06 2012
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 06 Apr 2012 09:04:58 -0400, Manu <turkeyman gmail.com> wrote:

 On 6 April 2012 15:58, Steven Schveighoffer <schveiguy yahoo.com> wrote:

 Note that d and d2 have no annotations attached even though they are of
 type D.  Because the type isn't affected by annotations.
Just to clarify, typeof(d) and typeof(d2) (ie, both D's) are still annotated with foo, right? This is precisely how I imagine it to be.
Correct. -Steve
Apr 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 14:58, Steven Schveighoffer wrote:

 An annotation is simply metadata, stored in the compiler, and looked up
 via compiler directives. Optionally (and I would encourage this),
 TypeInfo would store annotations on type declarations for retrieval at
 runtime.

 -Steve
Yes, annotations/attributes should be accessible at both compile time and runtime. -- /Jacob Carlborg
Apr 06 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 09:47, Walter Bright wrote:
 On 4/6/2012 12:42 AM, Alex Rønne Petersen wrote:
 Also, by storage class do you mean it will work only on fields?
No. Storage classes work on fields, functions, and variables.
They need to be attachable to classes, structs, enums and so on as well. -- /Jacob Carlborg
Apr 06 2012
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
On 6 April 2012 09:47, Walter Bright <newshound2 digitalmars.com> wrote:

 On 4/5/2012 5:00 AM, Manu wrote:

patterns, I
 don't think there should be any mystery over how they should be
implemented. I was thinking of something along the lines of what has been proposed here earlier: attr(identifier = expression) as a storage class, like: attr(foo = bar + 1) int x; and then: __traits(hasAttribute, x, foo) would return true, and: __traits(getAttribute, x, foo) would return the expression (bar+1). The expression would be compile-time only, evaluated at the point of declaration. The implementation is simple enough, just attach to each symbol an array of (identifier,expression) pairs. You could also omit the expression, and just have: attr(bar) int y;
I think this is unnecessarily verbose, although certainly workable as a minimum. Although there is one issue that 'foo' can't store compound data. I'd like to see attributes defined as a special sort of struct, and support constructors, this way you can associate rich data, and you can perform complex expressions (ctfe) within the constructor to set defaults, or calculate other details about the attribute if not specified. replay int x; // this is all that is needed if the attribute associates no variable information // or something associating consideraly more rich information editor("X coordinate", EditType.Slider, Colour.Red, "Verbose description about the thing") // this is still a lot easier to read to me... int x;
Apr 06 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 08:47, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
  > don't think there should be any mystery over how they should be
 implemented.

 I was thinking of something along the lines of what has been proposed
 here earlier:

  attr(identifier = expression)

 as a storage class, like:

  attr(foo = bar + 1) int x;

 and then:

 __traits(hasAttribute, x, foo)

 would return true, and:

 __traits(getAttribute, x, foo)

 would return the expression (bar+1). The expression would be
 compile-time only, evaluated at the point of declaration.

 The implementation is simple enough, just attach to each symbol an array
 of (identifier,expression) pairs.

 You could also omit the expression, and just have:

  attr(bar) int y;
I'm not a particular fan of that syntax. I would go with: identifier(key = value/expression) Like: foo(k1 = bar + 1, k2 = bar + 2) int x; If the attribute takes one key-value pair: foo(value = bar + 1) int x; Can be shortened like: foo(bar + 1) int x; And for attributes that don't take any values: foo int x; -- /Jacob Carlborg
Apr 06 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-04-06 08:47, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
  > don't think there should be any mystery over how they should be
 implemented.

 I was thinking of something along the lines of what has been proposed
 here earlier:

  attr(identifier = expression)

 as a storage class, like:

  attr(foo = bar + 1) int x;

 and then:

 __traits(hasAttribute, x, foo)

 would return true, and:

 __traits(getAttribute, x, foo)

 would return the expression (bar+1). The expression would be
 compile-time only, evaluated at the point of declaration.

 The implementation is simple enough, just attach to each symbol an array
 of (identifier,expression) pairs.

 You could also omit the expression, and just have:

  attr(bar) int y;
Again, this is my proposal: http://www.digitalmars.com/d/archives/digitalmars/D/Proposal_user_defined_attributes_161624.html#N161742 -- /Jacob Carlborg
Apr 06 2012
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 6 April 2012 at 06:47:56 UTC, Walter Bright wrote:
 I was thinking of something along the lines of what has been 
 proposed here earlier:

    attr(identifier = expression)
The identifier in there is a liability because of name conflicts. Instead, use typeof(expression) to identify it. Since two types can't have the same fully qualified name, it will never conflict. Jacob and I disagreed on some details, but both our proposals in the last thread had this in common. Java does it this way, too. Here's the other thread: http://forum.dlang.org/thread/bccwycoexxykfgxvedix forum.dlang.org
Apr 06 2012
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/6/12 1:47 AM, Walter Bright wrote:
 On 4/5/2012 5:00 AM, Manu wrote:

 patterns, I
  > don't think there should be any mystery over how they should be
 implemented.

 I was thinking of something along the lines of what has been proposed
 here earlier:

  attr(identifier = expression)

 as a storage class, like:

  attr(foo = bar + 1) int x;

 and then:

 __traits(hasAttribute, x, foo)

 would return true, and:

 __traits(getAttribute, x, foo)

 would return the expression (bar+1). The expression would be
 compile-time only, evaluated at the point of declaration.
You also need means to enumerate attributes. Andrei
Apr 06 2012
parent reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Andrei Alexandrescu wrote:
 On 4/6/12 1:47 AM, Walter Bright wrote:
 __traits(hasAttribute, x, foo)

 would return true, and:

 __traits(getAttribute, x, foo)

 would return the expression (bar+1). The expression would be
 compile-time only, evaluated at the point of declaration.
You also need means to enumerate attributes.
Minimalistically getAttribute*s* should be enough: __traits(getAttributes, x) would return all attributes of x. The rest can be implemented as library templates in std.traits.
Apr 06 2012
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 6 April 2012 at 15:16:37 UTC, Piotr Szturmaj wrote:
 __traits(getAttributes, x)
Note that my proposal from a couple weeks ago did it this way. getAttributes returned a TypeTuple. You'd loop through it with is(typeof()) to extract a specific one. The key is the type name. The value is whatever your thing evaluated to: attr(10+2) decl; conceptually the same as enum tmp = 10+2; decl.annotations ~= tmp;
Apr 06 2012
parent reply Marco Leise <Marco.Leise gmx.de> writes:
I don't want this thread to disappear. The ideas presented here have common=
 basic features among the nice-to-haves.

1. Attributes add meta data baggage to a symbol
2. This meta data is thought of as a read-only hash (has, get, iterate)
3. Can be queried at compile-time
4. The syntax is concise (i.e. improves over implementing attributes 'manua=
lly' with mixins)

Now the compiler has solved things (what is a symbol, an AST, ...) in one s=
pecific way and to keep it stable and the amount of work within bounds, any=
 implementation details of attributes that make invasive changes necessary =
should be postponed. I don't know the compiler, so it is just my gut feelin=
g when I say that annotating local variables could be a refinement to 1) th=
at doesn't work well. You get the point.

With that in mind it would be good to know exactly what can simply be tacke=
d onto the front-end (rather than refactoring a complex part of it). "What =
do you want to hear?" I hear you ask. Ok, here is my shameless "since D is =
supposed to be" argument: D is supposed to be pragmatic, so I would start w=
ith a collection of use cases. Really, "I want attributes to be like this" =
is not enough. The use case should be stated in a fashion, that programmers=
 without experience in the field can follow. The standard use cases for att=
ributes are must-haves, the rest can be nice-to-haves.

Add to the list, what you need from the attribute system:

** Serialization/RPC **

A relational SQL database comes with meta information on data types. We wan=
t to annotate D types with the corresponding types in the DB. This can be u=
sed to validate the value ranges at runtime, generate the correct SQL to wo=
rk with the tables or even create tables that don't exist already. It is al=
so common to establish relations between tables. The struct Parent may have=
 a 'Child*[]' field and Child a 'Parent*' field.
The same applies to RPC. For example we may want to return a bool[] using a=
 special case in the RPC system for bit arrays: ' Rpc(type =3D RpcType.nati=
ve_bit_array, mode =3D RpcMode.async) bool[] foo() { =E2=80=A6 }'. This ann=
otation applies to the symbol foo. If make this a more complex return type,=
 it becomes this:

	enum RpcMode =E2=80=A6;
	enum RpcType =E2=80=A6;

	struct Rpc =E2=80=A6;
	struct RpcStruct =E2=80=A6;
	// has a single field, syntax options:
	//  RpcTypeMap(type =3D RpcType.int)
	//  RpcTypeMap(RpcType.int)
	//  RpcTypeMap(int) ?
	struct RpcTypeMod { RpcType type };

	 RpcStruct struct MyRet {
		string name;
		 RpcTypeMap(RpcType.native_bit_array) bool[] flags;
	}

	 Rpc(mode =3D RpcMode.async) MyRet foo() { =E2=80=A6 }

For RPC it is also necessary, to annotate parameters in the same way:

	void foo( RpcTypeMap(RpcType.native_bit_array) bool[] flags) { =E2=80=A6 }


** Edit object properties in a GUI (as suggested by Manu) **

As seen in GUI builders, often the need occurs to generate bindings to data=
 structures in order to edit their properties in a convenient user interfac=
e. A uint field may be edited using a RGB+Alpha color selector and serializ=
ed into a data file. The requirements for the annotations are the same as a=
bove. (I know that RTTI would make life easier here, but it isn't a show st=
opper.)



For these to work it would require:
- user annotations to functions/methods/structs/classes
- only CTFE support (as annotations don't change at runtime)
- no influence on language semantics
And I agree with others that it is a good idea to implement annotations as =
structured types (POD structs at least) to avoid spelling mistakes and enco=
urage IDE support. Just as an idea: Such structs, could contain their own l=
ogic. So some annotations which work stand-alone could validate themselves =
(invariant()?), print debug msgs, write binding definitions to text files (=
if CTFE I/O happens) or actually mixin code if used on structs/classes. But=
 that's just brain-storming to give an idea why annotations as key/value pa=
irs could be unflexible.

h what people mostly expect and a good 'template' for D aside from runtim v=
s. compile-time issues.

thanks for reading :)

--=20
Marco
Apr 08 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-08 09:27, Marco Leise wrote:
 I don't want this thread to disappear. The ideas presented here have common
basic features among the nice-to-haves.
 For these to work it would require:
 - user annotations to functions/methods/structs/classes
 - only CTFE support (as annotations don't change at runtime)
I don't see why the attributes should be accessible at runtime. Even if they're read-only it's still good to be able to read the attributes at runtime. -- /Jacob Carlborg
Apr 08 2012
next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sun, 08 Apr 2012 12:44:17 +0200
schrieb Jacob Carlborg <doob me.com>:

 On 2012-04-08 09:27, Marco Leise wrote:
 I don't want this thread to disappear. The ideas presented here have common
basic features among the nice-to-haves.
 For these to work it would require:
 - user annotations to functions/methods/structs/classes
 - only CTFE support (as annotations don't change at runtime)
I don't see why the attributes should be accessible at runtime. Even if they're read-only it's still good to be able to read the attributes at runtime.
Yeah, it was supposed to mean "it requires CTFE support, runtime support is possible" :) -- Marco
Apr 08 2012
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 08/04/2012 12:44, Jacob Carlborg a écrit :
 On 2012-04-08 09:27, Marco Leise wrote:
 I don't want this thread to disappear. The ideas presented here have
 common basic features among the nice-to-haves.
 For these to work it would require:
 - user annotations to functions/methods/structs/classes
 - only CTFE support (as annotations don't change at runtime)
I don't see why the attributes should be accessible at runtime. Even if they're read-only it's still good to be able to read the attributes at runtime.
If it is available at compile time, it is implementable at runtime as a lib. So you pay for it only if you use it, and you don't add feature in the language just because it is convenient.
Apr 09 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-09 23:49, deadalnix wrote:

 If it is available at compile time, it is implementable at runtime as a
 lib. So you pay for it only if you use it, and you don't add feature in
 the language just because it is convenient.
I'm not saying how it should be implemented, just that it should be accessible at runtime. -- /Jacob Carlborg
Apr 09 2012
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 10 Apr 2012 02:30:21 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2012-04-09 23:49, deadalnix wrote:

 If it is available at compile time, it is implementable at runtime as a
 lib. So you pay for it only if you use it, and you don't add feature in
 the language just because it is convenient.
I'm not saying how it should be implemented, just that it should be accessible at runtime.
I think there was some confusion, read a quote of what you said: "I don't see why the attributes *should* be accessible at runtime" Emphasis added. I think you meant "shouldn't" -Steve
Apr 10 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-04-10 13:41, Steven Schveighoffer wrote:
 On Tue, 10 Apr 2012 02:30:21 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2012-04-09 23:49, deadalnix wrote:

 If it is available at compile time, it is implementable at runtime as a
 lib. So you pay for it only if you use it, and you don't add feature in
 the language just because it is convenient.
I'm not saying how it should be implemented, just that it should be accessible at runtime.
I think there was some confusion, read a quote of what you said: "I don't see why the attributes *should* be accessible at runtime" Emphasis added. I think you meant "shouldn't" -Steve
Yeah, I did, hehe :) This thread is getting too long now. -- /Jacob Carlborg
Apr 10 2012
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Tue, 10 Apr 2012 13:53:09 +0200
schrieb Jacob Carlborg <doob me.com>:

 On 2012-04-10 13:41, Steven Schveighoffer wrote:
 On Tue, 10 Apr 2012 02:30:21 -0400, Jacob Carlborg <doob me.com> wrote:

 On 2012-04-09 23:49, deadalnix wrote:

 If it is available at compile time, it is implementable at runtime as a
 lib. So you pay for it only if you use it, and you don't add feature in
 the language just because it is convenient.
I'm not saying how it should be implemented, just that it should be accessible at runtime.
I think there was some confusion, read a quote of what you said: "I don't see why the attributes *should* be accessible at runtime" Emphasis added. I think you meant "shouldn't" -Steve
Yeah, I did, hehe :) This thread is getting too long now.
So in the end we more or less agree that Walter and others can implement useful attributes for compile-time, whereas runtime support is nice-to-have (or can be provided by a lib)? My intention is to make it easier for the one who implements them if runtime support proves difficult. -- Marco
Apr 10 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-04-10 19:02, Marco Leise wrote:

 So in the end we more or less agree that Walter and others can implement
useful attributes for compile-time, whereas runtime support is nice-to-have (or
can be provided by a lib)? My intention is to make it easier for the one who
implements them if runtime support proves difficult.
Something like that. -- /Jacob Carlborg
Apr 10 2012