November 14, 2012
On 11/13/2012 2:55 PM, bearophile wrote:
> Walter Bright:
>
>> consider the type "int". Different modules impute different meanings into it
>> all the time, and it doesn't cause terrible compatibility problems between
>> modules.
>
> The usage of naked basic types as int and double cause troubles.

I know that you can use custom types instead, and have better type checking, etc., and can be a pretty good idea for a lot of use cases. But D does not require that. It's up to the programmer.

November 14, 2012
Walter Bright:

(I know this sub-discussion is a bit OT, but not too much, and I think it's not wasted time.)

>But D does not require that. It's up to the programmer.<

Oh, but the use of "newtype" is not required in Haskell; programmers are free to use it, or to use normal basic types as Int, Integer, Double, etc. Probably newtype is not that useful in little programs. And even in larger programs it's better to not use it too much.

And the use of that "using" in a newtype is not standard Haskell, it's a GHC compiler extension to the language, that you have to ask with a compilation switch or an annotation inside the code. That "using" attached to a newtype allows you to both use a newtype like its base type (like the underlying Int), or to choose where the newtype must not do what its base type is able to do (this technically means what typeclasses it conforms to or not). I think D Typedef should allow something similar, despite D has no typeclasses. As an example, currently D Typedef is kind of useless if you want to use it to define a new array type.

Bye,
bearophile
November 14, 2012
On 11/13/2012 5:22 PM, bearophile wrote:
> As an
> example, currently D Typedef is kind of useless if you want to use it to define
> a new array type.

D's typedef is deprecated, as nobody could figure out what it was good for or properly define its semantics.

November 14, 2012
Le 13/11/2012 23:27, Walter Bright a écrit :
> On 11/10/2012 12:21 PM, deadalnix wrote:
>> Thinking of it this way don't make any sense. The whole point of an
>> attribute is
>> to tell a library about how to understand your code.
>>
>> If many library uses the same attribute, then it defeat the whole
>> point of
>> having attribute. This is why the discussion about disallowing any
>> type as UDA
>> exists in the first place.
>
> I understand that. I just am not convinced of the scope of this issue,
> and I am not convinced that a runtime attribute system is that
> applicable for this case, nor am I convinced that exception handling is
> that applicable (all for reasons already explained).
>

I presented you compile time uses cases for such a mecanism already. See project lombok for instance.

> For another analogy, consider the type "int". Different modules impute
> different meanings into it all the time, and it doesn't cause terrible
> compatibility problems between modules.

int isn't meant to be discovered. The whole point of attribute is to be discovered.
November 14, 2012
Walter Bright:

> D's typedef is deprecated, as nobody could figure out what it was good for or properly define its semantics.

Look better, in both my last posts "Typedef" was std.typecons.Typedef.

Bye,
bearophile
November 14, 2012
On 2012-11-13 23:24, Walter Bright wrote:

> That is what I mean, and it also applies to a library type which
> different modules may press into service as attributes.

I think there must be some kind of misunderstanding here. I still don't see the problem if fully qualified symbols are used. I mean, it will be unique.

-- 
/Jacob Carlborg
November 14, 2012
On 11/13/2012 11:16 PM, Jacob Carlborg wrote:
> On 2012-11-13 23:24, Walter Bright wrote:
>
>> That is what I mean, and it also applies to a library type which
>> different modules may press into service as attributes.
>
> I think there must be some kind of misunderstanding here. I still don't see the
> problem if fully qualified symbols are used. I mean, it will be unique.
>

We agree that strings can be used globally as attributes with different meanings, right?

So why can't test.foo.bar also be used globally as an attribute with different meanings? It's just a type name, it has no magic property that says it cannot be used for different purposes. Ok, let's call it:

    std.mytypes.mystring

? Now have those string contents mean different things to different users of std.mytypes.mystring.
November 14, 2012
On 2012-11-14 08:46, Walter Bright wrote:

> We agree that strings can be used globally as attributes with different
> meanings, right?

Yes, but I would consider that a bad idea.

> So why can't test.foo.bar also be used globally as an attribute with
> different meanings? It's just a type name, it has no magic property that
> says it cannot be used for different purposes.

I guess it could. But there is no way of preventing the user from doing stupid things. I can create a map container out of two arrays, but that's not how arrays are intended to be used.

> Ok, let's call it:
>
>      std.mytypes.mystring
>
> ? Now have those string contents mean different things to different
> users of std.mytypes.mystring.

If "std.mytypes.mystring" is a variable of the type "string" then the fully qualified name is lost if it's used as an attribute. Something like this:

[std.mytypes.mystring] int a;

pragma(msg, __traits(getAttributes, a).stringof);

Would result in:

("foo")

pragma(msg, typeof(__traits(getAttributes, a)).stringof);

Would result in:

(string)

The name "std.mytypes.mystring" is gone. You have no idea where the string came from, who could have put it there. You would need to put the fully qualified name in the content of the string:

module std.mytypes;

string mystring = "std.mytypes.mystring";

The whole problem with this is that there is no actual thing called "attribute", there are just symbols with attached values.

In most cases I think it's the symbol/type name that is interesting. I imagine many attributes just look like this:

@attribute struct Serializable {}

I would prefer that only user defined types explicitly marked with @attribute (or similar) could be used as attributes. And preferably, that they cannot be used for anything else.

If only user defined types (and preferably marked with @attribute) are allowed then you can know exactly where a given attribute comes from and you can look up the documentation. Sure you cannot prevent anyone from using the attribute with a different meaning then it was intended for. But that's true for many other things in programming as well.

-- 
/Jacob Carlborg
November 14, 2012
Walter Bright, el 13 de November a las 16:49 me escribiste:
> On 11/13/2012 2:55 PM, bearophile wrote:
> >Walter Bright:
> >
> >>consider the type "int". Different modules impute different meanings into it all the time, and it doesn't cause terrible compatibility problems between modules.
> >
> >The usage of naked basic types as int and double cause troubles.
> 
> I know that you can use custom types instead, and have better type checking, etc., and can be a pretty good idea for a lot of use cases. But D does not require that. It's up to the programmer.

What really amazes me is how you always defend the "will not be included until real uses cases can be shown" and in this case you are doing the exact opposite.

Can you provide any real uses cases instead of talking about a completely theoretical and hypothetical cases?

Can you provide one concrete case where it makes sense NOT to restrict UDAs to types and it's different from restricting exception to classes derived from Exception?

Thank you.

-- 
November 14, 2012
On Wednesday, 14 November 2012 at 11:08:04 UTC, Leandro Lucarella wrote:
>
> Can you provide one concrete case where it makes sense NOT to restrict UDAs to
> types and it's different from restricting exception to classes derived from
> Exception?
>
> Thank you.

There was the example with Thrift...

  struct UserProfile {
        1: i32 uid,
        2: string name,
        3: string blurb
      }
      service UserStorage {
        void store(1: UserProfile user),
        UserProfile retrieve(1: i32 uid)
      }

You could use a user defined type for the struct... but for the members it would make sense to use the native type directly... and if you traverse the annotation in sequence rather than as standalone entities.. it's perfectly safe to use 1,2,3 as annotation...

i.e. first scan for the Thrift symbol, then scan for native typed int:s...