Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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.
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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?
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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.
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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.
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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.
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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, ";"); });
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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; } ---
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
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`
Fastest way to check using if identifier has already been defined, using static if or similar?
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?