Search code examples
oopcompiler-errorsd

No constructor found in the absence of writeln


I am using DMD64 D Compiler v2.063.2 on Ubuntu 13.04 64-bit.

I have written a class as below:

class FixedList(T){
    // list
    private T[] list;

    // number of items
    private size_t numberOfItems;

    // capacity
    private size_t capacity;

    // mutex
    private Mutex listMutex;

    // get capacity
    @property public size_t Capacity(){ return capacity; }
    @property public shared size_t Capacity(){ return capacity; }

    // constructor
    public this( size_t capacity ){
        // initialise
        numberOfItems = 0;
        this.capacity = capacity;

        writeln("Cons Normal");
    }

    // constructor
    public shared this( size_t capacity ){
        // initialise
        numberOfItems = 0;
        this.capacity = capacity;

        // create mutex
        listMutex = cast(shared)(new Mutex());

        writeln("Cons Shared");
    }
}

While class is written in this way, in main function, I wrote that code:

auto list1 = new shared FixedList!int( 128 );
auto list2 = new FixedList!int( 128 );

Output with this, there is no error at all and the output is as below:

Cons Shared
Cons Normal

What I do next is to remove both writeln lines from the code, and when I recompile the code, it starts showing error messages as below:

src/webapp.d(61): Error: constructor lists.FixedList!(int).FixedList.this called with argument types:
    ((int) shared)
matches both:
    lists.d(28): lists.FixedList!(int).FixedList.this(ulong capacity)
and:
    lists.d(37): lists.FixedList!(int).FixedList.this(ulong capacity)
src/app.d(61): Error: no constructor for FixedList
src/app.d(62): Error: constructor lists.FixedList!(int).FixedList.this called with argument types:
    ((int))
matches both:
    lists.d(28): lists.FixedList!(int).FixedList.this(ulong capacity)
and:
    lists.d(37): lists.FixedList!(int).FixedList.this(ulong capacity)
src/app.d(62): Error: no constructor for FixedList
make: *** [all] Error 1

Basically writeln function is preventing the error. Actually writeln is preventing in many places and I am not sure about why this is happening.

I even tried to compile the the code with m32 flag for 32-bit, but it is still same. Am I doing something wrong, or is this a bug?


Solution

  • pure, nothrow, and @safe are inferred for template functions. As FixedList is templated, its constructors are templated. writeln is not (and cannot be) pure as it does I/O. So, while writeln is in the constructors, they are inferred to not be pure, but everything else that the constructors are doing is pure, so without the calls to writeln, they become pure.

    Under some circumstances, the compiler is able to alter the return type of pure functions to implicitly convert it to immutable or shared. This works, because in those cases, the compiler knows that what's being returned is a new, unique object and that casting it to immutable or shared would not violate the type system. Not all pure functions qualify, as the parameter types can affect whether the compiler can guarantee that the return value is unique, but many pure functions are able to take advantage of this and implicitly convert their return value to immutable or shared. This is useful, because it can avoid code duplication (for different return types) or copying - since if the type returned doesn't match what you need with regards to immutable or shared, and you can't guarantee that it's not referred to elsewhere, you have to copy it to get the type that you want. In this case, the compiler is able to make the guarantee that the object is not referred to elsewhere, so it can safely cast it for you.

    Constructors effectively return new values, so they can be affected by this feature. This makes it so that if a constructor is pure, you can often construct immutable and shared values from it without having to duplicate the constructor (like you'd have to do if it weren't pure). As with other pure functions, whether this works or not depends on the constructor's parameter types, but it's frequently possible, and it helps avoid code duplication.

    What's causing you problems is that when FixedList's constructors are both pure, the compiler is able to use either of them to construct a shared object. So, it doesn't know which one to choose, and gives you an ambiguity error.

    I've reported this as a bug on the theory that the compiler should probably prefer the constructer which is explicitly marked as shared, but what the compiler devs will decide, I don't know. The ability to implicitly convert return values from pure functions is a fairly new feature and exactly when we can and can't do those implicit conversions is still being explored, which can result both in unanticipated problems (like this one probably is) as well as compiler bugs (e.g. there's at least one case with immutable, where it currently does the conversion when it shouldn't). I'm sure that these issues will be ironed out fairly quickly though.