www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - enum scope

reply "Trass3r" <un known.com> writes:
When writing C bindings I usually create lots of aliases via a 
string mixin to pull enum members into the enclosing scope so 
it's compatible to C.
Would it be wise to let the compiler do this automatically for 
extern(C) enums?
Jan 25 2012
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, January 26, 2012 02:06:45 Trass3r wrote:
 When writing C bindings I usually create lots of aliases via a
 string mixin to pull enum members into the enclosing scope so
 it's compatible to C.
 Would it be wise to let the compiler do this automatically for
 extern(C) enums?

Why? You're using them in D code, not C code. What difference does it make if the enum is one that's used in C code or not? Why would you use such aliases with enums from C but not those from D/ What makes enums from C different? - Jonathan M Davis
Jan 25 2012
next sibling parent bcs <bcs example.com> writes:
On 01/25/2012 05:12 PM, Jonathan M Davis wrote:
 On Thursday, January 26, 2012 02:06:45 Trass3r wrote:
 When writing C bindings I usually create lots of aliases via a
 string mixin to pull enum members into the enclosing scope so
 it's compatible to C.
 Would it be wise to let the compiler do this automatically for
 extern(C) enums?

Why? You're using them in D code, not C code. What difference does it make if the enum is one that's used in C code or not? Why would you use such aliases with enums from C but not those from D/ What makes enums from C different? - Jonathan M Davis

Copy paste portability?
Jan 25 2012
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2012-01-26 01:12:40 +0000, Jonathan M Davis <jmdavisProg gmx.com> said:

 On Thursday, January 26, 2012 02:06:45 Trass3r wrote:
 When writing C bindings I usually create lots of aliases via a
 string mixin to pull enum members into the enclosing scope so
 it's compatible to C.
 Would it be wise to let the compiler do this automatically for
 extern(C) enums?

Why? You're using them in D code, not C code. What difference does it make if the enum is one that's used in C code or not? Why would you use such aliases with enums from C but not those from D/ What makes enums from C different?

Often C enum value naming takes into account that they'll live in the outer scope. For instance: enum UITableViewRowAnimation { UITableViewRowAnimationFade, UITableViewRowAnimationRight, UITableViewRowAnimationLeft, UITableViewRowAnimationTop, UITableViewRowAnimationBottom, UITableViewRowAnimationNone, UITableViewRowAnimationMiddle, UITableViewRowAnimationAutomatic = 100 } So if you're doing direct bindings where you don't want to change the names, how do you use that in D? UITableViewRowAnimation.UITableViewRowAnimationFade -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jan 26 2012
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 1/26/2012 8:55 PM, Michel Fortin wrote:
 On 2012-01-26 01:12:40 +0000, Jonathan M Davis <jmdavisProg gmx.com> said:

 On Thursday, January 26, 2012 02:06:45 Trass3r wrote:
 When writing C bindings I usually create lots of aliases via a
 string mixin to pull enum members into the enclosing scope so
 it's compatible to C.
 Would it be wise to let the compiler do this automatically for
 extern(C) enums?

Why? You're using them in D code, not C code. What difference does it make if the enum is one that's used in C code or not? Why would you use such aliases with enums from C but not those from D/ What makes enums from C different?

Often C enum value naming takes into account that they'll live in the outer scope. For instance: enum UITableViewRowAnimation { UITableViewRowAnimationFade, UITableViewRowAnimationRight, UITableViewRowAnimationLeft, UITableViewRowAnimationTop, UITableViewRowAnimationBottom, UITableViewRowAnimationNone, UITableViewRowAnimationMiddle, UITableViewRowAnimationAutomatic = 100 } So if you're doing direct bindings where you don't want to change the names, how do you use that in D? UITableViewRowAnimation.UITableViewRowAnimationFade

enum { UITableViewRowAnimationFade, UITableViewRowAnimationRight, UITableViewRowAnimationLeft, UITableViewRowAnimationTop, UITableViewRowAnimationBottom, UITableViewRowAnimationNone, UITableViewRowAnimationMiddle, UITableViewRowAnimationAutomatic = 100 }
Jan 26 2012
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
 alias int UITableViewRowAnimation;
 enum
 {
 UITableViewRowAnimationFade,
 UITableViewRowAnimationRight,
 UITableViewRowAnimationLeft,
 UITableViewRowAnimationTop,
 UITableViewRowAnimationBottom,
 UITableViewRowAnimationNone,
 UITableViewRowAnimationMiddle,
 UITableViewRowAnimationAutomatic = 100
 }

That works for interfacing c, but not c++. The following is a better solution, and should probably be in the standard library. enum UITableViewRowAnimation { UITableViewRowAnimationFade, UITableViewRowAnimationRight, UITableViewRowAnimationLeft, UITableViewRowAnimationTop, UITableViewRowAnimationBottom, UITableViewRowAnimationNone, UITableViewRowAnimationMiddle, UITableViewRowAnimationAutomatic = 100 } alias UITableViewRowAnimation.UITableViewRowAnimationFade UITableViewRowAnimationFade; alias UITableViewRowAnimation.UITableViewRowAnimationRight UITableViewRowAnimationRight; alias UITableViewRowAnimation.UITableViewRowAnimationLeft UITableViewRowAnimationLeft; alias UITableViewRowAnimation.UITableViewRowAnimationTop UITableViewRowAnimationTop; alias UITableViewRowAnimation.UITableViewRowAnimationBottom UITableViewRowAnimationBottom; alias UITableViewRowAnimation.UITableViewRowAnimationNo UITableViewRowAnimationNo; alias UITableViewRowAnimation.UITableViewRowAnimationMiddle UITableViewRowAnimationMiddle; alias UITableViewRowAnimation.UITableViewRowAnimationAutomatic UITableViewRowAnimationAutomatic; (could be mixin(exposeEnumMembers!UITableViewRowAnimation); )
Jan 26 2012
prev sibling parent Mike Wey <mike-wey example.com> writes:
On 01/26/2012 12:55 PM, Michel Fortin wrote:
 On 2012-01-26 01:12:40 +0000, Jonathan M Davis <jmdavisProg gmx.com> said:

 On Thursday, January 26, 2012 02:06:45 Trass3r wrote:
 When writing C bindings I usually create lots of aliases via a
 string mixin to pull enum members into the enclosing scope so
 it's compatible to C.
 Would it be wise to let the compiler do this automatically for
 extern(C) enums?

Why? You're using them in D code, not C code. What difference does it make if the enum is one that's used in C code or not? Why would you use such aliases with enums from C but not those from D/ What makes enums from C different?

Often C enum value naming takes into account that they'll live in the outer scope. For instance: enum UITableViewRowAnimation { UITableViewRowAnimationFade, UITableViewRowAnimationRight, UITableViewRowAnimationLeft, UITableViewRowAnimationTop, UITableViewRowAnimationBottom, UITableViewRowAnimationNone, UITableViewRowAnimationMiddle, UITableViewRowAnimationAutomatic = 100 } So if you're doing direct bindings where you don't want to change the names, how do you use that in D? UITableViewRowAnimation.UITableViewRowAnimationFade

I would probably use: enum UITableViewRowAnimation { Fade, Right, Left, Top, Bottom, None, Middle, Automatic = 100 } Then you can use it like so: UITableViewRowAnimation.Fade -- Mike Wey
Jan 28 2012
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-01-26 02:06, Trass3r wrote:
 When writing C bindings I usually create lots of aliases via a string
 mixin to pull enum members into the enclosing scope so it's compatible
 to C.
 Would it be wise to let the compiler do this automatically for extern(C)
 enums?

You can use anonymous enums. The members will then live in the global scope. You can then use just one alias to an int, uint or what's appropriate. -- /Jacob Carlborg
Jan 25 2012
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2012-01-26 11:51:10 +0000, "Trass3r" <un known.com> said:

 You can use anonymous enums. The members will then live in the global 
 scope. You can then use just one alias to an int, uint or what's 
 appropriate.

Yeah but you loose type safety.

Or if you absolutely need both type safety and the values to live in the outer scope, you can do this: enum Something { SomethingPointy, SomethingSmooth, } alias Something.SomethingPointy SomethingPointy; alias Something.SomethingSmooth SomethingSmooth; But that's rather extreme verbosity at the definition. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Jan 26 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-01-26 12:51, Trass3r wrote:
 You can use anonymous enums. The members will then live in the global
 scope. You can then use just one alias to an int, uint or what's
 appropriate.

Yeah but you loose type safety.

It's not type safe in C. But you can wrap it in a struct with alias this instead. -- /Jacob Carlborg
Jan 26 2012
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-01-26 14:23, Trass3r wrote:
 It's not type safe in C. But you can wrap it in a struct with alias
 this instead.

Yep, but in D we have strong enums, so why not use them.

What about be able to do something like this: enum Foo { public: bar, fooBar, } Foo f = bar; -- /Jacob Carlborg
Jan 26 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/26/2012 07:21 PM, Gor Gyolchanyan wrote:
 That would break the independence between parser and semantic
 analyzer, because there's no way to disambiguate "bar" from "Foo.bar"
 without knowing, that "Foo" is actually an enum.

No, it would not. The parser does not have to care.
 On Thu, Jan 26, 2012 at 5:41 PM, Jacob Carlborg<doob me.com>  wrote:
 On 2012-01-26 14:23, Trass3r wrote:
 It's not type safe in C. But you can wrap it in a struct with alias
 this instead.

Yep, but in D we have strong enums, so why not use them.

What about be able to do something like this: enum Foo { public: bar, fooBar, } Foo f = bar; -- /Jacob Carlborg


Jan 26 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/26/2012 02:41 PM, Jacob Carlborg wrote:
 On 2012-01-26 14:23, Trass3r wrote:
 It's not type safe in C. But you can wrap it in a struct with alias
 this instead.

Yep, but in D we have strong enums, so why not use them.

What about be able to do something like this: enum Foo { public: bar, fooBar, } Foo f = bar;

public is the wrong keyword. Furthermore, the solution is not better than mixin Import!Foo; I think the extern(C) enum proposal is pragmatic and makes more sense.
Jan 26 2012
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On 1/26/2012 10:23 PM, Trass3r wrote:
 It's not type safe in C. But you can wrap it in a struct with alias
 this instead.

Yep, but in D we have strong enums, so why not use them.

If your binding is for yourself, that's not a big deal. But if you're putting it out there for public consumption, then I think compatibility with the C version would be more important. If someone is looking at sample C code, you should make it they don't need to adjust it much at all. In some cases, this is unavoidable (bit fields, macros), but where it *is* avoidable, it should be.
Jan 26 2012
prev sibling next sibling parent "Trass3r" <un known.com> writes:
 You can use anonymous enums. The members will then live in the 
 global scope. You can then use just one alias to an int, uint 
 or what's appropriate.

Yeah but you loose type safety.
Jan 26 2012
prev sibling next sibling parent "Trass3r" <un known.com> writes:
 Or if you absolutely need both type safety and the values to 
 live in the outer scope, you can do this:

 	enum Something
 	{
 		SomethingPointy,
 		SomethingSmooth,
 	}
 	alias Something.SomethingPointy SomethingPointy;
 	alias Something.SomethingSmooth SomethingSmooth;

 But that's rather extreme verbosity at the definition.

As I said in the first post, this is what I actually do. Though I use a mixin like mixin(bringIntoCurrentScope!Something); But inserting this everywhere is rather annoying. And since the whole module is guarded by an extern(C): anyway I figured the compiler could do it for me.
Jan 26 2012
prev sibling next sibling parent "Trass3r" <un known.com> writes:
 Often C enum value naming takes into account that they'll live 
 in the outer scope. For instance:

 	enum UITableViewRowAnimation {
   	UITableViewRowAnimationFade,
 	    UITableViewRowAnimationRight,
 	    UITableViewRowAnimationLeft,
 	    UITableViewRowAnimationTop,
 	    UITableViewRowAnimationBottom,
 	    UITableViewRowAnimationNone,
 	    UITableViewRowAnimationMiddle,
 	    UITableViewRowAnimationAutomatic = 100
 	}

 So if you're doing direct bindings where you don't want to 
 change the names, how do you use that in D?

 	UITableViewRowAnimation.UITableViewRowAnimationFade

Precisely. See dmd's source code, enum STC {STCscope, STCforeach, ...}, enum MOD {MODconst, MODshared,...}, etc.
Jan 26 2012
prev sibling next sibling parent "Trass3r" <un known.com> writes:
 It's not type safe in C. But you can wrap it in a struct with 
 alias this instead.

Yep, but in D we have strong enums, so why not use them.
Jan 26 2012
prev sibling next sibling parent Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> writes:
That would break the independence between parser and semantic
analyzer, because there's no way to disambiguate "bar" from "Foo.bar"
without knowing, that "Foo" is actually an enum.

On Thu, Jan 26, 2012 at 5:41 PM, Jacob Carlborg <doob me.com> wrote:
 On 2012-01-26 14:23, Trass3r wrote:
 It's not type safe in C. But you can wrap it in a struct with alias
 this instead.

Yep, but in D we have strong enums, so why not use them.

What about be able to do something like this: enum Foo { public: =C2=A0 =C2=A0bar, =C2=A0 =C2=A0fooBar, } Foo f =3D bar; -- /Jacob Carlborg

--=20 Bye, Gor Gyolchanyan.
Jan 26 2012
prev sibling next sibling parent Trass3r <un known.com> writes:
 If your binding is for yourself, that's not a big deal. But if you're  
 putting it out there for public consumption, then I think compatibility  
 with the C version would be more important. If someone is looking at  
 sample C code, you should make it they don't need to adjust it much

Yep, one big argument for my proposal.
Jan 26 2012
prev sibling next sibling parent Trass3r <un known.com> writes:
 What about be able to do something like this:

 enum Foo
 {
 public:
 bar,
 fooBar,
 }

 Foo f = bar;

public is the wrong keyword. Furthermore, the solution is not better than mixin Import!Foo; I think the extern(C) enum proposal is pragmatic and makes more sense.

+1
Jan 26 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 1/27/12, Daniel Murphy <yebblies nospamgmail.com> wrote:
 (could be mixin(exposeEnumMembers!UITableViewRowAnimation); )

I don't think that's possible without passing the name of the enum. Once you pass the type to the "expose" template it won't know the enum is named "UITableViewRowAnimation". You /could/ use typeid() to get the mangled name and try to demangle that, but lo' and behold core.demangle doesn't work at compile-time. :/
Jan 28 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 1/28/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 I don't think that's possible without passing the name of the enum.

Nevermind, I was wrong. It appears typeid() returns a mangled name only when used in a *pragma* call, otherwise you do get the proper name.
Jan 28 2012
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
import std.conv;
import std.traits;

string exposeEnumMembersImpl(T)()
{
    string result;
    foreach (member; EnumMembers!UITableViewRowAnimation)
        result ~= "alias " ~ to!string(T.stringof) ~ "." ~
to!string(member) ~ " " ~ to!string(member) ~ ";\n";
    return result;
}

template exposeEnumMembers(T)
{
    enum exposeEnumMembers = exposeEnumMembersImpl!T();
}

mixin( exposeEnumMembers!UITableViewRowAnimation );

I did notice something about mixins, they hide existing aliases. If
you already had those aliases listed and you added this mixin, the
newly mixed in aliases will not conflict with the old ones. I find
this behavior rather odd, even if it's defined this way..
Jan 28 2012
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message 
news:mailman.101.1327757271.25230.digitalmars-d puremagic.com...
 I did notice something about mixins, they hide existing aliases. If
 you already had those aliases listed and you added this mixin, the
 newly mixed in aliases will not conflict with the old ones. I find
 this behavior rather odd, even if it's defined this way..

Are you sure? I thought it was the other way around, mixed-in members did not override existing ones...
Jan 28 2012
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 1/28/12, Daniel Murphy <yebblies nospamgmail.com> wrote:
 "Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message
 news:mailman.101.1327757271.25230.digitalmars-d puremagic.com...
 I did notice something about mixins, they hide existing aliases. If
 you already had those aliases listed and you added this mixin, the
 newly mixed in aliases will not conflict with the old ones. I find
 this behavior rather odd, even if it's defined this way..

Are you sure? I thought it was the other way around, mixed-in members did not override existing ones...

int foo, bar; alias foo target; alias bar target; // error mixin("alias bar target;"); // but use this instead and no problem..
Jan 28 2012
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message
 int foo, bar;
 alias foo target;
 alias bar target;  // error
 mixin("alias bar target;");  // but use this instead and no problem..

Yes, but does target end up referenceing foo or bar?
Jan 28 2012
prev sibling next sibling parent Trass3r <un known.com> writes:
 import std.conv;
 import std.traits;

 string exposeEnumMembersImpl(T)()
 {
     string result;
     foreach (member; EnumMembers!UITableViewRowAnimation)
         result ~= "alias " ~ to!string(T.stringof) ~ "." ~
 to!string(member) ~ " " ~ to!string(member) ~ ";\n";
     return result;
 }

 template exposeEnumMembers(T)
 {
     enum exposeEnumMembers = exposeEnumMembersImpl!T();
 }

 mixin( exposeEnumMembers!UITableViewRowAnimation );

The extra template is senseless. And no imports are needed. string bringToCurrentScope(alias EnumType)() { string res = ""; foreach (e; __traits(allMembers, EnumType)) { res ~= "alias " ~ EnumType.stringof ~ "." ~ e ~ " " ~ e ~ ";\n"; } return res; } mixin(bringToCurrentScope!EnumName); Anyway the whole point of this thread is to get rid of a crappy mixin(blabla); after each enum I define!
Jan 28 2012
prev sibling next sibling parent Trass3r <un known.com> writes:
 The following is a better solution, and should probably be in the  
 standard library.

 (could be mixin(exposeEnumMembers!UITableViewRowAnimation); )

That's what I already do. The whole point of the thread is to get rid of that crap after each enum.
Jan 28 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 1/28/12, Trass3r <un known.com> wrote:
 The extra template is senseless.

No it's not. Your sample won't compile with -property. That's why I've wrapped it into a template, to avoid having to use parens.
 And no imports are needed.

Fair enough. But if we're going to be anal about it you should add a constraint `if (is(EnumType == enum))`. Otherwise your sample will compile for non-enum types, which may or may not be what you want. You probably don't want to end up with static method imported into the local scope by accident. For classes it will generate: alias MyClass.toString toString; alias MyClass.toHash toHash; alias MyClass.opCmp opCmp; alias MyClass.opEquals opEquals; alias MyClass.Monitor Monitor; alias MyClass.factory factory; Fun! :)
Jan 28 2012
prev sibling next sibling parent Trass3r <un known.com> writes:
 No it's not. Your sample won't compile with -property. That's why I've
 wrapped it into a template, to avoid having to use parens.

Never used -property. I don't mind adding parentheses either.
 Fair enough. But if we're going to be anal about it you should add a
 constraint `if (is(EnumType == enum))`. Otherwise your sample will
 compile for non-enum types

I do have that constraint in some other version of the function in another project. So it's an old one.
Jan 28 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 1/28/12, Trass3r <un known.com> wrote:
 No it's not. Your sample won't compile with -property. That's why I've
 wrapped it into a template, to avoid having to use parens.

Never used -property.

I don't use it either myself, but I believe someone mentioned it's going to become the default one day.
Jan 28 2012
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, January 28, 2012 23:10:01 Andrej Mitrovic wrote:
 On 1/28/12, Trass3r <un known.com> wrote:
 No it's not. Your sample won't compile with -property. That's why I've
 wrapped it into a template, to avoid having to use parens.

Never used -property.

I don't use it either myself, but I believe someone mentioned it's going to become the default one day.

Yes. -property was introduced to give an opportunity for people to migrate to property enforcement and to give the compiler a chance to iron out any bugs that it may have with regards to property enforcement. But property is supposed to be enforced. It only isn't because we're still in a period of migration from when property didn't exist and you could call any no-argument (or single-argument function when using assignment) with or without parens. - Jonathan M Davis
Jan 28 2012