Objective-C++ and Swift - nested structs in bridging header - swift

Please help me with the following issue. I am using the swift argument parser library https://github.com/apple/swift-argument-parser
Suppose I have this swift code in some swift file:
#objc public class Math: NSObject, ParsableCommand {
static var configuration = CommandConfiguration(
abstract: "A utility for performing maths.",
subcommands: [Add.self],
defaultSubcommand: Add.self)
}
extension Math {
struct Add: ParsableCommand {
static var configuration = CommandConfiguration(abstract: "Print the sum of the values.")
mutating func run() {
print("0")
}
}
}
` and I want to call to an objective-c++ function named "func" with an argument which is of type Math.Add like so from main.swift file:
var status: Int32 = 0
do {
// try to parse application arguments
var args = try Math.parseAsRoot()
switch args {
case let args as Math.Add:
status = func(args)
default:
try args.run()
}
} catch {
//Some code...
}
What should be the signature of the function and how the bridging-header files should look like? I made the signature be:
extern "C" int func(Math.Add *args);
And my bridging header is like so:
#ifndef __BRIDGING_HEADER_H__
#define __BRIDGING_HEADER_H__
#class Math;
#ifdef __cplusplus
extern "C" {
#endif
int func(Math.Add *args);
#ifdef __cplusplus
}
#endif
#endif /* __BRIDGING_HEADER_H__ */
but is doesn't work and the bridging header doesn't compile (Xcode writes the error: Interface type 'Math' cannot be passed by value; did you forget * in 'Math'?

Objective-C(++) doesn't support nested types, what you can do if you want to keep the nested structure on Swift, is to export a non-nested type for Objective-C:
extension Math {
#objc(Math_Add) // or MathAdd, or whatever name you like
struct Add: ParsableCommand {
, which can then be referenced in your header:
int func(Math_Add *args);
As a side note, I would also change the name of the func function to something that doesn't collide with Swift keywords. Even if you'll be able to call it, it will be confusing for other readers of your code.

Related

Swift macros when creating Array from literals

For the code below:
let services: [MyServices] = [
MyService(),
#if DEBUG
DebugService(),
#endif
]
I get compiler error:
expression failed to parse:
error: MyPlayground.playground:375:5: error: expected expression in container literal
#if DEBUG
^
error: MyPlayground.playground:376:19: error: consecutive statements on a line must be separated by ';'
DebugService(),
^
;
error: MyPlayground.playground:376:19: error: expected expression
DebugService(),
^
error: MyPlayground.playground:378:1: error: expected expression
]
But the same code works in Objective-C
NSArray *array = #[
#"11",
#if DEBUG
#"debug",
#endif
#"22"
];
Is this a compiler bug or expected behaviour ? Thank you.
Generally the body of each clause in an #if ... #else ... #endif compiler directive must surround complete statements.
But with the implementation of SE-308 #if for postfix member expressions in Swift 5.5 this directive has been expanded to be able to surround postfix member expressions.
So with a custom extension
extension Array {
func appending(_ e: Element) -> Self {
return self + [e]
}
}
one can conditionally initialize an array like this:
let services = [
MyService() ]
#if DEBUG
.appending(DebugService())
#endif
The #if / #endif constructs are not preprocessor macros like in C. They are compiler directives. They are part of the language.
In C, it runs the preprocessor on your source file, which results in a modified source file. That modified source file gets compiled.
Not so in Swift. In Swift, the compiler parses the source file and attempts to compile it.
Edit:
To understand why what you tried doesn't work, think of the #if / #endif like a regular if statement. Would the following compile?
let debug = true
let services: [MyServices] = [
MyService(),
if debug {
DebugService(),
}
]
(Answer: No. That's not legal. You can't insert an if statement in the middle of the parameters of an array initializer. Same goes for an #if / #elseif statement.)
You can’t use an #if / #endif block to assemble fragments of a statement together.
You would have to create complete statements in both cases:
#if debug
let services: [MyServices] = [
MyService(),
DebugService(),
]
#else
let services: [MyServices] = [
MyService()
]
#endif
(Or you could make services a var, and append DebugServices() to it inside an #if / #endif.)
Edit #2:
Better yet, use a "postfix" .appending() as in #MartinR's excellent answer.
Swift 5.5 (Using Swift Playgrounds)
import SwiftUI
struct ContentView: View {
let service: MyService = {
#if DEBUG
return DebugService()
#else
return MyService()
#endif
}()
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
}
}
}
class MyService: MyServices {
func resultHandler() {
print("RELEASE")
}
}
#if DEBUG
class DebugService: MyServices {
func resultHandler() {
print("DEBUG")
}
}
#endif
protocol MyServices {
func resultHandler()
}

Can I define constructor without arguments in C?

I have a C code:
static __inline__ __attribute__((__always_inline__))
__attribute((swift_name("Test.init()")))
test_t test_init(void) { /* ... */ }
And test Swift code:
let test = Test()
The code is compiled, but function test_init not call.
If I add test argument and call init with him, my method * test_init * is called.
For structures imported from C the compiler creates an init() initializer which takes no arguments and sets all members to zero. For example
__attribute((swift_name("Test")))
typedef struct {
int a;
} test_t;
is imported to Swift as
public struct Test {
public var a: Int32
public init()
public init(a: Int32)
}
as one can see with "Navigate -> Jump to Generated Interface" in Xcode.
You can create additional init methods in C, but you cannot replace
existing init methods.
(One could argue that the compiler should as least warn that the
C function with the Swift name "Test.init()" will be ignored in Swift, so you might consider to file a bug report.)
If you want to define another init method taking no arguments in C
then you have to give it a dummy Void argument:
__attribute((swift_name("Test.init(v:)")))
static __inline__ __attribute__((__always_inline__))
test_t test_init(void) {
test_t t = { 3 };
return t;
}
and call it as
let test = Test(v: ())
print(test) // Test(a: 3)

How to access a custom function from any file in the same Swift project?

If the postfix operator of a custom function is declared at file scope - as in my previous post - there must be a way to access such a function from another Swift 3 file in the same Xcode project.
Apple’s documentation on custom functions states that “New operators are declared at a global level …“ so I can presume the creators of Swift 3 would consider it important for a custom function to be accessed globally. But for a novice in Swift it is not self-evident how I would do this.
Based on code in my previous accepted answer (here) what would I need to do so a custom function can be accessed from another file elsewhere in the project ?
FINAL EDIT
The solution is embarrassingly simple (see accepted answer) and hopefully other Swift novices may also find it useful.
A postfix operator % is declared globally while an Extension of Int reads an Int variable from another file. Extensions of Double and CGFloat as well as Int are also possible.
CustomOperators.swift
import UIKit
postfix operator %
extension Double {
static postfix func % (n: Double) -> Double {
return Double(n) / 100
}
}
extension Int {
static postfix func % (n: Int) -> Double {
return Double(n) / 100
}
}
extension CGFloat {
static postfix func % (n: CGFloat) -> Double {
return Double(n) / 100
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
let test1: Double = 93.7
let test2: Int = 80
let test3: CGFloat = 70
override func viewDidLoad() {
super.viewDidLoad()
print(test1%) // prints '0.937'
print(test2%) // prints '0.8'
print(test3%) // prints '0.7'
}
}
Thanks marosoiae, and also Martin R and unniversal for your input.
EDIT 2
Martin R’s comments prompted me to try a further example with my custom postfix function defined in Utils but in file scope rather than as a static postfix function. Utils becomes an empty class for custom functions all defined in file scope outside the class.
import UIKit
class ViewController: UIViewController {
let value: Int = 25
override func viewDidLoad() {
super.viewDidLoad()
example1()
example2()
}
func example1() {
// 1. call to a function in Utils with an explicit value
// and nothing returned from Utils.
// Note this uses literal postfix syntax i.e. 25%
Utils.25%
// Debug message:
// Type 'Utils' has no member '25'
}
func example2() {
// 2. call to a function in Utils with an argument
// declared in UIViewController and nothing returned from Utils
Utils.(Int: value)%
// Debug message
// Expected member name following '.'
}
}
Utils.swift now compiles but from debug messages that Xcode reports with both examples, it is clear that the token '%' is expected immediately following the '.'.
Even without returning a variable from Utils.swift, this is obviously not how to call a postfix function in Utils.swift from a file elsewhere in the project. My question remains: how would I do it ?
EDIT 1
At this point it might help to include some code so I created a class with static functions, following the syntax (as far as possible) used in Unniversal's answer. I decided to try static functions if these help avoid cluttering the global scope with methods that should be owned by a class/struct.
File 1 - Utils
import UIKit
postfix operator %
class Utils {
static func yourFunction(){
//Do your stuff here
}
static func yourFunction1(value: Int) {
print(value)
}
static postfix func % (percentage: Int) -> Double {
return (Double(percentage) / 100)
}
}
The static function % reports
Member operator '%' must have at least one argument of type 'Utils'
which I’d expect to disappear once an argument is supplied from another file.
The following code shows four ways I tried to supply an argument to static functions in Utils. I ran the project with one example at a time
File 2 - UIViewController
import UIKit
class ViewController: UIViewController {
let value: Int = 25
var percentage = Double()
override func viewDidLoad() {
super.viewDidLoad()
// example1()
// example2()
// example3()
// example4()
}
func example1() {
// 1. call to a function in Utils with no argument and no return (i.e. suggested answer)
Utils.yourfunction()
// Debug messages:
// Type 'Utils' has no member 'yourfunction'
// Did you mean 'yourFunction'?
// Did you mean 'yourFunction1'?
}
func example2() {
// 2. call to a function in Utils with argument and no return
Utils.yourfunction1(Int: Int)
// Debug messages:
// Type 'Utils' has no member 'yourfunction'
// Did you mean 'yourFunction'?
// Did you mean 'yourFunction1'?
}
func example3() {
// 3. call to a function in Utils with argument and returning a value for percentage
Utils.%() {
return Int(percentage)
}
// Debug message:
// Use of unresolved operator '.%'
}
func example4() {
// 4. call to a function in Utils with argument and returning a value for percentage
percentage = Utils.%(Int: value) -> Int {
return Int(percentage)
}
// Debug messages:
// Use of unresolved operator '.%'
// Expected type before '->'
// Expected type after '->'
}
}
As far as I can see, static functions Utils.yourFunction and Utils.yourFunction1 can’t be accessed from outside Utils, as shown in example 1 and 2. And the postfix operator % seems to cause Xcode to report Use of unresolved operator ‘.%’, as shown in example 3 and 4. However these problems might be the way I adapted the syntax used by Unniversal.
Any function declared at file scope will have the implicit scope internal and will be visible in the rest of the project/module.
I recommend reading the access control guide for more information.
Edit:
I'm still not sure what you're trying to do, but it looks like you are mixing global functions with static methods and custom operators.
If what you want is to declare a custom operator that you can use in any other file in the project, the solution is in the documentation that you linked in your question.
So this is what you need to declare a custom % (as you defined it) for the Int type:
CustomOperators.swift
postfix operator %
extension Int {
static postfix func % (n: Int) -> Double {
return Double(n) / 100
}
}
main.swift
print(90%) //outputs "0.9"
That's all there is to it. You simply declare the operator globally: postfix operator % and you define the operator function as a static method in a extension on the Int type.
Now you can use your new operator in other files (like I did in main.swift).
If you want a function to be accessed globally I would recommend to create a class that has static functions. For example
class Utils {
static func yourFunction(){
//Do your stuff here
}
}
To use it :
Utils.yourfunction()

Is it possible to disable some lines of code in Swift?

I trying to make my code compilable with both Swift 1.2 and 2.0, without creating a new branch, by using macro.
Macro in Swift that you defined in custom Swift Compiler flags doesn't allow you to check the conditions as freely as Obj-C.
For example, in function declaration, if it like Obj-C. I can do something like this.
class ThisIsAClass
{
#if SWIFT_TWO_POINT_O
func foo(bar bar: String)
#else
func foo(#bar: String)
#endif
{
// Do some common code
// ...
// ...
#if SWIFT_TWO_POINT_O
print("Do 2.0 things")
#else
print("Do 1.2 things")
#endif
}
}
Macro condition checking within the function is fine.
But the condition checking for declaring function will failed.
Is there a way I can achieve something like this.
Or separate between Swift 1.2 and 2.0 branches is the only way.
Yes, you can define compiler flags and check them to conditionally compile parts of your source, as noted in the docs.
However, there's an important caveat (emphasis added):
In contrast with condition compilation statements in the C preprocessor, conditional compilation statements in Swift must completely surround blocks of code that are self-contained and syntactically valid. This is because all Swift code is syntax checked, even when it is not compiled.
So you can't do:
#if SWIFT_ONE
func foo(/* swift 1 params */)
#else
func foo(/* swift 2 params */)
#endif
{
// ... function body ...
}
...because func foo(params) is not a syntactically complete element. (A syntactically complete function declaration includes the function body.) Ditto for, say, trying to #if around a class declaration but not its contents, etc.
So what can you do instead?
in this particular case, func foo(bar bar: String) is perfectly valid Swift 1.x syntax. The # was merely a shorthand for it... so just use the longhand and you won't have to worry about language-version differences. (Feel free to post about #foo and #bar on Twitter, though.)
more generally, you can have multiple separate functions and dispatch to them:
func foo() {
#if SWIFT_ONE
fooForSwift1()
#else
fooForSwift2()
#endif
}
or for classes or other types, you can use type aliases:
class Foo1 { /* ... */ }
class Foo2 { /* ... */ }
#if SWIFT_ONE
typealias Foo = Foo1
#else
typealias Foo = Foo2
#endif

Macros in Swift?

Does Swift currently support macros, or are there future plans to add support? Currently I'm scattering:
Log.trace(nil, function: __FUNCTION__, file: __FILE__, line: __LINE__)
In various places throughout my code.
In this case you should add a default value for the "macro" parameters.
Swift 2.2 and higher
func log(message: String,
function: String = #function,
file: String = #file,
line: Int = #line) {
print("Message \"\(message)\" (File: \(file), Function: \(function), Line: \(line))")
}
log("Some message")
Swift 2.1 and lower
func log(message: String,
function: String = __FUNCTION__,
file: String = __FILE__,
line: Int = __LINE__) {
print("Message \"\(message)\" (File: \(file.lastPathComponent), Function: \(function), Line: \(line))")
}
log("Some message")
This is what fatalError and assert functions do.
There are no other macros except the conditional compilation already mentioned in another answer.
The Apple docs state that:
Declare simple macros as global constants, and translate complex macros into functions.
You can still use #if/#else/#endif - but my feeling is that they will not introduce macro functions, the language simply doesn't need it.
Since XCode 7.3, the __FILE__ __FUNCTION__ and __LINE__ compile-time constants have become the nicer-looking #file #function and #line respectively.
Here is an updated Swift 2 answer.
func LogW(msg:String, function: String = #function, file: String = #file, line: Int = #line){
print("[WARNING]\(makeTag(function, file: file, line: line)) : \(msg)")
}
private func makeTag(function: String, file: String, line: Int) -> String{
let url = NSURL(fileURLWithPath: file)
let className = url.lastPathComponent ?? file
return "\(className) \(function)[\(line)]"
}
Example of use:
LogW("Socket connection error: \(error)")
lastPathComponent needs an NSURL, so I changed the above code to this:
func log(message: String,
function: String = __FUNCTION__,
file: String = __FILE__,
line: Int = __LINE__) {
let url = NSURL(fileURLWithPath: file)
print("Message \"\(message)\" (File: \(url.lastPathComponent ?? "?"), Function: \(function), Line: \(line))")
}
log("some message")
There is way to use macros on swift (but this used in Mixed of objective c and swift)
declare your macros into Project-name-Bridging-Header.h
#define YOUR_MACRO #"Description"
or create separate header file for macros "macros.h"
import this header "macros.h" in to your Bridging-Header.h file..
now just save your project your macros will came in swift file ..
if you don't wanna object c code on your swift project... just create dummy cocoa touch classes it will create bridging header then use my way...
Macros are evil, but sometimes you just need them. For example, I have
struct RegionEntity {
var id: Int!
}
And I want to place instances of this struct to Set. So I have to conform it to Hashable protocol.
extension RegionEntity: Hashable {
public var hashValue: Int {
return id
}
}
public func ==(first: RegionEntity, second: RegionEntity) -> Bool {
return first.id == second.id
}
Great. But what if I have dozens of such structs and the logic is the same? Maybe I can declare some protocol and conform it to Hashable implicitly. Let's check:
protocol Indexable {
var id: Int! { get }
}
extension Indexable {
var hashValue: Int {
return id
}
}
func ==(first: Indexable, second: Indexable) -> Bool {
return first.id == second.id
}
Well, it works. And now I'm gonna conform my struct to both protocols:
struct RegionEntity: Indexable, Hashable {
var id: Int!
}
Nope. I can't do that, because Equatable requires == operator with Self and there is no == operator for RegionEntity.
Swift forces me to copy-paste confirmation code for each struct and just change the name. With macro I could do that with only one line.
A macro proposal is going through Swift Evolution right now. This would allow you to define a custom type that could create a macro that can be evaluated at compile time, like the C stringify macro, for example.
https://forums.swift.org/t/se-0382-expression-macros/62090