Thread overview
Definitive list of storage classes
Apr 14, 2012
Jonathan M Davis
Apr 14, 2012
Daniel Murphy
Apr 14, 2012
Jonathan M Davis
Apr 15, 2012
Jakob Ovrum
Apr 15, 2012
Peter Alexander
Jan 29, 2021
kdevel
Jan 30, 2021
MoonlightSentinel
Jan 30, 2021
ag0aep6g
April 14, 2012
I'd like to know which modifiers are considered to be storage classes. The term seems to be used on a lot more than actually qualifies (including using the term for the type qualfiers: const, immutable, and shared), and even the documentation uses it on stuff that I wouldn't have thought would be considered storage classes, because they have no effect on how variables are stored or linked (e.g. synchronized).

Someone asked about it on stackoverflow, and my explanation is not as good as it should be simply because I can't find a definitive list anywhere:

http://stackoverflow.com/questions/10150510/what-are-the-storage-classes-in-d

- Jonathan M Davis
April 14, 2012
"Jonathan M Davis" <jmdavisProg@gmx.com> wrote in message news:mailman.1707.1334377994.4860.digitalmars-d@puremagic.com...
> I'd like to know which modifiers are considered to be storage classes. The
> term
> seems to be used on a lot more than actually qualifies (including using
> the
> term for the type qualfiers: const, immutable, and shared), and even the
> documentation uses it on stuff that I wouldn't have thought would be
> considered
> storage classes, because they have no effect on how variables are stored
> or
> linked (e.g. synchronized).
>
> Someone asked about it on stackoverflow, and my explanation is not as good
> as
> it should be simply because I can't find a definitive list anywhere:
>
> http://stackoverflow.com/questions/10150510/what-are-the-storage-classes-in-d
>
> - Jonathan M Davis

There's always the list in 'declaration.h'.

If I had to guess I'd say 'storage class' meant something much more specific in C than it does in D, where it seems to mean properties of a declaration that do not affect the type.


April 14, 2012
On Sunday, April 15, 2012 01:49:09 Daniel Murphy wrote:
> "Jonathan M Davis" <jmdavisProg@gmx.com> wrote in message news:mailman.1707.1334377994.4860.digitalmars-d@puremagic.com...
> 
> > I'd like to know which modifiers are considered to be storage classes. The
> > term
> > seems to be used on a lot more than actually qualifies (including using
> > the
> > term for the type qualfiers: const, immutable, and shared), and even the
> > documentation uses it on stuff that I wouldn't have thought would be
> > considered
> > storage classes, because they have no effect on how variables are stored
> > or
> > linked (e.g. synchronized).
> > 
> > Someone asked about it on stackoverflow, and my explanation is not as good
> > as
> > it should be simply because I can't find a definitive list anywhere:
> > 
> > http://stackoverflow.com/questions/10150510/what-are-the-storage-classes-i n-d
> > 
> > - Jonathan M Davis
> 
> There's always the list in 'declaration.h'.

That's clearly not the list, since it includes const, immutable, and shared, which are type qualifiers rather than storage classes. It also has stuff like init in it, which isn't even vaguely a storage class. All of the storage classes may be in that list, but I don't know how you'd figure out which ones they are from that list.

> If I had to guess I'd say 'storage class' meant something much more specific in C than it does in D, where it seems to mean properties of a declaration that do not affect the type.

Except that both Walter and Andrei seem to talk about type qualifiers/constructors and storage classes as if they meant essentially the same thing as in C/C++. For instance, talking about const as being a type qualifier rather than a storage class doesn't mean anything to a non-D audience unless it means essentially the same thing as in C. Also, the documentation lists synchronized as being a storage class whereas it affects no variables whatsoever and all of the descriptions of storage classes in TDPL act like storage classes are for variables only. But synchronized doesn't affect scoping, storage, or linking at all as a storage class in C would, so that would at least seem to indicate that something other than the C definition is being used.

Regardless, if a storage class does not have a specific definition separate from D which can be applied to D, then D needs to give its own definition for what on earth the term means, and I don't find _anywhere_ that does that. Everywhere that mentions it seems to assume that you have some idea of what it means already. TDPL _does_ sort of try and define it, but not really. It pretty much just lists certain modifiers as being storage classes without giving a full list or explaining exactly what constitutes a storage class. The closest thing that it gives to a definition

"Each function parameter (base and exponent in the example above) has, in addition to its type, an optional storage class that decides the way that arguments are passed to the function when invoked."

would seem indicate that static (which it later says is a storage class) isn't a storage class at all, since storage classes would only apply to function parameters (which would also disqualify synchronized as a storage class, which would be at odds with the online docs).

So, I'd like an official definition of storage class with a list of what qualifies as a one in D. But it wouldn't surprise me at all if Walter's the only one who can do that.

- Jonathan M Davis
April 15, 2012
On Saturday, 14 April 2012 at 17:50:39 UTC, Jonathan M Davis wrote:
> That's clearly not the list, since it includes const, immutable, and shared,
> which are type qualifiers rather than storage classes. It also has stuff like
> init in it, which isn't even vaguely a storage class. All of the storage
> classes may be in that list, but I don't know how you'd figure out which ones
> they are from that list.

Obviously D has inherited the term "storage class" from C and C++, but then expanded use of the term to a point where it's not always meaningful any more. I agree that the term needs some work.

`const`, `immutable` and `shared` actually can affect the storage of variables in specific situations (e.g. an immutable module variable declaration), but we know they are also type qualifiers, beyond any doubt. I don't think it would be a stretch to say they are both storage classes and type qualifiers, and this is in fact how the specification presents it.

I personally think that it's meaningless to classify them as both and would prefer their storage class classification be dropped from the specification text.

>
>> If I had to guess I'd say 'storage class' meant something much more specific
>> in C than it does in D, where it seems to mean properties of a declaration
>> that do not affect the type.
>
> Except that both Walter and Andrei seem to talk about type
> qualifiers/constructors and storage classes as if they meant essentially the
> same thing as in C/C++.

If Walter and/or Andrei have made an executive decision about what is and what isn't a storage class, I suggest they submit a pull request to dlang.org clarifying its new meaning.

I have a feeling not a lot of thought has gone into this issue though, and Walter denying that immutable is a storage class (in his Lang.NEXT talk) probably means one of two things, 1) immutable is not a storage class in the context he presented, or 2) he was wrong and it is both a storage class and a type qualifier/constructor (per the specification).

> TDPL _does_ sort of try and define it, but not really. It pretty much
> just lists certain modifiers as being storage classes without giving a full
> list or explaining exactly what constitutes a storage class. The closest thing
> that it gives to a definition
>
> "Each function parameter (base and exponent in the example above) has, in
> addition to its type, an optional storage class that decides the way that
> arguments are passed to the function when invoked."
>
> would seem indicate that static (which it later says is a storage class) isn't
> a storage class at all, since storage classes would only apply to function
> parameters (which would also disqualify synchronized as a storage class, which
> would be at odds with the online docs).

He is referring to the *parameter storage classes*, and he's actually wrong on one point: a parameter can have multiple parameter storage classes as long as they are compatible.

List from the specification on functions:
"Parameter storage classes are in, out, ref, lazy, const, immutable, shared, inout or scope."

One point of interest is that you can define a function like:

    void foo(const scope int a);

With the `const` before the `scope` like that. This has to be taken into consideration if the definition of a storage class is to be revisited.

> So, I'd like an official definition of storage class with a list of what qualifies
> as a one in D. But it wouldn't surprise me at all if Walter's the only one who
> can do that.

Anyone making such a list would probably be making rather arbitrary on-the-spot decisions if we don't provide a solid definition of what a storage class is in D. As long as we have a good definition, anyone could fix the lists.
April 15, 2012
On Saturday, 14 April 2012 at 17:50:39 UTC, Jonathan M Davis wrote:
> On Sunday, April 15, 2012 01:49:09 Daniel Murphy wrote:
>> There's always the list in 'declaration.h'.
>
> That's clearly not the list, since it includes const, immutable, and shared,
> which are type qualifiers rather than storage classes. It also has stuff like
> init in it, which isn't even vaguely a storage class. All of the storage
> classes may be in that list, but I don't know how you'd figure out which ones
> they are from that list.

As I understand it, const, immutable, and shared are both type qualifiers and storage classes. In C++, const is also both a storage class and type qualifier, which causes confusion.

// At global scope
immutable int x = 1;
int y = 2;

Here x and y are stored very differently. y is thread local whereas x is a program-wide read-only global. It's a similar situation with const and shared.
January 29, 2021
On Sunday, 15 April 2012 at 09:59:54 UTC, Peter Alexander wrote:

[...]

> As I understand it, const, immutable, and shared are both type qualifiers and storage classes. In C++, const is also both a storage class and type qualifier, which causes confusion.
>
> // At global scope
> immutable int x = 1;
> int y = 2;
>
> Here x and y are stored very differently. y is thread local whereas x is a program-wide read-only global. It's a similar situation with const and shared.

A few days ago I ran into the following problem:

```mod.d
module mod;

immutable int x = 1;
    const int y = 1;
          int z = 1;
```

```main.d
import std.stdio;
import mod;

void main ()
{
   writeln (x);
   writeln (y);
   writeln (z);
}
```

   $ dmd -c mod.d main.d
   $ dmd main.o mod.o
   $ ./main
   1
   1
   1

This is expected. Now I changed mod.d, recompiled only it and relinked:

```mod.d (2nd version)
module mod;

immutable int x = 2;
    const int y = 2;
          int z = 2;
```

   $ dmd -c mod.d
   $ dmd main.o mod.o
   $ ./main
   1
   1
   2

Here I'd expect three 2s. But this behavior I only achieve if I create
separate initializations:

```mod.d (3rd version)
module mod;

immutable int x;
    const int y;
          int z = 2;

shared static this () {
   x = 2;
   y = 2;
}
```

Unfortunately I could not find a reasonable recap on this issue. In [1]
const and immutable are intruduced as "attributes" but there is no
explanation of their meanings. In [2] const and immutable become
"type qualifiers" and likewise "storage classes".

[1] https://dlang.org/spec/attribute.html#const
[2] https://dlang.org/spec/const3.html
January 30, 2021
On Friday, 29 January 2021 at 21:32:19 UTC, kdevel wrote:
> Unfortunately I could not find a reasonable recap on this issue. In [1]

The problem is that dmd treats const/immutable variables kinda like enums when they have an initializer. The final AST never accesses x, y but uses their initializers instead:

immutable immutable(int) x = 2;
const const(int) y = 2;
int z = 2;
void main()
{
	writeln(2);
	writeln(2);
	writeln(z);
	return 0;
}
January 30, 2021
On 30.01.21 02:46, MoonlightSentinel wrote:
> The problem is that dmd treats const/immutable variables kinda like enums when they have an initializer. The final AST never accesses x, y but uses their initializers instead:

Throw `__ctfe` into the mix and it gets even more fun:

void main()
{
    const bool x = __ctfe;
    version (none) static const bool y = __ctfe; /* Error: variable `__ctfe` cannot be read at compile time */
    else static const bool y = x; /* no error */
    static assert(x == y); /* passes */
    assert(x == y); /* fails */
}