Thread overview
`static` on module-level functions
Jul 07, 2023
IchorDev
Jul 07, 2023
IchorDev
Jul 07, 2023
IchorDev
Jul 07, 2023
Paul Backus
Jul 09, 2023
IchorDev
July 07, 2023

Can anyone point me to a part of the D spec that says what static means when applied to functions that are declared at module scope? (Other than module constructors, obviously)
I used to assume the property would do something, so I actually used it in a lot of my code when I was first learning D. Now someone I work with who’s newer to the language is now also going through this phase. The assumption of both me and them was that a static module-level function would more-or-less work like a function with pragma(inline, true), which makes more sense if you overlook how static usually applies to functions and you instead look at how static applies to almost everything else: variables (their initialisation is compile-time), if, foreach, and assert. However, I haven’t seen anything to suggest that static even does anything at all in this case; it also doesn’t give you a compiler error or even a warning, is it like this to make automatic code generation easier, or does it actually do something? Maybe D’s spec could be tweaked to make this a bit clearer? On quite a few occasions I’ve searched for info about this and found nothing relevant.

P.S. If it doesn’t actually do anything, I wonder if something like the behaviour of “static import” would be desirable?

July 07, 2023
Yes, static on a free-function does not do anything.

```
; [#uses = 0]
; Function Attrs: uwtable
define void @void onlineapp.func()() #0 {
  ret void
}
```

```
; [#uses = 0]
; Function Attrs: uwtable
define void @void onlineapp.func()() #0 {
  ret void
}
```

Looks identical to me (LDC, LLVM IR).

As for inlining, backends like LLVM will freely inline if they feel it is a good idea. You don't need to use the pragma, it only overrides the logic.
July 07, 2023

On Friday, 7 July 2023 at 03:18:53 UTC, Richard (Rikki) Andrew Cattermole wrote:

>

Yes, static on a free-function does not do anything.

Good to know. I think the D spec should definitely be amended to explicitly mention that static can be applied to them, but doesn't do anything.

July 07, 2023
Static does do something on functions when they are not free-functions.

https://dlang.org/spec/attribute.html#static

However yes, it does not describe what a free-function is there.

https://issues.dlang.org/show_bug.cgi?id=24038
July 07, 2023
On Friday, 7 July 2023 at 10:01:41 UTC, Richard (Rikki) Andrew Cattermole wrote:
> Static does do something on functions when they are not free-functions.
>
> https://dlang.org/spec/attribute.html#static
>

Well yes, I even mentioned that in the OP. It's just that I'd expect using `static` "incorrectly" to cause an error, like `const` does. Instead, marking something as `static` *actually* does nothing, and nothing really tells you, so it causes a bit of a placebo effect.

> https://issues.dlang.org/show_bug.cgi?id=24038

Thank you! :)
July 07, 2023

On 7/7/23 6:38 AM, IchorDev wrote:

>

Well yes, I even mentioned that in the OP. It's just that I'd expect using static "incorrectly" to cause an error, like const does. Instead, marking something as static actually does nothing, and nothing really tells you, so it causes a bit of a placebo effect.

D allows no-op attributes in many cases because you can possibly apply attributes to a group via attribute: or attribute { ... }, and you may not want to fine-tune which things can get the attribute to avoid errors.

Here's a fun one:

enum foo() {
   return "what?";
}

What does this mean? enum is a storage class, and any storage class applied to a function is going to cause the function to be inferred return type. So effectively, the enum does nothing but take the place of auto. (foo is a function that returns string)

However, I can't think of a valid reason to allow static on a module-level scope. Applying static to a declaration at module-level should be a no-op. So maybe that's one "use" of static that can be eliminated.

-Steve

July 07, 2023

On Friday, 7 July 2023 at 13:31:59 UTC, Steven Schveighoffer wrote:

>

However, I can't think of a valid reason to allow static on a module-level scope. Applying static to a declaration at module-level should be a no-op. So maybe that's one "use" of static that can be eliminated.

Well, it can be used to work around this bug:

https://issues.dlang.org/show_bug.cgi?id=17435

So we might want to fix that issue before we make module-level static an error.

July 09, 2023

On Friday, 7 July 2023 at 13:31:59 UTC, Steven Schveighoffer wrote:

>

D allows no-op attributes in many cases because you can possibly apply attributes to a group via attribute: or attribute { ... }, and you may not want to fine-tune which things can get the attribute to avoid errors.

Here's a fun one:

enum foo() {
   return "what?";
}

What does this mean? enum is a storage class, and any storage class applied to a function is going to cause the function to be inferred return type. So effectively, the enum does nothing but take the place of auto. (foo is a function that returns string)

However, I can't think of a valid reason to allow static on a module-level scope. Applying static to a declaration at module-level should be a no-op. So maybe that's one "use" of static that can be eliminated.

-Steve

Ah yes, that's another beginner's trap—enum functions.

We should really make enum for functions mean "CTFE-only", or something similar. Granted, you can kinda do that already with lambda enums, as long as you make sure not to call them in runtime code. However, enum templates can't be implicitly instantiated from eponymous lambda parameters like with function templates, and getting errors about "__lambda7" instead of "thisFnName" isn't great either. As it is, it at least makes it possible for BetterC code to use compile-time GC for mixin generation, I just wish it was a little bit nicer.