www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Fastest way to check using if identifier has already been defined,

reply drathier <forum.dlang.org fi.fo> writes:
I'm generating some code. Some of the generated types need to be 
overridden, so I define them manually at the top of the generated 
file. Then I need to guard against redefining the identifier 
(type/value/function) later on, in the generated code.

I'm currently using `static if (!__traits(compiles, thingy)) {` 
to avoid redefining things twice.

Of course the proper fix is to not generate code for the 
identifiers which are already manually defined, and not generate 
any `static if`s at all, but until then, is there a faster way 
than `static if (__traits(compiles, ...` to check if a 
type/value/function has already been defined?
Jun 03 2020
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Wednesday, 3 June 2020 at 09:03:22 UTC, drathier wrote:
 I'm generating some code. Some of the generated types need to 
 be overridden, so I define them manually at the top of the 
 generated file. Then I need to guard against redefining the 
 identifier (type/value/function) later on, in the generated 
 code.

 I'm currently using `static if (!__traits(compiles, thingy)) {` 
 to avoid redefining things twice.

 Of course the proper fix is to not generate code for the 
 identifiers which are already manually defined, and not 
 generate any `static if`s at all, but until then, is there a 
 faster way than `static if (__traits(compiles, ...` to check if 
 a type/value/function has already been defined?
You can use this template: enum Exists(alias T) = is(typeof(T)); I don't know if there's a faster way bu this technic is used, notatbly in phobos, to workaroud issues of double declaration in `static foreach`
Jun 03 2020
next sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Wednesday, 3 June 2020 at 09:39:34 UTC, Basile B. wrote:
 You can use this template:

   enum Exists(alias T) = is(typeof(T));

 I don't know if there's a faster way bu this technic is used, 
 notatbly in phobos, to workaroud issues of double declaration 
 in `static foreach`
enum Exists(alias T) = is(typeof(T)); static assert(!Exists!bar); // undefined identifier bar -- Simen
Jun 03 2020
parent reply Basile B. <b2.temp gmx.com> writes:
On Wednesday, 3 June 2020 at 10:24:44 UTC, Simen Kjærås wrote:
 On Wednesday, 3 June 2020 at 09:39:34 UTC, Basile B. wrote:
 You can use this template:

   enum Exists(alias T) = is(typeof(T));

 I don't know if there's a faster way bu this technic is used, 
 notatbly in phobos, to workaroud issues of double declaration 
 in `static foreach`
enum Exists(alias T) = is(typeof(T)); static assert(!Exists!bar); // undefined identifier bar -- Simen
This is because the template parameter must be resolved to a valid symbol or type. This version other version bypass the problem: --- enum Exists(string s) = is(typeof(mixin(s))); void main() { static if (!Exists!"foo") int foo; foo = 42; } ---
Jun 03 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 3 June 2020 at 13:24:17 UTC, Basile B. wrote:
 This is because the template parameter must be resolved to a 
 valid symbol or type.
 This version other version bypass the problem:

 ---
 enum Exists(string s) = is(typeof(mixin(s)));

 void main()
 {
     static if (!Exists!"foo")
         int foo;
     foo = 42;
 }
 ---
Fails if the symbol in question is the name of a type. struct Foo {} enum Exists(string s) = is(typeof(mixin(s))); static assert(Exists!"Foo"); // false What you actually want is something like this: enum Exists(string s) = __traits(compiles, { mixin("alias _ = ", s, ";"); });
Jun 03 2020
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Wednesday, 3 June 2020 at 15:25:51 UTC, Paul Backus wrote:
 On Wednesday, 3 June 2020 at 13:24:17 UTC, Basile B. wrote:
 This is because the template parameter must be resolved to a 
 valid symbol or type.
 This version other version bypass the problem:

 ---
 enum Exists(string s) = is(typeof(mixin(s)));

 void main()
 {
     static if (!Exists!"foo")
         int foo;
     foo = 42;
 }
 ---
Fails if the symbol in question is the name of a type. struct Foo {} enum Exists(string s) = is(typeof(mixin(s))); static assert(Exists!"Foo"); // false What you actually want is something like this: enum Exists(string s) = __traits(compiles, { mixin("alias _ = ", s, ";"); });
And they both fail if the thing you refer to isn't available in the scope where Exists is defined. I believe this covers most cases, but there may very well be corner cases I haven't considered: string exists(string s) { return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); })"; } // Handles values: int global; unittest { int local; { int outOfScope; } static assert(mixin("local".exists)); static assert(mixin("global".exists)); static assert(!mixin("outOfScope".exists)); } // And types: struct Global {} unittest { struct Local {} { struct OutOfScope; } static assert(mixin("Global".exists)); static assert(mixin("Local".exists)); static assert(!mixin("OutOfScope".exists)); } // But not expressions: static assert(!mixin("1+2".exists)); // Correctly fails for missing declarations: static assert(!mixin("nowhere".exists)); Like Stefan said though, we're quite a bit off from the original request - the above certainly shouldn't be faster than drathier's original code. The only advantage I see is that it might read a little clearer. -- Simen
Jun 04 2020
parent reply Q. Schroll <qs.il.paperinik gmail.com> writes:
On Thursday, 4 June 2020 at 09:03:40 UTC, Simen Kjærås wrote:
 string exists(string s) {
     return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); 
 })";
 }
Little nitpicking, but D has many forms of string literals. Escaping is hard to read especially without syntax highlighting. Escaping to me is an old hack C did we shouldn't really use. string exists(string s) { return `__traits(compiles, { mixin("alias _ = ` ~ s ~ `;"); })`; } The _ as a name, to me, proves that a __traits(freshName), that returns a string that is distinct from every symbol name visible from the point it's defined, would be useful in these occasions. Because if someone used _ as an identifier in a context where the `exisits` function is used, it might fail.
Jun 04 2020
next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Thursday, 4 June 2020 at 14:20:45 UTC, Q. Schroll wrote:
 On Thursday, 4 June 2020 at 09:03:40 UTC, Simen Kjærås wrote:
 string exists(string s) {
     return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); 
 })";
 }
Little nitpicking, but D has many forms of string literals. Escaping is hard to read especially without syntax highlighting. Escaping to me is an old hack C did we shouldn't really use. string exists(string s) { return `__traits(compiles, { mixin("alias _ = ` ~ s ~ `;"); })`; } The _ as a name, to me, proves that a __traits(freshName), that returns a string that is distinct from every symbol name visible from the point it's defined, would be useful in these occasions. Because if someone used _ as an identifier in a context where the `exisits` function is used, it might fail.
Don't have a unique name facility now? ... I remember seeing one. Could have been a mirage I guess.
Jun 04 2020
prev sibling parent Paul Backus <snarwin gmail.com> writes:
On Thursday, 4 June 2020 at 14:20:45 UTC, Q. Schroll wrote:
 Little nitpicking, but D has many forms of string literals. 
 Escaping is hard to read especially without syntax 
 highlighting. Escaping to me is an old hack C did we shouldn't 
 really use.

     string exists(string s) {
         return `__traits(compiles, { mixin("alias _ = ` ~ s ~ 
 `;"); })`;
     }

 The _ as a name, to me, proves that a __traits(freshName), that 
 returns a string that is distinct from every symbol name 
 visible from the point it's defined,  would be useful in these 
 occasions. Because if someone used _ as an identifier in a 
 context where the `exisits` function is used, it might fail.
In the Lisp language family, this feature is called "gensym" (generate symbol). It is indeed quite useful to have when generating code. I believe it was proposed at one point to add a special __GENSYM__ keyword, similar to the current __FILE__, __LINE__, __MODULE__, etc. that would evaluate to a unique identifier each time it was used. I'm not sure what became of that proposal. Maybe it needed a DIP and no one was available to write one?
Jun 04 2020
prev sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Wednesday, 3 June 2020 at 09:39:34 UTC, Basile B. wrote:
 On Wednesday, 3 June 2020 at 09:03:22 UTC, drathier wrote:
 [...]
You can use this template: enum Exists(alias T) = is(typeof(T)); I don't know if there's a faster way bu this technic is used, notatbly in phobos, to workaroud issues of double declaration in `static foreach`
Please don't promote templates like this as long as they are not really zero-cost. They don't add much to compile time granted. But Barnacles.
Jun 03 2020
prev sibling parent drathier <forum.dlang.org fi.fo> writes:
On Wednesday, 3 June 2020 at 09:03:22 UTC, drathier wrote:
 I'm generating some code. Some of the generated types need to 
 be overridden, so I define them manually at the top of the 
 generated file. Then I need to guard against redefining the 
 identifier (type/value/function) later on, in the generated 
 code.

 I'm currently using `static if (!__traits(compiles, thingy)) {` 
 to avoid redefining things twice.

 Of course the proper fix is to not generate code for the 
 identifiers which are already manually defined, and not 
 generate any `static if`s at all, but until then, is there a 
 faster way than `static if (__traits(compiles, ...` to check if 
 a type/value/function has already been defined?
This seems more complicated than I initially assumed. Is there a faster way if we separate the question to find just one of types, templates or top-level values at a time, into three different solutions? The definitions and static ifs are always always top level definitions/statements in my case.
Jun 04 2020