Is there a way in swift to declare an inline function?

强颜欢笑 提交于 2019-11-28 22:29:18

Swift 1.2 will include the @inline attribute, with never and __always as parameters. For more info, see here.

As stated before, you rarely need to declare a function explicitly as @inline(__always) because Swift is fairly smart as to when to inline a function. Not having a function inlined, however, can be necessary in some code.

All credit to the answer, just summarizing the information from the link.

To make a function inline just add @inline(__always) before the function:

@inline(__always) func myFunction() {

}

However, it's worth considering and learning about the different possibilities. There are three possible ways to inline:

  • sometimes - will make sure to sometimes inline the function. This is the default behavior, you don't have to do anything! Swift compiler might automatically inline functions as an optimization.
  • always - will make sure to always inline the function. Achieve this behavior by adding @inline(__always) before the function. Use "if your function is rather small and you would prefer your app ran faster."
  • never - will make sure to never inline the function. This can be achieved by adding @inline(never) before the function. Use "if your function is quite long and you want to avoid increasing your code segment size."

I came across an issue that i needed to use @inlinable and @usableFromInline attributes that were introduced in Swift 4.2 so i would like to share my experience with you.

Let me get straight to the issue though, Our codebase has a Analytics Facade module that links other modules.

App Target -> Analytics Facade module -> Reporting module X.

Analytics Facade module has a function called report(_ rawReport: EventSerializable) that fire the reporting calls, This function uses an instance from the reporting module X to send the reporting calls for that specific reporting module X.

The thing is, calling that report(_ rawReport: EventSerializable) function many times to send the reporting calls once the users launch the app creates unavoidable overhead that caused a lot of crashes for us.

Moreover it's not an easy task to reproduce these crashes if you are setting the Optimisation level to None on the debug mode. In my case i was able only to reproduce it when i set the Optimisation level to Fastest, Smallest or even higher.

The solution was to use @inlinable and @usableFromInline.

Using @inlinable and @usableFromInline export the body of a function as part of a module's interface, making it available to the optimiser when referenced from other modules.

The @usableFromInline attribute marks an internal declaration as being part of the binary interface of a module, allowing it to be used from @inlinable code without exposing it as part of the module's source interface.

Across module boundaries, runtime generics introduce unavoidable overhead, as reified type metadata must be passed between functions, and various indirect access patterns must be used to manipulate values of generic type. For most applications, this overhead is negligible compared to the actual work performed by the code itself.

A client binary built against this framework can call those generics functions and enjoy a possible performance improvement when built with optimisations enabled, due to the elimination of abstraction overhead.

Sample Code:

@inlinable public func allEqual<T>(_ seq: T) -> Bool
    where T : Sequence, T.Element : Equatable {
        var iter = seq.makeIterator()
        guard let first = iter.next() else { return true }

        func rec(_ iter: inout T.Iterator) -> Bool {
            guard let next = iter.next() else { return true }
            return next == first && rec(&iter)
        }

        return rec(&iter)
}

More Info - Cross-module inlining and specialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!