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
Related
I'm seeing some strange behavior at the interface of protocol extensions and generics. I'm new to Swift, so possibly I misunderstand, but I don't see how this can be correct behavior.
First let's define a protocol, and extend it with a default function implementation:
protocol Foo {
}
extension Foo {
static func yo() {
print("Foo.yo")
}
}
Now define a couple of conforming types:
struct A: Foo {
}
struct B: Foo {
static func yo() {
print("B.yo")
}
}
A.yo()
B.yo()
As expected, A.yo() uses the default implementation of yo, whereas B.yo() uses the explicit implementation provided by B: the output is
Foo.yo
B.yo
Now let's make a simple generic type:
struct C<T: Foo> {
static func what() {
T.yo()
}
}
C<A>.what()
C<B>.what()
C<A>.what() prints Foo.yo, as expected. But C<B>.what() also prints Foo.yo!
Surely the meaning of C<B> is simply the template for C with B substituted in for the type parameter T? Yet B's version of yo is not being called.
What am I missing? I'm using Swift 5.2.2.
Now, as it turns out you can fix this problem by declaring yo in the original definition of Foo. If we do this:
protocol Foo {
static func yo()
}
then C<B>.what() works as I would expect, printing B.yo. I can't understand the original behavior in the first place, but even less can I understand how this would change it.
In my actual application I can't use this fix, because I am extending a pre-existing protocol with a function that I want to specialize in a particular conforming type.
Generics are resolved at compile time. They're not dynamically dispatched like method calls on class hierarchies or protocols. That staticness is kind of their point, that's where the performance wins stem from.
As far as I can tell, Foo.yo() and B.yo() are totally unrelated functions. Calling Foo.yo() does a statically dispatched call to Foo, and likewise, calling B.yo() causes a statically dispatched call to B.
Yet, if you up-cast B.self to a Foo.Type, and you call yo() on it, you end up with a statically dispatched call to Foo:
(B.self as Foo.Type).yo()
To get dynamic dispatch (to achieve the kind of polymorphism you're after), you need to define yo as a requirement of the protocol. That establishes a relationship between B.yo() (which is now a part of the conformance to the protocol) and Foo.yo() (which is a default implementation for types who don't provide their own).
protocol Foo {
// static func yo() // uncomment this
}
extension Foo {
static func yo() {
print("Foo.yo")
}
}
struct A: Foo {
}
struct B: Foo {
static func yo() {
print("B.yo")
}
}
struct C<T: Foo> {
static func what() {
T.yo()
}
}
A.yo()
B.yo()
(B.self as Foo.Type).yo()
C<A>.what()
C<B>.what()
Results before:
Foo.yo
B.yo
Foo.yo
Foo.yo
Foo.yo
Results after making yo a requirement:
Foo.yo
B.yo
B.yo
Foo.yo
B.yo
Itβs hard to suggest a fix for your exact situation without more details of the exact situation- are you not able to provide these? Suffice to say this is the expected behaviour and its to do with some optimisations and assumptions the compiler makes.
You might want to check out this article on static vs dynamic dispatch in Swift: https://medium.com/#PavloShadov/https-medium-com-pavloshadov-swift-protocols-magic-of-dynamic-static-methods-dispatches-dfe0e0c85509
While doing some research on ncurses and how to use it in Swift, I took a look at IOGUI.
It wouldn't compile properly, so I began clearing warnings and errors.
That's when I came across what may be some Swift subtleness that I'm unaware of.
Note: I'm not discussing compilation errors below. This question is specific to the parsing done by Xcode to indicate warnings and errors in the code editor.
Referring to the following struct:
public struct MenuWidget {
var widgetRows: Int
// CUT
private var startRow: Int
#if os(Linux)
public init(startRow: Int, widgetSize: Int, choices: [GUIMenuChoices], delegate: #escaping MenuChoicesSelectionDelegate, mainWindow: UnsafeMutablePointer<WINDOW>) {
self.startRow = startRow
// CUT
initWindows()
}
#else
public init(startRow: Int, widgetSize: Int, choices: [GUIMenuChoices], delegate: #escaping MenuChoicesSelectionDelegate, mainWindow: OpaquePointer) {
self.startRow = startRow
// CUT
initWindows()
}
#endif
// CUT
} // END STRUCT
Within the #if os(Linux) section, self.startRow is marked as inaccessible from that scope.
Yet in the #else, there is no error indicated. widgetRows is accessible in both the #if and #else
If I remove private from the startRow declaration, then it's fine in both scopes. But that makes the variable internal and makes it accessible outside of the struct, which is incorrect.
It could also just be the behavior of the Swift #if construct that I'm not familiar with.
I've searched the usual places, including here at SO. Nothing similar deals with this particular scenario, at least not with the search terms I used.
Any hints or tips would be appreciated.
P.S. If you want to check out the IOGUI source, I'm specifically referring to lines 41 and 78-100 (inclusive) of MenuWidget.swift.
This is not an if construct; it's an #if construct. That means that only one of the #if / #endif blocks even compiles. The other could be complete nonsense for all the Swift compiler cares; the compiler never even sees it. That is what conditional compilation means. So, if you are not on Linux, you have no way of knowing how the code inside the #if part behaves. The code would be just the same if it said this:
#if os(Linux)
public init(startRow: Int, widgetSize: Int, choices: [GUIMenuChoices], delegate: #escaping MenuChoicesSelectionDelegate, mainWindow: UnsafeMutablePointer<WINDOW>) {
zampabalooie and a hot-cha-cha
}
#else
public init(startRow: Int, widgetSize: Int, choices: [GUIMenuChoices], delegate: #escaping MenuChoicesSelectionDelegate, mainWindow: OpaquePointer) {
self.startRow = startRow
// CUT
initWindows()
}
#endif
If you are not on Linux, that will compile just fine β and that doesn't entitle you to start drawing conclusions about Swift's knowledge of some amazing "zampabalooie" or its sudden use of spaces between terms.
And conversely, if you are on Linux, you have no way of knowing how the code inside the #else part behaves.
I'm writing a debugging function that will be called from other function in my project. This function is marked as #inline(__always), and does nothing if DEBUG is 0.
Does this function have any cost whatsoever at DEBUG == 0? I'm pretty sure that the answer is no, but I just want to confirm it.
tl;dr
Zero cost π
Elaboration
I'm assuming your function looks something like this:
#inline(__always)
func myFunction() {
#if DEBUG
doStuff()
doStuff()
doStuff()
#endif
}
First, the preprocessor directives are followed. So if your DEBUG flag is 0, you can think of it as being preprocessed into this:
#inline(__always)
func myFunction() {
}
When you call myFunction anywhere, it's replaced with its contents at compile time. Assuming DEBUG is still 0, can think of it like this:
// What you wrote:
func myOtherFunction() {
print("Before")
myFunction()
print("After")
}
// Imagine it becoming this while compiling:
func myOtherFunction() {
print("Before")
print("After")
}
And, as you can see, the non-content of your inlined empty function are included, introducing zero cost to calling this function in this compilation environment.
Obviously, Swift code is not compiled into more Swift code. That's why I said you can imagine this; it's not truly what's happening. In actuality, it gets compiled into LLVM IR, but the end result is the same.
To provide a fallback language for NSLocalizedString, I'm using this #undef and #define in Objective-C:
#undef NSLocalizedString
#define NSLocalizedString(key, comment) #"NSLocalizedString has been replaced";
This works perfectly well if called from Objective-C, but if called from Swift, the new definition of NSLocalizedString is ignored. (bridging header is configured correctly and works)
Is this possible in Swift, and if so, how?
Note: the real example is here on Github, also see SO answer here
You can do this for NSObject subclasses like this
extension NSObject {
func NSLocalizedString(key: String, comment: String) -> String {
return "yes we have localized an NSObject"
}
}
What about AnyObject? In this case, you would have to be aware of and conform to the FallbackLanguage protocol in your AnyObject subclass
protocol FallbackLanguage: class {}
// add default implementations
extension FallbackLanguage {
func NSLocalizedString(key: String, comment: String) -> String {
return "yes we have localized AnyObject via FallbackLanguage protocol"
}
}
Notes
These two solutions can both be in your project without any issues.
If you're calling NSLocalizedString outside of a class instance, you're out of luck.
You will have to do a global function... the other options will cause all sort of problems, such as retrain cycles, or classes classes witch do not inherit from NSObject(that is only subset of the problems) - this will not work at all. yes global function usually are big no! but that is the only way to "override" global function. ,
Here is a code I use in production, we had few thousands of string, at some point we had to make our app dynamically localized - and this is what we did.
// Global functions for lagacy code
func NSLocalizedString(_ key: String, comment: String) -> String {
return key.localized()
}
func NSLocalizedStringInTable(key: String, tableName: String ) -> String {
return key.localized(using: tableName)
}
Calling a method from its name (in a String format) can be sometimes useful.
In Swift it is recomended to change behavior and to use closures to do something "dynamically", so for example you can have a dictionary of functions, with the name as the key, and the implementation as the value.
However, sometimes you want to simply know "how to do it", and this is the reason of this question.
So, how to call dynamically a Swift method starting from it's name as string?
In Objective C it was simple:
[self performSelector:NSSelectorFromString(#"aSelector")];
But performSelector is banned in Swift
Is there any alternative?
In Swift, you should use closures and change your approach.
However, if you want to use performSelector to dynamically call a method given only it's String signature, altough it's not supported natively, I've found how to do it.
It is possible to create a C alternative to performSelector that:
works even on native swift classes (non objective-c)
takes a selector from string
However it's not so straightforward to implement a complete version of it, and it's necessary to create the method in C.
in C we have dlsym(), a function that returns a pointer to a function given the char symbol.
Well, reading this interesting post:
http://www.eswick.com/2014/06/inside-swift/
I've learned a lot of interesting things about swift.
Swift instance methods are plain functions with a specific signature, like this
_TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString
where the "self" value is passed as the last parameter
in short you can call it directly from the c side without any kind of bridging, it is sufficient to rebuild the correct function signature.
In the signature above, there is the name of the project (FirstSwiftTest) and the lenght (14), the name of the class (ASampleClass) and the lenght (12), the name of the function (aTestFunction) and the lenght (13), then other values as the return type ecc ecc. For other details look at the previous link
The function above, is the representation of this:
class ASampleClass
{
func aTestFunction() -> NSString
{
println("called correctly")
return NSString(string: "test")
}
}
Well, on the c side, I was able to create this function
#include <stdio.h>
#include <dlfcn.h>
typedef struct objc_object *id;
id _performMethod(id stringMethod, id onObject)
{
// ...
// here the code (to be created) to translate stringMethod in _TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString
// ...
id (*functionImplementation)(id);
*(void **) (&functionImplementation) = dlsym(RTLD_DEFAULT, "_TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString");
char *error;
if ((error = dlerror()) != NULL) {
printf("Method not found \n");
} else {
return functionImplementation(onObject); // <--- call the function
}
return NULL
}
And then called it on the swift side
let sampleClassInstance = ASampleClass()
println(_performMethod("aTestFunction", sampleClassInstance))
The function resulted in these statement printed on the log:
called correctly
test
So it should be not so difficult to create a _performMethod() alternative in C that:
creates automatically the function signature (since it seems to have a logic :-)
manages different return value types and parameters
EDIT
In Swift 2 (and maybe in Beta3, I didn't try) It seems that performSelector() is permitted (and you can call it only on NSObject subclasses). Examining the binary, It seems that now Swift creates static functions that can be specifically called by performSelector.
I created this class
class TestClass: NSObject {
func test() -> Void {
print("Hello");
}
}
let test = TestClass()
let aSel : Selector = NSSelectorFromString("test")
test.performSelector(aSel)
and now in the binary I find
000000010026d830 t __TToFC7Perform9TestClass4testfT_T_
At this time, I don't understand well the reasons behind this, but I'll investigate further
You could call a method from a String this way:
let foo = <some NSObject subclass instance>
let selectorName = "name"
foo.perform(Selector(selectorName))
It is available only when your foo class is subclass of NSObject
swift3 version
class MyClass:NSObject
{
required public override init() { print("Hi!") }
public func test(){
print("This is Test")
}
public class func static_test(){
print("This is Static Test")
}
}
if let c: NSObject.Type = NSClassFromString("TestPerformSelector.MyClass") as? NSObject.Type{
let c_tmp = c.init()
c_tmp.perform(Selector("test"))
c.perform(Selector("static_test"))
}