Is there a way to declare an inline function in Swift?
Asked Answered
R

4

52

I'm very new to the Swift language.

I wanted to declare an inline function just like in C++ so my func declaration looks like this:

func MyFunction(param: Int) -> Int {
    ...
}

and I want to do something like this:

inline func MyFunction(param: Int) -> Int {
    ...
}

I tried to search on the web but I didn't find anything relevant maybe there is no inline keyword but maybe there is another way to inline the function in Swift.

Renascence answered 10/1, 2015 at 20:46 Comment(8)
Why would you want to do this?Celaeno
I want to reduce the time for the function call, I know it will expand and my source code will be larger but I wanted to make a benchmark. but first I need to know how to do inline in swift!Renascence
Well, as far as I know Swift has no inline-functionality like C++, and honestly, I don't see how that woulld reduce the time for a function call at all. Swift is fundamentally a very different language from C++.Celaeno
in C++ if I want to overload, let say, the "+" operator for a class, and I will be using it a million of times making the overloaded function as inline will save me a lot of time. I did a similar test with swift calling and empty fun 500000 time the cost of the callbacks was around 5,47 sec an inline implementation (if there is one) should do betterRenascence
Hm, that's interesting. Objective-C used to have a preprocessor that could potentially have been able to do this, but since Swift doesn't, and it isn't compiled at runtime, I don't see any way this can be achieved unfortunately.Celaeno
Many thanks @Celaeno I will try to see with Objective-C and see merging it with Swift if I canRenascence
On second thought, Obj-C doesn't compile at runtime either, so it's pretty much not possible. Sorry!Celaeno
The answer is security. We have a pretty complex code, which performs some security task and it MUST NEVER BE CENTRALISED (as the attacker can only bypass the single place to cancel all the protection everywhere). Normally (C, yes, I am that old), this would be done using the preprocessor, but according to my research, Swift does not provide the macros. So I was looking for the other option, which is inlining.Nedneda
J
62

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.

Swift-5 added the @inlinable attribute, which helps ensuring that library/framework stuff are inlineable for those that link to your library. Make sure you read up about it, as there may be a couple of gotchas that might make it unusable. It's also only for functions/methods declared public, as it's meant for libraries wanting to expose inline stuff.

Jugular answered 29/3, 2015 at 17:10 Comment(2)
"Not having a function inlined, however, can be necessary in some code." Could you give an example, for educational purposes?Rumsey
@Rumsey Recursive functions, for example. Note that some recursive functions can derecursed into a loop, but some functions are inherently recursive, see this great video.Myceto
V
26

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."
Vineyard answered 28/5, 2017 at 19:8 Comment(0)
M
7

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

Musgrove answered 2/8, 2019 at 21:23 Comment(0)
D
1

I came here because I was looking for a way to obfuscate code for security reasons.
Inlining a sensitive method can make it harder to get sensitive information from a compiled binary.

I found a good summary of the topic in this article: The forbidden inline attribute in swift

The author recommends in general not to use @inline because the decision should be left for the compiler to take, plus it is not even officially supported.
However it also lines out some edge cases where @inline may be beneficial, like optimising for speed or code obfuscation.

Dimorphous answered 21/4, 2023 at 7:15 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.