Thread overview
Static member function returning immutable slice; compiler error: without this cannot be immutable
Jul 05, 2018
Ivo Maffei
Jul 05, 2018
Adam D. Ruppe
Jul 05, 2018
ag0aep6g
Jul 06, 2018
Ali Çehreli
Jul 06, 2018
Ivo Maffei
July 05, 2018
I'm writing my first D program and I want to have a class which contains a private static list of objects.
Moreover such list should be visible from outside the class, so I wrote a get method which returns such list as immutable (so that the list cannot be modified outside the class).
Finally such method should be static since the list is static and therefore I should not need an object to access such list.

Here is the code:

class Foo {
	private static Foo[] fooSlice = new Foo[0]; //private static slice

	static immutable Foo[] getFooList() { //static method returning an immutable slice
		return fooSlice;
	}	
}

However when compiling with dub I get the following error:

Error: function `main.Foo.getFooList` without this cannot be immutable

I noted that the error goes away when I remove the static or immutable qualifier.

Thanks a lot for any help.
July 05, 2018
On Thursday, 5 July 2018 at 19:43:43 UTC, Ivo Maffei wrote:
> 	private static Foo[] fooSlice = new Foo[0]; //private static

That initializer is useless, don't do that, just use the slice.

> 	static immutable Foo[] getFooList() { //static method returning an immutable slice

Actually, that's a static immutable *method* returning a mutable slice. It is like you wrote:

immutable {
   // bunch of methods here
}

so it is applying to this. To make it apply to the return, use parens around it:


static immutable(Foo)[] getFooList() {}

or

static immutable(Foo[]) getFooList() {}


the former is a mutable array of immutable objects and the latter is all immutable
July 05, 2018
On 07/05/2018 09:43 PM, Ivo Maffei wrote:
> class Foo {
>      private static Foo[] fooSlice = new Foo[0]; //private static slice
> 
>      static immutable Foo[] getFooList() { //static method returning an immutable slice
>          return fooSlice;
>      }
> }
> 
> However when compiling with dub I get the following error:
> 
> Error: function `main.Foo.getFooList` without this cannot be immutable

If you want to return an `immutable Foo[]`, you have to write the signature like this:

    static immutable(Foo[]) getFooList()

Otherwise, the `immutable` qualifier applies to the method itself instead of the `Foo[]` return type. But a static method can't be immutable, so you get the error.

But it won't work even if you fix that, because mutable doesn't convert to immutable like that.

`immutable` means that the data can't ever change. Not even the owning Foo is allowed to change it. If you want to disallow changes from outside, but still allow the owning Foo to make changes, use `const`:

    static const(Foo[]) getFooList()
July 05, 2018
On 07/05/2018 01:00 PM, ag0aep6g wrote:

> `immutable` means that the data can't ever change. Not even the owning
> Foo is allowed to change it. If you want to disallow changes from
> outside, but still allow the owning Foo to make changes, use `const`:
>
>      static const(Foo[]) getFooList()

To add, in that context 'immutable' would be a guarantee to the outside world: "I will never change this data." On the other hand, 'const' means "Dear compiler, please make sure the caller does not mutate this data."

However, I think the return type would be more useful as const(Foo)[] to let the caller to be able to add elements to their local copy of the slice:

struct Foo {
}

Foo[] foos;

// const(Foo[]) would not allow the concatenation in main.
const(Foo)[] getFooList() {
    return foos;
}

void main() {
    auto f = getFooList();
    f ~= Foo();
}

But then one might argue that if the caller would concatenate anyway, which would cause memory allocation and copying, wouldn't the caller better use .dup to get a mutable copy of the elements.

    auto f = getFooList().dup;
    f ~= Foo();

I don't know... Too much analysis... :)

Ali

July 06, 2018
Ok thanks to everyone for their help.

So I tried what you suggested and so the problem was bracketing.

For future reference, the above code can be fixed into this:

class Foo {
	private static Foo[] fooSlice; //private static slice

	static const(Foo[]) getFooList() { //static method returning a constant slice
		return fooSlice;
	}	
}