I understand Swift's inlining well. I know the nuances between the four function-inlining attributes. I use @inline(__always)
a lot, especially when I'm just making sugary APIs like this:
public extension String {
@inline(__always)
var length: Int { count }
}
I do this because there's not really a cost involved in inlining it, but there would be the cost of an extra stack frame if it weren't inlined. For less-obvious sugar, I'll lean toward @inlinable
andor @usableFromInline
as needed.
However, one distinction vexes me. The two possible arguments to @inline
are never
and __always
. Despite the lack of actual documentation, this choice of spelling here acts as a sort of self-documentation, implying that if you are going to use one of these, you should lean toward never
, and __always
is discouraged.
But why is this the direction the Swift language designers encourage? As far as I know, if no attribute is applied at all, then this is the behavior:
- If a function (et al) is used within the module in which it's declared, the compiler might choose to inline it or not, depending on which would produce better code (by some measure)
- If that function (et al) is used outside the module, its implementation is not exposed in a way that allows it to be inlined, so it is never inlined.
So, it seems most of the time, not-inlining is the default. That's fine and dandy, I have no problem with that on the surface; don't bloat the executable any more than you need to.
But then, I've never had a reason to think @inline(never)
is useful. From what I understand, the only reason I would use @inline(never)
is if I've noticed that the Swift compiler is choosing to inline a non-annotated function too much, and it's bloating my executable. This seems like a super-niche occurrence:
- My software is running fine
- The Swift compiler's algorithm for deciding whether to inline something is not making the right choice for my code
- I care about the size of the binary so much that I'm inspecting it closely enough to discover that a function is being inlined automatically too much
- The problem is only in code that I've written into my own module; not code I'm using from some other module
Or, as Rob said in the comments, if you're going through some disassembly and automatic inlining makes it hard to read.
I can't imagine that these are the use cases which the Swift language designers had in mind when designing this attribute. Especially since Swift is not meant for embedded systems, binary size (and the (dis)assembly in general) isn't really that much of a concern. I've never seen an unreasonably-large Swift binary anyway (>50MB).
So why is never
encouraged more than __always
? I often run into reasons why I should force a function to be inlined, but I've not yet seen a reason to force a function to be stacked, at least in my own work.
@inlinable
, not suggesting eithernever
or__always
. – Truckle@inline(never)
. I was going through some disassembly recently, and all that automatic inlining made it much harder to read. Adding@inline(never)
to some called functions replaced a lot of noise with a singlecall
. – Trucklenever
is plain and__always
is double-underscore-discouraged – Luxate