Jump to page: 1 2
Thread overview
Fastest way to check using if identifier has already been defined, using static if or similar?
Jun 03, 2020
drathier
Jun 03, 2020
Basile B.
Jun 03, 2020
Simen Kjærås
Jun 03, 2020
Basile B.
Jun 03, 2020
Paul Backus
Jun 04, 2020
Simen Kjærås
Jun 04, 2020
Q. Schroll
Jun 04, 2020
Stefan Koch
Jun 04, 2020
Paul Backus
Jun 03, 2020
Stefan Koch
Jun 04, 2020
drathier
June 03, 2020
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
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
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
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
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
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
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
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
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
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?
« First   ‹ Prev
1 2