Thread overview
How does one use toString() inside of the class's hash function? Compiler error
April 01
module def;

class Def
{
public:
   this(string latex)
   {
      this.latex = latex;
   }

   this()
   {
      this.latex = "";
   }

   override string toString() const
   {
      return latex;
   }

   string opUnary(string op="*")() const
   {
      return toString();
   }

   override bool opEquals(const Object rhs) const
   {
      return rhs is this;
   }

   override nothrow @safe size_t toHash()
   {
      auto s = toString();
      typeid(s).getHash(&s);
   }

private:
   string latex;
}

Something like this. I know I could very well hash latex member, but what if the user redefines toString() ? So I would like to call toString(), but DMD compiler bitches:

Error: @safe function def.Def.toHash cannot call @system function def.Def.toString: def.Def.toString is declared here...

I've always wondered about this, because I run into it every time I have an idea and begin to code. It's a major bottleneck to my coding performance.

How can we fix it?

April 01

On Tuesday, 1 April 2025 at 09:21:25 UTC, Daniel Donnelly, Jr. wrote:

>

It's a major bottleneck to my coding performance.

I don't see a good reason to use a random address or some content of a string for hashing. I'm also amazed that a user might be allowed to change values ​​at will; values that the system might need to find the data that user is searching for.

-manfred

April 01

On Tuesday, 1 April 2025 at 09:21:25 UTC, Daniel Donnelly, Jr. wrote:

>

Something like this. I know I could very well hash latex member, but what if the user redefines toString() ? So I would like to call toString(), but DMD compiler bitches:

Error: @safe function def.Def.toHash cannot call @system function def.Def.toString: def.Def.toString is declared here...

This works for me:

   @safe nothrow override string toString() const
   {
      return latex;
   }

   override nothrow @safe size_t toHash()
   {
      auto s = toString();
      return hashOf(s);
   }

Changes made:

  • Mark toString as @safe and nothrow.
  • Use hashOf instead of getHash.
April 02

On Tuesday, 1 April 2025 at 09:21:25 UTC, Daniel Donnelly, Jr. wrote:

>

Error: @safe function def.Def.toHash cannot call @system function def.Def.toString: def.Def.toString is declared here...

I've always wondered about this, because I run into it every time I have an idea and begin to code.  It's a major bottleneck to my coding performance.

How can we fix it?

The function (toHash) does not return any values. Maybe it's the reason for the error, but let me share code for inspiration. Maybe it's not simple, but I use this way:

class C(T)
{
  size_t id;
  private T latex;

  invariant {
    static assert(!__traits(isFloating, T));
  }

  this() {
    if (latex == latex.init) id = size_t.max;
    else id = typeid(latex).getHash(&latex);
  }

  this(T value) {
    latex = value;
    this();
  }

  size_t length() => toString.length;//*
  string opUnary(string op)() const
  if (op == "*") {
    import std.string : format;
    return format("@%s", &latex);
  }//*/
  
  override const @safe nothrow
  {
    string toString()
    {
      import std.conv : to;
      return latex.to!string;
    }

    size_t toHash()
    {
      static if (is(T == string))
      {
        auto i = toString;
        return i.hashOf;
      } else return id;
    }

    bool opEquals(Object rhs)
    {
      return rhs.toHash == this.toHash; /*
      return rhs is this;//*/
    }
  }
}

unittest
{
  auto cHelper(T)(T value) => new C!T(value);

  auto a = cHelper("foo");
  auto b = cHelper("zoo");

  assert(a != b, "equalised!");
  assert(*a != *b);

  // but ->
  assert(a.id == a.toHash); // or
  assert(b.id == b.toHash);

  imported!"std.stdio".writeln(*a);
  // "@7F......"
}

SDB@79