Reputation: 2212
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?
Upvotes: 3
Views: 138
Reputation: 38287
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.
Upvotes: 3
Reputation: 21
A pure
constructor can build a shared
object without being marked shared
itself.
Apparently, pureness is inferred for constructors.
writeln
is not pure
. So, with it in place, the constructors are not pure
.
When writeln
is removed, the constructors become pure
. Both constructors now match the shared
call.
Upvotes: 2