Dennis brought up a discussion about reducing the size of object.d that came up in a PR thread. Specifically, moving things into separate modules, then making object.d a list of public imports would make it easier to maintain a custom object.d.

It is unfortunate that my suggestion was used to push an other idea

A public import, is the same problem

My issue with `object.d` is it is shadowing symbols


`destroy` for example

If i want a `destroy` function, i call destroy, but if i made a typo in my function or forgot to actually create it, then it'll silently call `destroy` from `object.d` without letting you know about it, that's what prompted me to make the PR

I now banned the `destroy` name, and instead use `dispose` as people on the IRC suggested me to do, wich in restrospec is a better word indeed


But i figured i should not expect such changes, so instead i now compile with `-betterC` and a custom `object.d` for all of my projects

The other unfortunate thing is i now have to deal with issues like this, and incorporate hacks into my codebases for LDC: https://github.com/ldc-developers/ldc/issues/2425#issuecomment-1193330845


The consensus was that with D's built-in ability to differentiate symbols (FQN, static imports), this isn't a problem. Iain closed the PR after the meeting, noting that we agreed something needs to be done about object.d, "but not this".


The worst part is that file should not be needed at all to begin with


You can't do simple ptr/slice casting without it, and you can't use enums without it

If `destroy` is essential to D, then it should be upgraded to a builtin and reserved keyword, if it is just an utility function, then it shouldn't be in the global scope, or it should be prefixed `__destroy`



There needs a way to differentiate functions used for language support like `switch` and `cast` with other utility functions, 2 different concerns


This is what i have to carry to opt out this specific thing (luckily i do not use any other features): (see at the end of the post)

And one recent issue i had, because of the custom `object.d` route:

https://i.imgur.com/Ye9ewJP.png

I couldn't figure out what caused the issue, thanks to Adam, compiling with `dmd -v` pointed out the problematic import: `import core.sys.windows.threadaux;`

Pay as you go is the way to go, but the experience should be drastically improved imo


```D
module object;

alias size_t = typeof(int.sizeof);
alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0);

alias sizediff_t = ptrdiff_t; // For backwards compatibility only.
/**
 * Bottom type.
 * See $(DDSUBLINK spec/type, noreturn).
 */
alias noreturn = typeof(*null);

alias hash_t = size_t; // For backwards compatibility only.
alias equals_t = bool; // For backwards compatibility only.

alias string  = immutable(char)[];
alias wstring = immutable(wchar)[];
alias dstring = immutable(dchar)[];


bool __equals(T1, T2)(scope const T1[] lhs, scope const T2[] rhs)
@nogc nothrow pure @trusted
if (__traits(isScalar, T1) && __traits(isScalar, T2))
{
    if (lhs.length != rhs.length)
        return false;

    static if (T1.sizeof == T2.sizeof
// Signedness needs to match for types that promote to int. // (Actually it would be okay to memcmp bool[] and byte[] but that is
        // probably too uncommon to be worth checking for.)
&& (T1.sizeof >= 4 || __traits(isUnsigned, T1) == __traits(isUnsigned, T2))
        && !__traits(isFloating, T1) && !__traits(isFloating, T2))
    {
        if (!__ctfe)
        {
// This would improperly allow equality of integers and pointers // but the CTFE branch will stop this function from compiling then.

            import core.stdc.string : memcmp;
            return lhs.length == 0 ||
0 == memcmp(cast(const void*) lhs.ptr, cast(const void*) rhs.ptr, lhs.length * T1.sizeof);
        }
    }


    foreach (const i; 0 .. lhs.length)
    {
static if (__traits(isStaticArray, at(lhs, 0))) // "Fix" for -betterC
        {
if (at(lhs, i)[] != at(rhs, i)[]) // T1[N] != T2[N] doesn't compile with -betterC.
                return false;
        }
        else
        {
            if (at(lhs, i) != at(rhs, i))
                return false;
        }
    }
    return true;
}

bool __equals(T1, T2)(scope T1[] lhs, scope T2[] rhs)
if (!__traits(isScalar, T1) || !__traits(isScalar, T2))
{
    if (lhs.length != rhs.length)
    {
        return false;
    }
    if (lhs.length == 0)
        return true;

    static if (useMemcmp!(T1, T2))
    {
        if (!__ctfe)
        {
static bool trustedMemcmp(scope T1[] lhs, scope T2[] rhs) @trusted @nogc nothrow pure
            {
                pragma(inline, true);
                import core.stdc.string : memcmp;
return memcmp(cast(void*) lhs.ptr, cast(void*) rhs.ptr, lhs.length * T1.sizeof) == 0;
            }
            return trustedMemcmp(lhs, rhs);
        }
        else
        {

            foreach (const i; 0 .. lhs.length)
            {
static if (__traits(isStaticArray, at(lhs, 0))) // "Fix" for -betterC
                {
if (at(lhs, i)[] != at(rhs, i)[]) // T1[N] != T2[N] doesn't compile with -betterC.
                        return false;
                }
                else
                {
                    if (at(lhs, i) != at(rhs, i))
                        return false;
                }
            }
            return true;
        }
    }
    else
    {

    foreach (const i; 0 .. lhs.length)
    {
static if (__traits(isStaticArray, at(lhs, 0))) // "Fix" for -betterC
        {
if (at(lhs, i)[] != at(rhs, i)[]) // T1[N] != T2[N] doesn't compile with -betterC.
                return false;
        }
        else
        {
            if (at(lhs, i) != at(rhs, i))
                return false;
        }
    }
        return true;
    }
}

pragma(inline, true)
ref at(T)(T[] r, size_t i) @trusted
// exclude opaque structs due to https://issues.dlang.org/show_bug.cgi?id=20959
    if (!(is(T == struct) && !is(typeof(T.sizeof))))
{
    static if (is(immutable T == immutable void))
        return (cast(ubyte*) r.ptr)[i];
    else
        return r.ptr[i];
}

template BaseType(T)
{
    static if (__traits(isStaticArray, T))
        alias BaseType = BaseType!(typeof(T.init[0]));
    else static if (is(immutable T == immutable void))
        alias BaseType = ubyte;
    else static if (is(T == E*, E))
        alias BaseType = size_t;
    else
        alias BaseType = T;
}

template useMemcmp(T1, T2)
{
    static if (T1.sizeof != T2.sizeof)
        enum useMemcmp = false;
    else
    {
        alias B1 = BaseType!T1;
        alias B2 = BaseType!T2;
enum useMemcmp = __traits(isIntegral, B1) && __traits(isIntegral, B2) && !( (B1.sizeof < 4 || B2.sizeof < 4) && __traits(isUnsigned, B1) != __traits(isUnsigned, B2) );
    }
}



TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from)
{
   const fromSize = from.length * TFrom.sizeof;
   const toLength = fromSize / TTo.sizeof;

   if ((fromSize % TTo.sizeof) != 0)
   {
//onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
        assert(0);
   }

   struct Array
   {
       size_t length;
       void* ptr;
   }
   auto a = cast(Array*)&from;
   a.length = toLength; // jam new length
   return *cast(TTo[]*)a;
}



// switch
extern(C) void __switch_error()(string file = __FILE__, size_t line = __LINE__)
{
    //__switch_errorT(file, line);
    wasm.abort();
}

extern(C) int __switch(T, caseLabels...)(/*in*/ const scope T[] condition) pure nothrow @safe @nogc
{
    // This closes recursion for other cases.
    static if (caseLabels.length == 0)
    {
        return int.min;
    }
    else static if (caseLabels.length == 1)
    {
        return __cmp(condition, caseLabels[0]) == 0 ? 0 : int.min;
    }
    // To be adjusted after measurements
    // Compile-time inlined binary search.
    else static if (caseLabels.length < 7)
    {
        int r = void;
        enum mid = cast(int)caseLabels.length / 2;
        if (condition.length == caseLabels[mid].length)
        {
            r = __cmp(condition, caseLabels[mid]);
            if (r == 0) return mid;
        }
        else
        {
// Equivalent to (but faster than) condition.length > caseLabels[$ / 2].length ? 1 : -1 r = ((condition.length > caseLabels[mid].length) << 1) - 1;
        }

        if (r < 0)
        {
            // Search the left side
            return __switch!(T, caseLabels[0 .. mid])(condition);
        }
        else
        {
            // Search the right side
return __switch!(T, caseLabels[mid + 1 .. $])(condition) + mid + 1;
        }
    }
    else
    {
// Need immutable array to be accessible in pure code, but case labels are // currently coerced to the switch condition type (e.g. const(char)[]). pure @trusted nothrow @nogc asImmutable(scope const(T[])[] items)
        {
            assert(__ctfe); // only @safe for CTFE
immutable T[][caseLabels.length] result = cast(immutable)(items[]);
            return result;
        }
static immutable T[][caseLabels.length] cases = asImmutable([caseLabels]);

        // Run-time binary search in a static array of labels.
        return __switchSearch!T(cases[], condition);
    }
}

extern(C) int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted
    if (__traits(isScalar, T))
{
    // Compute U as the implementation type for T
    static if (is(T == ubyte) || is(T == void) || is(T == bool))
        alias U = char;
    else static if (is(T == wchar))
        alias U = ushort;
    else static if (is(T == dchar))
        alias U = uint;
    else static if (is(T == ifloat))
        alias U = float;
    else static if (is(T == idouble))
        alias U = double;
    else static if (is(T == ireal))
        alias U = real;
    else
        alias U = T;

    static if (is(U == char))
    {
        import core.internal.string : dstrcmp;
        return dstrcmp(cast(char[]) lhs, cast(char[]) rhs);
    }
    else static if (!is(U == T))
    {
        // Reuse another implementation
        return __cmp(cast(U[]) lhs, cast(U[]) rhs);
    }
    else
    {
        version (BigEndian)
static if (__traits(isUnsigned, T) ? !is(T == __vector) : is(T : P*, P))
        {
            if (!__ctfe)
            {
int c = mem.memcmp(lhs.ptr, rhs.ptr, (lhs.length <= rhs.length ? lhs.length : rhs.length) * T.sizeof);
                if (c)
                    return c;
static if (size_t.sizeof <= uint.sizeof && T.sizeof >= 2) return cast(int) lhs.length - cast(int) rhs.length;
                else
return int(lhs.length > rhs.length) - int(lhs.length < rhs.length);
            }
        }

immutable len = lhs.length <= rhs.length ? lhs.length : rhs.length;
        foreach (const u; 0 .. len)
        {
            static if (__traits(isFloating, T))
            {
                immutable a = lhs.ptr[u], b = rhs.ptr[u];
                static if (is(T == cfloat) || is(T == cdouble)
                    || is(T == creal))
                {
                    // Use rt.cmath2._Ccmp instead ?
                    auto r = (a.re > b.re) - (a.re < b.re);
                    if (!r) r = (a.im > b.im) - (a.im < b.im);
                }
                else
                {
                    const r = (a > b) - (a < b);
                }
                if (r) return r;
            }
            else if (lhs.ptr[u] != rhs.ptr[u])
                return lhs.ptr[u] < rhs.ptr[u] ? -1 : 1;
        }
return (lhs.length > rhs.length) - (lhs.length < rhs.length);
    }
}

// This function is called by the compiler when dealing with array
// comparisons in the semantic analysis phase of CmpExp. The ordering
// comparison is lowered to a call to this template.
extern(C) int __cmp(T1, T2)(T1[] s1, T2[] s2)
if (!__traits(isScalar, T1) && !__traits(isScalar, T2))
{
    alias U1 = Unqual!T1;
    alias U2 = Unqual!T2;

    static if (is(U1 == void) && is(U2 == void))
static @trusted ref inout(ubyte) at(inout(void)[] r, size_t i) { return (cast(inout(ubyte)*) r.ptr)[i]; }
    else
static @trusted ref R at(R)(R[] r, size_t i) { return r.ptr[i]; }

    // All unsigned byte-wide types = > dstrcmp
immutable len = s1.length <= s2.length ? s1.length : s2.length;

    foreach (const u; 0 .. len)
    {
static if (__traits(compiles, __cmp(at(s1, u), at(s2, u))))
        {
            auto c = __cmp(at(s1, u), at(s2, u));
            if (c != 0)
                return c;
        }
else static if (__traits(compiles, at(s1, u).opCmp(at(s2, u))))
        {
            auto c = at(s1, u).opCmp(at(s2, u));
            if (c != 0)
                return c;
        }
        else static if (__traits(compiles, at(s1, u) < at(s2, u)))
        {
            if (at(s1, u) != at(s2, u))
                return at(s1, u) < at(s2, u) ? -1 : 1;
        }
        else
        {
            // TODO: fix this legacy bad behavior, see
            // https://issues.dlang.org/show_bug.cgi?id=17244
            static assert(is(U1 == U2), "Internal error.");
auto c = (() @trusted => mem.memcmp(&at(s1, u), &at(s2, u), U1.sizeof))();
            if (c != 0)
                return c;
        }
    }
    return (s1.length > s2.length) - (s1.length < s2.length);
}


template Unqual(T : const U, U)
{
    static if (is(U == shared V, V))
        alias Unqual = V;
    else
        alias Unqual = U;
}


// binary search in sorted string cases, also see `__switch`.
private int __switchSearch(T)(/*in*/ const scope T[][] cases, /*in*/ const scope T[] condition) pure nothrow @safe @nogc
{
    size_t low = 0;
    size_t high = cases.length;

    do
    {
        auto mid = (low + high) / 2;
        int r = void;
        if (condition.length == cases[mid].length)
        {
            r = __cmp(condition, cases[mid]);
            if (r == 0) return cast(int) mid;
        }
        else
        {
// Generates better code than "expr ? 1 : -1" on dmd and gdc, same with ldc
            r = ((condition.length > cases[mid].length) << 1) - 1;
        }

        if (r > 0) low = mid + 1;
        else high = mid;
    }
    while (low < high);

    // Not found
    return -1;
}
```

Reply via email to