Thread overview
Unqualified class name
Aug 21, 2021
Jeremy T. Gibson
Aug 21, 2021
Ali Çehreli
Aug 21, 2021
Jeremy T. Gibson
Aug 21, 2021
jfondren
Aug 22, 2021
Ali Çehreli
Aug 22, 2021
jfondren
Aug 21, 2021
jfondren
Aug 21, 2021
Jeremy T. Gibson
August 21, 2021

I saw this thread -- https://forum.dlang.org/post/hdkvezicxfvehbtvjkfu@forum.dlang.org -- which works at compile time (although templating seems like overkill for my purpose), but is there a simple way to get the unqualified name of a class at runtime without having to pass it through std.format? typeid(class).name always yields the full classname, including its module information (i.e., "modulename.classname"), where I only want "classname" on its own.

I'm currently using manually-assigned literals to store the name of each class, which seems... wrong. ;-)

If it matters or makes things simpler, the class is attempting to report its own name in one of its own methods, rather than an external function attempting to deduce the name of an arbitrary object at runtime.

August 21, 2021
On 8/21/21 10:33 AM, Jeremy T. Gibson wrote:

> `typeid(class).name` always yields the full classname, including its module information (i.e., "modulename.classname"), where I only want "classname" on its own.

I've been reminded of __traits(identifier) on this forum just yesterday:

import std.stdio;

class Coo {

  string name() const {
    return __traits(identifier, typeof(this));
  }
}

void main() {
  auto c = new Coo();
  writeln(c.name());
}

Ali
August 21, 2021

On Saturday, 21 August 2021 at 17:33:51 UTC, Jeremy T. Gibson wrote:

>

is there a simple way to get the unqualified name of a class at runtime without having to pass it through std.format? typeid(class).name always yields the full classname, including its module information (i.e., "modulename.classname"), where I only want "classname" on its own.

https://dlang.org/phobos/object.html#.TypeInfo_Class.name is all you have there, and it's just a string, so the simple way is to manipulate the string.

This seems a bit silly but I'm not worried about VMS 2.0 coming along and changing how extensions work ("nodot".extension == "" however, so if module-less classes are possible then this would fail with a RangeError):

class Whoami {
    string report() {
        import std.path : extension;

        return "class: " ~ typeid(this).name.extension[1..$];
    }
}

class AnotherOne : Whoami {}

unittest {
    assert((new Whoami).report == "class: Whoami");
    assert((new AnotherOne).report == "class: AnotherOne");
}

string unqualified(string name) {
    import std.string : lastIndexOf;
    import std.algorithm : min;

    const i = name.lastIndexOf('.');
    return i == -1 ? name : name[min(i+1, $) .. $];
}

unittest {
    assert(typeid(new Whoami).name.unqualified == "Whoami");
    assert(typeid(new AnotherOne).name.unqualified == "AnotherOne");
    assert("".unqualified == "");
    assert("x".unqualified == "x");
    assert("x.".unqualified == "");
}
August 21, 2021
On Saturday, 21 August 2021 at 18:27:34 UTC, Ali Çehreli wrote:
>     return __traits(identifier, typeof(this));

That works perfectly!  Thanks. =)
August 21, 2021

On Saturday, 21 August 2021 at 18:45:07 UTC, jfondren wrote:

>

On Saturday, 21 August 2021 at 17:33:51 UTC, Jeremy T. Gibson wrote:

>

is there a simple way to get the unqualified name of a class at runtime without having to pass it through std.format? typeid(class).name always yields the full classname, including its module information (i.e., "modulename.classname"), where I only want "classname" on its own.

https://dlang.org/phobos/object.html#.TypeInfo_Class.name is all you have there, and it's just a string, so the simple way is to manipulate the string.

>

string unqualified(string name) {
import std.string : lastIndexOf;
import std.algorithm : min;

const i = name.lastIndexOf('.');
return i == -1 ? name : name[min(i+1, $) .. $];

Parsing was always an option, but anytime I come across a solution where parsing/formatting seems to be the answer, it always feels more hacky than a genuine solution. Hacks can be fine, especially in low-frequency code like the stuff I'm revisiting this month, but I always prefer direct library-based or language-based solutions whenever humanly possible. Dlang's reference docs unfortunately assume a level of expertise with the language (especially, expertise with code generation and compiler specs) that makes it much harder for me to "ask the right questions" when I'm searching: I'm really not much of a programmer. Heh.

August 21, 2021

On Saturday, 21 August 2021 at 21:13:58 UTC, Jeremy T. Gibson wrote:

>

On Saturday, 21 August 2021 at 18:27:34 UTC, Ali Çehreli wrote:

>
return __traits(identifier, typeof(this));

That works perfectly! Thanks. =)

This is exactly the solution you linked to in your first post, and found wanting.

class Whoami {
    string name() {
        return __traits(identifier, typeof(this));
    }
}
class AnotherOne : Whoami { }

unittest {
    assert((new Whoami).name == "Whoami");
    assert((new AnotherOne).name == "Whoami");
}
August 21, 2021
On 8/21/21 2:48 PM, jfondren wrote:
> On Saturday, 21 August 2021 at 21:13:58 UTC, Jeremy T. Gibson wrote:
>> On Saturday, 21 August 2021 at 18:27:34 UTC, Ali Çehreli wrote:
>>>     return __traits(identifier, typeof(this));
>>
>> That works perfectly!  Thanks. =)
> 
> This is exactly the solution you linked to in your first post, and found wanting.
> 
> ```d
> class Whoami {
>      string name() {
>          return __traits(identifier, typeof(this));
>      }
> }
> class AnotherOne : Whoami { }
> 
> unittest {
>      assert((new Whoami).name == "Whoami");
>      assert((new AnotherOne).name == "Whoami");
> }
> ```

I did not read the linked thread but a "this template parameter" seems to work in this case:

class Whoami {
  string name(this This)() const {
    return __traits(identifier, This);
  }
}
class AnotherOne : Whoami { }

unittest {
  assert((new Whoami).name == "Whoami");
  assert((new AnotherOne).name == "AnotherOne");
}

void main() {
}

Ali

August 22, 2021

On Sunday, 22 August 2021 at 00:18:18 UTC, Ali Çehreli wrote:

>

I did not read the linked thread but a "this template parameter" seems to work in this case:

class Whoami {
string name(this This)() const {
return __traits(identifier, This);
}
}
class AnotherOne : Whoami { }

unittest {
assert((new Whoami).name == "Whoami");
assert((new AnotherOne).name == "AnotherOne");
}

void main() {
}

Ali

That's not enough to make runtime dispatch out of static dispatch:

class Whoami {
    string name(this This)() const {
        return __traits(identifier, This);
    }

    string rtname() const {
        import std.path : extension;

        return typeid(this).name.extension[1 .. $];
    }
}

class AnotherOne : Whoami { }

unittest {
    import std.algorithm : map, equal;

    auto list = [new Whoami, new AnotherOne];
    assert(list.map!(o => o.name).equal(["Whoami", "Whoami"]));
    assert(list.map!(o => o.rtname).equal(["Whoami", "AnotherOne"]));
}

The next stage of complication is to have compiled library code that loops over Whoami[] getting some subtypes of Whoami that were defined unknowable to the library.