Thank you, that indeed answers my question! But the reason I’m asking is, it nevertheless feels odd to invert the polarity of global and static
variables (constants) here by introducing a new place to use the lazy
keyword.
I think there’s another option (or two) avoiding the lazy
keyword in this context. Either:
- just don’t introduce any keyword here and deduce from the expression whether it’s a compile-time constant initialisation expression (such as
= (1, "one")
), and if not (such as= Int.random(in: 0 ..< 10)
) then make it lazy; or - make the non-lazy compile-time constant initialisation ride on the same syntax which is planned for the general feature of constant or literal expressions which Doug and others discussed above.
In both cases, there’d be no lazy
in these contexts. Option 2, which could turn out to mean no syntax at all, merging into option 1, would IMO keep the language best together.
This might result in "spooky action" that produces an ill-formed binary. Consider what might happen if you accidentally emitted non-constant, lazily-constructed data into a section that you read with C (which is a thing Swift Testing must do.) You'd end up with uninitialized data among other potential problems. I'd rather we make laziness opt-in (or perhaps opt-out with _const
in lieu of a supported solution).
If we don't have an immediate use for it, I'd like to push against making lazy
available for use with @section
. The existence of lazy
local properties as a builtin language feature is a hack that I still hope can be supplanted by a library feature someday. (Maybe property macros with init accessors are up to the task now.) And the implementation for globals has almost nothing in common with the implementation for local properties; we already have trouble explaining that global initialization is thread-safe and referentially transparent for let
s, whereas it is most definitely not for lazy
properties, and spelling them the same will only make this harder to communicate. I also don't think global initialization should be thought of as "lazy" but as "happening before the first use", since the optimizer is allowed to move the point of initialization, to get it out of loops or things like that (and, of course, turn constant initializers into fully static values in the binary).
Thank you Joe, you worded it better. One lazy is not like the other.
I very much like the proposal as-is. I do not think forcing @section()
to have elf, macho, etc
params is a good idea. Often you need to vary the section name for many other reasons than just the object file format. For example on various embedded devices you need to use different section names for the same object format depending on the toolchain used or targeted device (sometimes even between device revisions.)
I would much much rather have #if
conditions which allow me to express the true conditions than pre-baked elf/macho/coff conditions.
This is already an expert feature it does not need sugar, it needs expressivity.
Hello all,
The Language Steering Group discussed the feedback on this proposal, and requested a few changes to be proposal based on that feedback. The author has made these changes:
- The
#if
conditionobjectFileFormat
has been changed toobjectFormat
. - The use of
lazy
has been removed from the proposal. - The proposal now uses the alternative syntax discussed here that specifies the object format names in the section attribute, i.e.,
@section(ELF: “...”, MachO: “...”, COFF: “...”)
, with the addition of adefault:
label whose name will be used for any object format not otherwise covered by that attribute.
We'll be extending the review until Tuesday, October 14th to gather more feedback on the proposal with these changes.
Thank you
Doug Gregor
Review Manager
For Swift Testing's purposes, we'll be able to adopt even with these adjustments in place. That said… a default:
label doesn't really make much sense in this context, as there is no universal, standard, or common fallback to use here. Can the LSG provide some more justification for adding it? What is the intended use case?
Intended use cases can include:
- You're computing the section name somewhere else (say, with a set of
#if objectFormat(...)
checks) and then you put the computed value in@section(default: theSection
), as noted above. - There is an object format that's available in the underlying LLVM but doesn't yet have a suitable label in
@section
.
Doug
Then maybe provide two ways to specify the section:
// either with object format names but without `default:`
@section(ELF: “...”, MachO: “...”, COFF: “...”)
// or with just the name (also without having to use `default:`)
@section(precomputedName)
That's not possible under the proposal since you must use a string literal. So it's impossible to use this part of the API correctly.
Perhaps _default
would be appropriate then? You'd be dealing with an unsupported corner of the compiler stack. Once the compiler is updated to "learn" of the new object format, we could easily add a new label for it.
What’s the rationale behind naming the object formats with an uppercase first letter (MachO
, ELF
) rather than the lowercase first letter used with variables, enum cases, and function parameters (machO
, elf
)?
They are proper names, and the spelling for them is MachO
, ELF
, and COFF
. So it does make sense to use the proper spelling here.
One can use this in the form allowed by the original proposal, i.e.,
#if objectFormat(MachO)
@section(default: "...")
#else
@section(default: "...")
#endif
var globalThing = 0
Additionally, we expect a feature that allows the use of a named constant here in lieu of a string literal to become available in the not-too-distant future, and want to support both use cases.
Doug

What’s the rationale behind naming the object formats with an uppercase first letter (
MachO
,ELF
) rather than the lowercase first letter used with variables, enum cases, and function parameters (machO
,elf
)?
I see these as similar to platform names, where we adopt the capitalization preferred by the platform owner (Windows
, FreeBSD
, macOS
). These technologies have names, those names use capitalization in sometimes idiosyncratic ways, and there's no compelling reason to ignore their decisions.
Would it be feasible to drop the default:
when we're just providing a single value?
#if objectFormat(MachO)
@section("__TEXT,__butt")
#else
@section("__TEXT,__jawn")
#endif
var globalThing = 0
@rauhul would that alleviate your concerns?

They are proper names, and the spelling for them is
MachO
,ELF
, andCOFF
. So it does make sense to use the proper spelling here.
FTM we didn't follow this approach with @objc
name, and we plan not to follow it with @c
name either.
yes! though I still disagree with the premise of providing elf:macho:coff:
arguments.
(Composable features are both more teachable and extensible)
Are these two fragments equivalent?
#if objectFormat(MachO) || objectFormat(ELF)
@section(MachO: "__DATA_CONST,mysection", ELF: "mysection")
#endif
#if objectFormat(MachO)
@section(default: "__DATA_CONST,mysection")
#elif objectFormat(ELF)
@section(default: "mysection")
#endif
Can't @used
be a parameter of @section
?
@section(MachO: "__DATA,mysection", used)
or
@section(MachO: "__DATA,mysection", used: true)
or
@section(MachO: "__DATA,mysection", dontDeadStrip: true)

Are these two fragments equivalent?
#if objectFormat(MachO) || objectFormat(ELF) @section(MachO: "__DATA_CONST,mysection", ELF: "mysection") #endif
#if objectFormat(MachO) @section(default: "__DATA_CONST,mysection") #elif objectFormat(ELF) @section(default: "mysection") #endif
Yes.

Can't
@used
be a parameter of@section
?@section(MachO: "__DATA,mysection", used) or @section(MachO: "__DATA,mysection", used: true) or @section(MachO: "__DATA,mysection", dontDeadStrip: true)
It's possible. The proposal makes the point that these are separate notions.
Doug