# Specialised closures in an ABI-stable library

**URL:** <https://forums.swift.org/t/specialised-closures-in-an-abi-stable-library/67856>\
**Category:** Using Swift\
**Tags:** generics, optimizations, resilience, specialization\
**Created:** [October 14, 2023, 4:58pm UTC](https://forums.swift.org/t/specialised-closures-in-an-abi-stable-library/67856 "2023-10-14T16:58:52Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [October 14, 2023, 4:58pm UTC](https://forums.swift.org/t/specialised-closures-in-an-abi-stable-library/67856/1 "2023-10-14T16:58:52Z")

</div>

I'm working on a feature for a resilient library, that looks something like this:

```swift
@frozen
public struct Stream<Source: IteratorProtocol<Int>>: IteratorProtocol {

  public var source: Source

  @usableFromInline
  internal var internalState: InternalState

  @inlinable
  public mutating func next() -> Int? {
    internalState.next { source.next() }
  }
}

@usableFromInline
internal struct InternalState {

  @usableFromInline
  internal func next(consumeFromSource: () -> Int?) -> Int? {
    //... Algorithm not available for inlining ...
  }
}

```

In words: we have a public generic outer type, which is completely specialisable by client modules, and a non-generic internal core, which is our ABI barrier. The implementation details of the core are not exposed at all to clients.

Clients are supposed to pass data in to the core via the non-escaping closure. The idea is that, because that part is `@inlinable`, they can specialise the closure and hopefully avoid runtime metadata lookups.

Unfortunately I don't think that's what I'm seeing:

 ![image](https://global.discourse-cdn.com/swift/original/3X/4/2/425418c3a4d029024c3079d46c66b038dda57bf9.png)

BTW: the resilient library I mentioned before is the standard library, `Stream` is `Unicode.NFC<S>.Iterator`, and `InternalState` is `_NFCNormalizerState` and `_NFDNormalizerState`. I don't think that's relevant but it helps explain what the picture is showing - the highlighted frame is `Stream<S>.next`.

What I think the Instruments output is telling me is that, although the `Stream.next` function can be inlined (I did have to force it using `@inline(__always)`), that doesn't seem to include `closure #1 in (Stream.next)`, which doesn't seem to be inlined or specialised or anything.

And as a result, the closure contains calls to `swift_checkMetadataState` taking up 44% of each call to `next()`, together with smaller functions such as `swift_getAssociatedTypeWitness` and `swift_getAssociatedConformanceWitness` which I believe indicate a lack of specialisation.

So my questions are:

1. Am I reading the instruments output ~correctly? Would it be possible to eliminate the calls to `swift_checkMetadataState` if the closure were specialised?

2. Is the pattern I'm trying to implement sound, conceptually? Is there something I'm overlooking?

3. If I understand it correctly and the pattern is sound, is it possible for me to do anything to get the performance I'm looking for? Or is this maybe an optimiser issue?

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [October 14, 2023, 6:33pm UTC](https://forums.swift.org/t/specialised-closures-in-an-abi-stable-library/67856/2 "2023-10-14T18:33:13Z")

</div>

OK I solved it.

It turns out, one of the _calling_ functions in the client library was generic but only `@usableFromInline`. In other words, `Source` itself was an unspecialised generic:

```swift
// This was a stack of functions, but basically amounts to this:

@usableFromInline
internal func process(_ source: some IteratorProtocol<Int>) {
  for value in Stream(source) {
    // ...
  }
}

```

Once that function was made `@inlinable`, `Stream<Source>` could be fully specialised (as intended). It did exactly what I wanted it to do, and the performance is everything I hoped it would be. So this pattern does work 🙂

---

<div class="post-metadata">

**Author:** ![dmt](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dmt/32/30830_2.png) [@dmt](https://forums.swift.org/u/dmt)\
**Post date:** [October 14, 2023, 7:10pm UTC](https://forums.swift.org/t/specialised-closures-in-an-abi-stable-library/67856/3 "2023-10-14T19:10:26Z")

</div>

It catches me pretty regularly. Wish there's a linter for this (Or maybe I just didn't find one)

---

<div class="post-metadata">

**Author:** ![\_ck512](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/_ck512/32/32421_2.png) [@\_ck512](https://forums.swift.org/u/_ck512)\
**Post date:** [June 6, 2024, 8:29am UTC](https://forums.swift.org/t/specialised-closures-in-an-abi-stable-library/67856/4 "2024-06-06T08:29:34Z")

</div>

You can use `-Xswiftc -Rpass-missed='specialize'`, it reports warnings like "Unable to specialize `foo` because definition is not visible". You can add `@inlinable` to those definitions.
