digitalmars.D.learn - Fastest way to check using if identifier has already been defined,
- drathier (11/11) Jun 03 2020 I'm generating some code. Some of the generated types need to be
- Basile B. (6/18) Jun 03 2020 You can use this template:
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (5/10) Jun 03 2020 enum Exists(alias T) = is(typeof(T));
- Basile B. (13/25) Jun 03 2020 This is because the template parameter must be resolved to a
- Paul Backus (8/20) Jun 03 2020 Fails if the symbol in question is the name of a type.
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (40/62) Jun 04 2020 And they both fail if the thing you refer to isn't available in
- Q. Schroll (13/17) Jun 04 2020 Little nitpicking, but D has many forms of string literals.
- Stefan Koch (4/22) Jun 04 2020 Don't have a unique name facility now?
- Paul Backus (9/22) Jun 04 2020 In the Lisp language family, this feature is called "gensym"
- Stefan Koch (5/12) Jun 03 2020 Please don't promote templates like this as long as they are not
- drathier (6/18) Jun 04 2020 This seems more complicated than I initially assumed. Is there a
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
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
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
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: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; } ---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
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
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: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. -- SimenThis 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 04 2020
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
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:Don't have a unique name facility now? ... I remember seeing one. Could have been a mirage I guess.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
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
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: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.[...]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
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