November 14, 2012
On Wednesday, 14 November 2012 at 13:28:05 UTC, Tove wrote:
> // in this nested scope, all uints are interpreted as belonging to the thrift module.
> [std.attributes(uint, thrift)]
> struct UserProfile
> ...
>
> // error detected at compile-time
> [std.attributes(uint, thrift), std.attributes(uint, thrift2)]
> struct UserProfile
> ...

»interpreted as belonging to the thrift module« – what do you even mean by that? As of now, UDAs are just a way to tuck arbitrary symbols onto declarations. There is no concept of »belonging« to a module, and I don't think there should be.

Also, your solution is more complex than simply using types, yet less flexible: What if you want to use "uint" attributes from two libraries on the same type?

David
November 14, 2012
On Wednesday, 14 November 2012 at 13:28:05 UTC, Tove wrote:
> // in this nested scope, all uints are interpreted as belonging to the thrift module.
> [std.attributes(uint, thrift)]
> struct UserProfile
> ...
>
> // error detected at compile-time
> [std.attributes(uint, thrift), std.attributes(uint, thrift2)]
> struct UserProfile
> ...

»interpreted as belonging to the thrift module« – what do you even mean by that? As of now, UDAs are just a way to tuck arbitrary symbols onto declarations. There is no concept of »belonging« to a module, and I don't think there should be.

Also, your solution is more complex than simply using types, yet less flexible: What if you want to use "uint" attributes from two libraries on the same type?

David
November 15, 2012
On 2012-11-14 22:13, Walter Bright wrote:

> I am having a REALLY hard time making my point here.
>
> struct MyString
> {
>       string s;
> }
> Just because it is not a builtin type does not change anything.

Sure you _can_ but it would be quite stupid. With user defined types there is at least some context. With a plain string (or any built in type) it can come from any where and mean anything.

The difference is, with a user defined type you know the meaning of the attribute, with a built in type you do not, not in the same way at least.

-- 
/Jacob Carlborg
November 15, 2012
On 2012-11-14 23:39, Andrei Alexandrescu wrote:

> I think a simple way to put this is that attribute name lookup works the
> same as ordinary symbol lookup. Assuming we did a good job at the
> latter, the former doesn't introduce any specific issues.

Exactly.

-- 
/Jacob Carlborg
November 15, 2012
On Wednesday, 14 November 2012 at 23:57:38 UTC, David Nadlinger wrote:
> Also, your solution is more complex than simply using types, yet less flexible: What if you want to use "uint" attributes from two libraries on the same type?
>
> David

I disagree, you can always fallback to using user defined types... but it _allows_ for native types also, i.e. more flexible.

November 15, 2012
Timon Gehr, el 14 de November a las 17:25 me escribiste:
> On 11/14/2012 03:31 PM, Leandro Lucarella wrote:
> >Tove, el 14 de November a las 13:55 me escribiste:
> >>>struct UserProfile {
> >>>    @Id(1) i32 uid;
> >>>    @Id(2) string name;
> >>>    @Id(3) string blurb;
> >>>}
> >>>
> >>>Where Id is "thrift.attributes.Id" or something similar.
> >>
> >>well, similar... but beginning with a symbol...
> >>
> >>[thrift.attributes.Definition]
> >>struct UserProfile
> >>{
> >>   [1] i32 uid;
> >>   [2] string name;
> >>   [3] string blurb;
> >>}
> >
> >OK, that's just a good example of convenience of allowing native types, but I
> >think it is still potentially harmful. What if you pass that struct to another
> >library that have another meaning attached to int annotations? How could you
> >tell that library that this particular int annotations is not for it?
> >...
> 
> By not telling it that they are for it. Note that the [thrift.attributes.Definition] annotation is significant.

Yes, but that only tells thrift how to interpret those ints, it doesn't tell any other module they *shouldn't* interpret them. Or are you suggesting every module that want to attach meaning to an int attribute should check if the parent module doesn't have any other attribute attached to it?

> >I mean, it convenient to be able to throw numbers or strings too:
> >
> >void f() { throw 1; }
> >
> >void g() { throw "error"; }
> >
> >int main()
> >{
> >	try {
> >		g();
> >	} catch (char[] e) {
> >		writefln(e);
> >	}
> >	try {
> >		f();
> >	} catch (int i) {
> >		return i;
> >	}
> >	return 0;
> >}
> >
> 
> What he does is more like (but not exactly like):
> 
> class ThriftException{
>     int x;
>     this(int x){ this.x = x; }
> }

I don't know what does this mean.

-- 
November 15, 2012
On Thursday, 15 November 2012 at 08:45:49 UTC, Tove wrote:
> I disagree, you can always fallback to using user defined types... but it _allows_ for native types also, i.e. more flexible.

You are missing the point: In your proposal, if you want to use two libraries together which are expecting you to provide e.g. 'int' annotations, you are screwed. This is a big, BIG problem.

David
November 16, 2012
On Thursday, 15 November 2012 at 22:04:27 UTC, David Nadlinger wrote:
> On Thursday, 15 November 2012 at 08:45:49 UTC, Tove wrote:
>> I disagree, you can always fallback to using user defined types... but it _allows_ for native types also, i.e. more flexible.
>
> You are missing the point: In your proposal, if you want to use two libraries together which are expecting you to provide e.g. 'int' annotations, you are screwed. This is a big, BIG problem.
>
> David

no, I implied the solution already... actually there are many different ways to solve it... some possible today, some require new minor support features(like sending the annotated symbol as a template alias parameter to the annotation)... but could give us compile time errors when ambiguity is detected.

In the common case there are no collisions, so most of the time we can use the nice user-friendly syntax!

[lib1.x]
struct User
{
  [1] int uid;
}

But we _can_ disambiguate when needed...
[lib1.x, lib2.y]
struct User
{
  [lib!1, lib2!2] int uid; // ok
  [1, lib2!2] int uid; // ok
  [lib1!1, 2] int uid; // ok
  [1,2] int uid; // not supported
  [1]   int uid; // not supported
}

lib2 doesn't have to know about lib1.
lib1 doesn't have to know about lib2.
Because they just have to check the annotation in _prioritized_ order.

1. find my unique lib2.y symbol
2. if there is a lib2!uint on a nested symbol, use it...
3. if not check for a native int.

November 16, 2012
On 11/15/2012 12:22 AM, Jacob Carlborg wrote:
> On 2012-11-14 22:13, Walter Bright wrote:
>
>> I am having a REALLY hard time making my point here.
>>
>> struct MyString
>> {
>>       string s;
>> }
>> Just because it is not a builtin type does not change anything.
>
> Sure you _can_ but it would be quite stupid. With user defined types there is at
> least some context. With a plain string (or any built in type) it can come from
> any where and mean anything.
>
> The difference is, with a user defined type you know the meaning of the
> attribute, with a built in type you do not, not in the same way at least.
>

The whole point of my example was no, you do not necessarily know the meaning of a user-defined type that is used as an attribute.
November 16, 2012
On Friday, 16 November 2012 at 10:41:44 UTC, Walter Bright wrote:
> The whole point of my example was no, you do not necessarily know the meaning of a user-defined type that is used as an attribute.

Agree. Imagine we have 3 generic libs/modules...
"Optimized CTFE Polygon Primitive Lib", Math, Gfx
... and then the "end user", creates a program.

Both Math and Gfx, want to use the optimized Polygon in their modules...

[Polygon(...)]
struct SpaceShip
{
}

This is just as ambiguous as if you had used a built-in int:s... and it can be solved in the exact same way which I outlined in the other thread.