[swift-dev] What can you change in a fixed-contents struct?

Thomas Roughton t.roughton at me.com
Tue Sep 5 16:48:01 CDT 2017


Hi Jordan and David,

Reading this from a user’s perspective, I’d be very much in favour of something like the @abi annotation. The core issue I see with the ‘allow renaming’ approach is that users coming to Swift from other languages will do so with the expectation that ordering is significant (i.e. it’s somewhat intuitive that stored properties will be stored in the order they’re declared in languages such as C/C++). Given that the layout algorithm’s requirements in Swift mean that the order may be completely different from the definition order, I feel that having order be significant in this one area (reinforcing the expectation) is misleading and a potential source of confusion; I think it’s better to have the declaration order be consistently meaningless. 

With that said, being able to rename properties is still very necessary; hence I feel that something like the @abi is a good solution, given that @fixedContents structs are likely not a novice level feature. I suppose the issue with that solution is it does remove the ability for the compiler to tightly reorder and pack properties if it follows the declaration order exactly; the question is whether that’s even something that should be a goal for @fixedContents structs, or whether something like a compiler warning for sub-optimal alignment could be a better approach.

Having an explicit @abi annotation could also go some way to addressing the issue of manual layout with structs. I’m primarily thinking of graphics contexts, wherein you need to declare e.g. a struct with vertex layout, and then that needs to be specified when passed to the GPU. The current solution is to declare in C code and import into Swift, which is cumbersome; having @fixedContents structs be the method of choice when a deterministic layout is needed seems to make sense. If combined with a hypothetical MemoryLayout<Type>.offsetOf(property) Swift would, I think, meet that need.

I guess my closing question is: under what circumstances would a user declare a @fixedContents struct and not care about its layout in memory; in other words, where might a novice need to use this feature?

Thomas

> On 6/09/2017, at 8:01 AM, David Zarzycki via swift-dev <swift-dev at swift.org> wrote:
> 
> Hi Jordan,
> 
> Thanks for thinking about this. For whatever it may be worth, I’m concerned about 1) the ability to reorder declarations and 2) the “either/or” nature of this proposal.
> 
> First, reordering: The ability to reorder declarations is deeply ingrained into the subconsciousness of Swift programmers and for good reasons. I think adding localized declaration order sensitivity is likely to be very brittle and regrettable in the long run. I also think this problem is made worse by having a type declaration context attribute because it can easily get lost in the noise of nontrivial declarations. The net result is that people will frequently forget about local order sensitivity. Yes, the compiler can engage in heroics and compare the previous module ABI and the new module ABI for conflicts, but that seems risky, complex, slow, and differently error prone.
> 
> Second, the “either/or” nature of this proposal: What do you think about a lightweight “belt and suspenders” solution whereby @fixedContents requires that stored properties be lightly annotated with their layout order? For example:
> 
> @fixedContents(3) struct Foo {
>   @abi(0) var x: Int
>   func a() {
>     // a thousand lines of ABI layout distraction
>   }
>   @abi(1) var y: Double
>   func b() {
>     // another thousand lines of ABI layout distraction
>   }
>   @abi(2) var z: String
> }
> 
> That would enable both renaming and reordering, would it not? This approach would also aid the compiler in quickly detecting hastily added/deleted declarations too because the count of @abi([0-9]+) declarations wouldn’t match the number passed to @fixedContents.
> 
> Dave
> 
> 
> 
>> On Sep 5, 2017, at 14:59, Jordan Rose via swift-dev <swift-dev at swift.org <mailto:swift-dev at swift.org>> wrote:
>> 
>> Hey, all. In preparation for the several proposals we have to come this year, I cleaned up docs/LibraryEvolution.rst <https://github.com/apple/swift/pull/11742> a little bit based on what's changed in Swift 4. This is mostly just mentioning things about generic subscripts, but there is one issue that I remember John bringing up some time in this past year: once you've made a struct fixed-contents, what can you change about its stored properties?
>> 
>>> To opt out of this flexibility, a struct may be marked '@fixedContents'. This promises that no stored properties will be added to or removed from the struct, even non-public ones.
>> 
>> Interestingly, this means that you can have non-public members of a fixed-contents struct. This is actually pretty sensible: it's the equivalent of a C++ class with non-public fields but a defaulted, inlinable copy constructor. Any inlinable members can access these properties directly as well; it's just outsiders that can't see them. But if inlinable code can reference these things, and if we really want them to be fast, that means they have to have a known offset at compile-time.
>> 
>> Now, we don't plan to stick to C's layout for structs, even fixed-contents structs. We'd really like users to not worry about manually packing things into trailing alignment space. But we still need a way to lay out fields consistently; if you have two stored properties with the same type, one of them has to go first. There are two ways to do this: sort by name, and sort by declaration order. That means we can either allow reordering or allow renaming, but not both. Which do people think is more important?
>> 
>> At the moment I'm inclined to go with "allow renaming" just because that's what C does. It's not great because you're allowed to reorder nearly everything else in the language, but there's a "least surprise" principle here that I think is still useful. It'd be surprising for the name of a non-public property to affect your library's ABI.
>> 
>> (In theory we could also make different decisions for public and non-public fields, because it's much less likely to want to change the name of a public property. But you could do it without breaking source compatibility by introducing a computed property at the same time as you do the renaming. It's up to us whether that should break binary compatibility or not.)
>> 
>> 
>> Note that because the layout algorithm isn't public, Swift isn't going to allow the thing from C where you have an existing field and you split it into two smaller fields. You can use computed properties for that instead. (Strictly speaking this probably isn't even good C because the fields in your struct can affect by-value calling conventions.)
>> 
>> 
>> By the way, I'm putting this on swift-dev because we're nowhere near a proposal and I want to keep the discussion narrow for now, but of course this point will be called out when the fixed-contents attribute—whatever its final form—goes to swift-evolution for a proper review.
>> 
>> Thanks!
>> Jordan
>> _______________________________________________
>> swift-dev mailing list
>> swift-dev at swift.org <mailto:swift-dev at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-dev
> 
> _______________________________________________
> swift-dev mailing list
> swift-dev at swift.org
> https://lists.swift.org/mailman/listinfo/swift-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20170906/79113384/attachment.html>


More information about the swift-dev mailing list