Macros in Swift?
MacrosSwiftMacros Problem Overview
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.
Macros Solutions
Solution 1 - Macros
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.
Solution 2 - Macros
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.
Solution 3 - Macros
Since XCode 7.3, the __FILE__
__FUNCTION__
and __LINE__
compile-time constants have become the nicer-looking #file
#function
and #line
respectively.
Solution 4 - Macros
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)")
Solution 5 - Macros
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")
Solution 6 - Macros
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...
Solution 7 - Macros
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.
Solution 8 - Macros
Swift doesn't support macros because it would conflict with type-safety.