Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 03, 2020 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? |
June 03, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to drathier | 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`
|
June 03, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | 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
|
June 03, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | 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;
}
---
|
June 03, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | 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, ";"); });
|
June 03, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | 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.
|
June 04, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | 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 |
June 04, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | 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.
|
June 04, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Q. Schroll | 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.
|
June 04, 2020 Re: Fastest way to check using if identifier has already been defined, using static if or similar? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Q. Schroll | 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?
|
Copyright © 1999-2021 by the D Language Foundation