July 17, 2016
On Sunday, July 17, 2016 09:07:13 Ali Çehreli via Digitalmars-d wrote:
> To those who know the compiler internals, is there a reason why UDA are
> not applied to all turtles? (I guess the answer is not that simple. :) )

Mabye some of them are actually tortoises? ;)

D's features rarely seem to be implemented as "turtles all the way down" to begin with. That's usually something that comes later after folks complain about something that they think is inconsistent. And it's sometimes disputable as to whether something counts as being "turtles all the way down" or whether it would actually be a good idea to _not_ do "turtles all the way down" (for instance, some of the way that attributes are applied such that you're allowed to put them on all kinds of things where they don't apply but don't get an error is arguably a case of "turtles all the way down," but it's also quite problematic at least some of the time).

In this particular case, I have no idea whether it would be a good idea or not, but it is a bit similar to applying UDAs to variables, which would be rather odd (though per the OP, it sounds like it's legal to put them on member variables; I don't have any experience with UDAs though, so I'm not sure what their restrictions are exactly). And if you can put UDAs on enum members the way that the OP is looking to do, that immediately poses the question of whether something like

enum @MyUDA foo = "hello world";

should be legal, and if we do that, we're pretty much at the point that any variable should be allowed to have a UDA, which seems pointless and overcomplicated to me - particularly with regards to local variables. I expect that if there's a good enough, practical argument to be made, then we could end up with UDAs on enum members, but that argument is going to have to be made such that Walter and Andrei are convinced, which may or may not be easy. But anyone who feels strongly about this should consider putting together a DIP.

- Jonathan M Davis


July 17, 2016
On 2016-07-17 19:01, Jonathan M Davis via Digitalmars-d wrote:

> Mabye some of them are actually tortoises? ;)
>
> D's features rarely seem to be implemented as "turtles all the way down" to
> begin with. That's usually something that comes later after folks complain
> about something that they think is inconsistent. And it's sometimes
> disputable as to whether something counts as being "turtles all the way
> down" or whether it would actually be a good idea to _not_ do "turtles all
> the way down" (for instance, some of the way that attributes are applied
> such that you're allowed to put them on all kinds of things where they don't
> apply but don't get an error is arguably a case of "turtles all the way
> down," but it's also quite problematic at least some of the time).
>
> In this particular case, I have no idea whether it would be a good idea or
> not, but it is a bit similar to applying UDAs to variables, which would be
> rather odd (though per the OP, it sounds like it's legal to put them on
> member variables;

I'm using UDA's on instance variables in my serialization library:

class Foo
{
    int a;
    @nonSerialized int b;
}

I could also imagine more use cases for a serialization library:

class Foo
{
    @name("a") int _a;
    @verison_(2) int b;
}

Other use cases would be to communicate to other applications. In Objective-C #defines are used in the code to indicate which instance variables and functions/actions can be connected in Interface Builder. In D, UDA's would be a perfect fit for that:

class Foo
{
    @IBOutlet NSButton button;
    @IBAction void onClick(NSButton sender) {}
}

> I don't have any experience with UDAs though, so I'm not
> sure what their restrictions are exactly). And if you can put UDAs on enum
> members the way that the OP is looking to do, that immediately poses the
> question of whether something like
>
> enum @MyUDA foo = "hello world";

I don't see why this shouldn't be possible.

> should be legal, and if we do that, we're pretty much at the point that any
> variable should be allowed to have a UDA, which seems pointless and
> overcomplicated to me - particularly with regards to local variables.

I don't see a reason not allowing UDA's on local variables either. You might say that it's not possible to access local variables, true, but the compiler might not be the only tool that analyzes the source code. I just suggested in another thread [1] that a UDA could be used on a local variable and then be interpreted by an external tool, I didn't even think that UDA's could not be used on local variables.

Going back to the Objective-C example with IBOutlet/IBAction. IBOutlet is a #define which expands to nothing and IBAction expands to "void". Clang recognizes these #defines [2], not because the compiler needs to but because Clang is used to build other tools that analyzes source code, in this case Xcode/Interface Builder.

> I expect that if there's a good enough, practical argument to be made, then we
> could end up with UDAs on enum members, but that argument is going to have
> to be made such that Walter and Andrei are convinced, which may or may not
> be easy. But anyone who feels strongly about this should consider putting
> together a DIP.

A naive implementation could allow to put attributes on all declarations, but that would then allow meaningless code like adding "private" to a locale variable. But when it comes to UDA's, a single UDA doesn't have a semantic meaning itself, like "private" does.

For a programming language to be useful it needs to be designed in a way that allows the users to implement things that the designers have not thought of. Adding artificial restrictions because the designers can not come up with a use case goes very much against this.

[1] http://forum.dlang.org/post/nmg142$2ji1$1@digitalmars.com

[2] http://clang.llvm.org/doxygen/group__CINDEX.html#gaaccc432245b4cd9f2d470913f9ef0013

-- 
/Jacob Carlborg
July 17, 2016
On 7/13/2016 4:57 AM, Tomer Filiba wrote:
> It would be really nice if I could put UDAs on enum members as well, e.g.,
>
> enum MyEnum {
>     @("SOM") SomeMember,
>     @("ANO") AnotherMemberWithAVeryLongName,
> }

Not a bad idea. It's been asked for before.


> And while we're on the subject, why can't enums have methods? At the risk of
> sounding as if I like Java (I don't :) ), it's a really nice language feature.
> Back to our example:
>
> enum MyEnum {
>     @("SOM") SomeMember,
>     @("ANO") AnotherMemberWithAVeryLongName;
>
>     string dump() {
>         ...  // `this` is a value, not a ref here
>     }
>     static MyEnum load(string name) {
>         ...
>     }
> }
>
> Basically just allow a semicolon at the end of the members, after which methods
> could appear. Adding members or whatever else Java has is an overkill -- just
> use a struct for that. But instead of lots of dumpMyEnum(MyEnum
> e)/loadMyEnum(string s) pairs, you could write myMember.dump()/MyEnum.load(s)


struct MyEnum {
    @("SOM") enum SomeMember = 0;
    @("ANO") enum AnotherMemberWithAVeryLongName = 1;

    string dump() {
        ...  // `this` is a value, not a ref here
    }
    static MyEnum load(string name) {
        ...
    }
}

Not as nice, but gets the job done. But adding a new aggregate type comes with a lot of baggage. I'm not convinced the complexity is worth the benefit, which seems minor.
July 18, 2016
On Sunday, 17 July 2016 at 20:51:42 UTC, Walter Bright wrote:
> On 7/13/2016 4:57 AM, Tomer Filiba wrote:
> struct MyEnum {
>     @("SOM") enum SomeMember = 0;
>     @("ANO") enum AnotherMemberWithAVeryLongName = 1;
>
>     string dump() {
>         ...  // `this` is a value, not a ref here
>     }
>     static MyEnum load(string name) {
>         ...
>     }
> }
>
> Not as nice, but gets the job done. But adding a new aggregate type comes with a lot of baggage. I'm not convinced the complexity is worth the benefit, which seems minor.

With a union it's ok, see the sugestion here

https://forum.dlang.org/post/kmqmqxskccaceurutgzq@forum.dlang.org

members are not part of the aggregate. The size is then just equal to the common type, used as variable to make bit op like with a regular enum.

I mean that the OP is asking for a really minor feature while he could solve the problem himself, in case he really needs it.
August 31, 2017
On Sunday, 17 July 2016 at 20:51:42 UTC, Walter Bright wrote:
> On 7/13/2016 4:57 AM, Tomer Filiba wrote:
>> It would be really nice if I could put UDAs on enum members as well, e.g.,
>>
>> enum MyEnum {
>>     @("SOM") SomeMember,
>>     @("ANO") AnotherMemberWithAVeryLongName,
>> }
>
> Not a bad idea. It's been asked for before.
>
>
>> And while we're on the subject, why can't enums have methods? At the risk of
>> sounding as if I like Java (I don't :) ), it's a really nice language feature.
>> Back to our example:
>>
>> enum MyEnum {
>>     @("SOM") SomeMember,
>>     @("ANO") AnotherMemberWithAVeryLongName;
>>
>>     string dump() {
>>         ...  // `this` is a value, not a ref here
>>     }
>>     static MyEnum load(string name) {
>>         ...
>>     }
>> }
>>
>> Basically just allow a semicolon at the end of the members, after which methods
>> could appear. Adding members or whatever else Java has is an overkill -- just
>> use a struct for that. But instead of lots of dumpMyEnum(MyEnum
>> e)/loadMyEnum(string s) pairs, you could write myMember.dump()/MyEnum.load(s)
>
>
> struct MyEnum {
>     @("SOM") enum SomeMember = 0;
>     @("ANO") enum AnotherMemberWithAVeryLongName = 1;
>
>     string dump() {
>         ...  // `this` is a value, not a ref here
>     }
>     static MyEnum load(string name) {
>         ...
>     }
> }
>
> Not as nice, but gets the job done. But adding a new aggregate type comes with a lot of baggage. I'm not convinced the complexity is worth the benefit, which seems minor.

If it's a simple rewrite rule then there is no complexity. I don't see how adding UDA's to enums is a new aggregate type(it's still an enum).

The problem with such rewrites by the user is that the structs do not behave as enums and so all the mechanisms that enums have won't work. This creates problems, bugs, kludges, etc.

Maybe the problem is that the implementation of UDA's is not expressive enough to modify in a simple way? So fixing the code to make it do what it should have done in the first place is where the complexity lies?

Having UDA's are as useful as having them. How do you know how useful they can be until it is done? I have several perfectly valid use cases for them, and the hacks are 10x much work and may break some code that depends them actually being enum's.

You should realize that what you see as minor is not necessarily minor and what you think is not beneficial is only your relative opinion about yourself. What would be more helpful is for you to state what criteria you would need to actually put in the effort to implement the new features rather than stating opinions that only shut down progress.

Just remember there are at least 10's of thousands of D users and your experiences with writing D code is only one small aspect. Many D users that come from different backgrounds will have different understandings and different approaches to how they will write *their* code and what they expect. While you owe them nothing, it would be nice to at least acknowledge their view as relevant. If something is a theoretical contradiction, that is one thing, and it must be proved so... but is something is simply not done out of priority, laziness, convenience, etc then that is another.

If dmd is properly written then the complexity of adding new features should be compartmentalized and relatively localized. While one can never predict the ramifications of adding new features(both good and bad), I think this is why there are experimental versions of dmd? New features should not be looked upon with disdain but be welcomed. The potential issues and complexity that seem to be brought up can be mitigated with the proper approaches.



September 01, 2017
On Wednesday, 13 July 2016 at 11:57:21 UTC, Tomer Filiba wrote:
> It would be really nice if I could put UDAs on enum members as well, e.g.,
>
> enum MyEnum {
>     @("SOM") SomeMember,
>     @("ANO") AnotherMemberWithAVeryLongName,
> }
>
> I can think of many reasons why that would be desired, but the concrete one is the following: I have an interchangeable data format, and my enum might gain members over time. I don't care about the value of the member, so I don't want to number them myself, but I can't control where users would choose to place the new member, so they might cause renumbering of existing members, breaking the interchangeable format.
>
> So what I wanted is to assign each member a "short stable name" that would be used to serialize the value (using my own dump/load functions)... But I had to resort to a long, ugly switch statement, mapping members to their names and vice versa. The dumping function uses final-switch, so you won't forget to update it, but the loading one can't (it takes a string) so it would be easy to people to forget.
>
> Given that UDAs can be used practically everywhere (including struct/union members), is there an objection to make them legal on enum members as well?
>
> And while we're on the subject, why can't enums have methods? At the risk of sounding as if I like Java (I don't :) ), it's a really nice language feature. Back to our example:
>
> enum MyEnum {
>     @("SOM") SomeMember,
>     @("ANO") AnotherMemberWithAVeryLongName;
>
>     string dump() {
>         ...  // `this` is a value, not a ref here
>     }
>     static MyEnum load(string name) {
>         ...
>     }
> }
>
> Basically just allow a semicolon at the end of the members, after which methods could appear. Adding members or whatever else Java has is an overkill -- just use a struct for that. But instead of lots of dumpMyEnum(MyEnum e)/loadMyEnum(string s) pairs, you could write myMember.dump()/MyEnum.load(s)
>
>
> -tomer

Here how I implement it

struct EnumArray(E, V)
{
nothrow @safe:

public:
    struct Entry
    {
        E e;
        V v;
    }

private:
    enum isEntryType(T) = is(Entry == T);
    enum size = EnumMembers!E.length;
    V[size] _values;

public:
    this(T...)(T aValues)
    if (allSatisfy!(isEntryType, T))
    {
        foreach (ref Entry i; aValues)
            _values[i.e] = i.v;
    }

    V opIndex(E aEnum) const
    {
        return _values[aEnum];
    }

    V opIndexAssign(V aValue, E aEnum)
    {
        return _values[aEnum] = aValue;
    }

    V opDispatch(string aEnumName)() const
    {
        import std.conv : to;

        enum e = aEnumName.to!E;
        return _values[e];
    }

    version (none)
    V opDispatch(string aEnumName)(V aValue)
    {
        import std.conv : to;

        enum e = aEnumName.to!E;
        return _values[e] = aValue;
    }

    E getEnum(V aValue, E aDefault = E.min)
    {
        foreach (i; EnumMembers!E)
        {
            if (_values[i] == aValue)
                return i;
        }

        return aDefault;
    }

@property:
    size_t length() const
    {
        return size;
    }
}

unittest // EnumArray
{
    enum EnumTest
    {
        one,
        two,
        max
    }

    alias EnumTestInt = EnumArray!(EnumTest, int);

    EnumTestInt testInt = EnumTestInt(
        EnumTestInt.Entry(EnumTest.one, 1),
        EnumTestInt.Entry(EnumTest.two, 2),
        EnumTestInt.Entry(EnumTest.max, int.max)
    );

    assert(testInt.one == 1);
    assert(testInt.two == 2);
    assert(testInt.max == int.max);

    assert(testInt[EnumTest.one] == 1);
    assert(testInt[EnumTest.two] == 2);
    assert(testInt[EnumTest.max] == int.max);

    assert(testInt.getEnum(1) == EnumTest.one);
    assert(testInt.getEnum(2) == EnumTest.two);
    assert(testInt.getEnum(int.max) == EnumTest.max);
    assert(testInt.getEnum(3) == EnumTest.one); // Unknown -> return default min


    alias EnumTestString = EnumArray!(EnumTest, string);

    EnumTestString testString = EnumTestString(
        EnumTestString.Entry(EnumTest.one, "1"),
        EnumTestString.Entry(EnumTest.two, "2"),
        EnumTestString.Entry(EnumTest.max, "int.max")
    );

    assert(testString[EnumTest.one] == "1");
    assert(testString[EnumTest.two] == "2");
    assert(testString[EnumTest.max] == "int.max");

    assert(testString.getEnum("1") == EnumTest.one);
    assert(testString.getEnum("2") == EnumTest.two);
    assert(testString.getEnum("int.max") == EnumTest.max);
    assert(testString.getEnum("3") == EnumTest.one); // Unknown -> return default min
}

Pham

1 2
Next ›   Last »