Hey, all. @Slava_Pestov brought up a problem when trying to use the (not-yet-approved) inlinable
attribute on a struct constructor: it ends up trying to reference the tiny functions we generate to set the initial value of each property. This is a problem because those initial-value functions are not inlinable (right now), but nor should they have public symbols (ideally).
For a resilient library there is a clear answer here: you can't make a non-delegating struct constructor inlinable unless the struct is fixed-contents/fixed-layout/frozen. That's a requirement anyway because you need to know what properties the struct has, and it's easy enough to have that annotation imply "initial-value functions must be inlinable", with the semantic restrictions that entails.
However, it's less clear what to do for non-resilient libraries, i.e. the normal libraries everyone builds. Originally Slava and I planned to have the same restriction, but since everything in a non-resilient library exposes its layout the attribute suddenly only mattered for this one little thing (whether initial-value functions were inlinable or not, which in turn controls whether initializers can be inlinable). That seemed like overkill to me and Doug (after some thought), especially if inlinable
gets formally added to the language this year (SE-0193) but not this other annotation on structs. (I actually have a good chunk of a proposal written for that, but don't want to bring it up until SE-0193 and SE-0192 are done.)
@John_McCall, Slava, and I talked this over and came up with several options, none of which are perfect:
-
(original plan) Non-delegating struct initializers cannot be marked
inlinable
unless the struct is marked "fixed-contents" in some way (annotation to be designed). That annotation would make property initial value expressions inlinable, and enforce the usual restrictions about that. Has the advantage that it's the same restriction with or without resilience enabled, but the disadvantage that this is the only time the to-be-designed annotation is interesting in normal libraries (at least for now). -
Non-delegating struct initializers cannot be marked
inlinable
unless all of the struct's properties with explicit initial value expressions are marked as "inlinable" in some way (annotation to be designed). (I'd be a little sad if we spell this@inlinable
as well because I really wanted that to mean "you can rely on this property being stored forever" in resilient libraries.) -
Non-delegating struct initializers cannot be marked
inlinable
if the struct has any properties with explicit initial value expressions. This stinks if you have a bunch of initializers and you end up repeating code, but it is simple. -
If there's an inlinable non-delegating struct initializer anywhere in the module, the property initial values are implicitly made inlinable. This could lead to the initial value expressions being type-checked and SILGen'd multiple times during a build, however, if such an initializer is defined in a separate file from the struct.
-
Same as (4), but inlinable non-delegating struct initializers are disallowed outside of the file where the struct is defined. Solves the problem with (4) in exchange for a somewhat arbitrary restriction.
-
(what's currently implemented) Property initial value expressions are given public symbols, so they can be referenced from inlinable initializers. This "works" but it means the initializer can't be completely inlined away; there's always going to be a call to some opaque code when used across library boundaries.
Note that I referred to "explicit initial value expressions" a few times; I think even if we pick one of the more restrictive options we'd still want to make an exception for the implicit = nil
for Optional properties and the hidden initialization for lazy
properties, as if they were written out in each initializer.
Thoughts, everyone? IIRC, where the three of us left off Slava was still leaning towards (1), I was leaning towards (5), and John was leaning towards (4).
P.S. I've been talking about structs, but classes have the same problem, really.