Swift - how to create custom operators to use in other modules? - swift

I created a sample project and a framework next to it. The framework is called "SampleFramework". Then I created a custom operator in SampleFramework. Here is what it looks like:
infix operator >>= {associativity left}
public func >>=<A, B>(a: A?, f: A -> B?) -> B? {
if let a = a { return f(a) }
else { return .None }
}
Then I wanted to use it my main application. I imported the SampleFramework to my source file and then I wrote this code to test it:
NSURL(string: "www.google.com") >>= { println("\($0)") }
It didn't compile. Here is Xcode's error message:
Ambiguous operator declarations found for operator. Operator is not a
known binary operator

I can confirm that that what you are seeing is what really happens. I just tried it myself and I've seen the same result.
My opinion is that >>= is somehow conflicting with some other operator (probably the bite shift operator: >>) or is being declared somewhere else too (you can see why I think that here). I did successfully declared custom operators in a framework and used those in the main app code before (you can see that here for example).
What I would suggest is rename your custom operator to something else. When I did that (renamed the custom operator to >>>=) the compiler stopped complaining and my app compiled just fine.
Later edit
Ok. So this might help a bit more. Basically when an operator is already declared and you want to add extra functionality to that operator (for example doing things like 3 * "Hello" like Johan Kool said he wanted to) all you have to do is overload that operator's method.
Basically, in your specific case I am now 100% that >>= is an already declared operator and you can go ahead and just add these lines in your framework:
public func >>=<A, B>(a: A?, f: A -> B?) -> B? {
if let a = a { return f(a) }
else { return .None }
}
This will make your operator work. BUT it will inherit the precedence and associativity of the original operator thus giving you less control over how it's supposed to behave.

I figured it out. I think declaration of operator (infix operator >>= {associativity left}) is module specific. You can't apply access control to it. But the operator function can be accessed in other modules. So in order to make this work I had to copy operator declaration and paste it to main project.

It seems to be sufficient to just add the
infix operator + : Additive
in each source where you want to apply your framework-defined operator, assuming that your framework has some
public func + (lhs: ...
declared.
Anyhow, it's nasty to have the need for adding this if you use a framework and I'd like to see some way to have some global approach where importing a framework also makes available the operators automatically.
Edit After fiddling around for hours, the problem went away. I have not figured out what's the cause. I had lots of infix declarations in my basic framework (for historic reason). Once I got rid of them, everything went to normal. So now that I have only infix for the new operators, it's fine. But obviously re-declaring existing ones (like *, +, etc.) Swift seems to get hick-ups.

Related

Swift: Chaining String/Substring methods yields 'ambiguous use of' errors. Fix or alternative?

I'm trying to do the most basic string manipulation using Swift. It looks like String provides everything I need, even though it relies on Substring intermediate results. So this works
let myString = "0123456789"
let mySubstring = myString.dropFirst(2)
print(mySubstring.dropLast(2))
It successfully yields "234567" as a Substring.
However, when I attempt to chain the calls...
print(myString.dropFirst(2).dropLast(2))
I get the following error...
9> print(myString.dropFirst(2).dropLast(2))
error: repl.swift:9:7: error: ambiguous use of 'dropFirst'
print(myString.dropFirst(2).dropLast(2))
^
Swift.Collection:39:17: note: found this candidate
public func dropFirst(_ n: Int) -> Self.SubSequence
^
Swift.Sequence:20:17: note: found this candidate
public func dropFirst(_ n: Int) -> AnySequence<Self.Element>
^
So it seems like the compiler is understandably having trouble inferring which dropFirst method to invoke because it is defined twice with different return types.
Is there a way around this? Is this just really poor API design on Apple's part? I'm trying to just get a nice easy to read and concise bit of code. I can also make it work by resorting to NSString but this seems wasteful and even more verbose and obtuse.
UPDATE:
I am able to get a better result by adding as Substring after the chain as in...
print(myString.dropFirst(2).dropLast(2) as Substring)
...since that disambiguates the overloaded methods. I would still love to see a more concise solution. Thanks.
If you define the return type, it has no trouble resolving which function to use. There are a number of ways to do this, such as:
let mySubstring: Substring = myString.dropFirst(2).dropLast(2)
Of course, as you say, you can insert this Substring type within the expression:
let mySubstring = (myString.dropFirst(2) as Substring).dropLast(2)
Surprisingly, it works if you reverse the order and do the dropLast first:
print(myString.dropLast(2).dropFirst(2))

Swift: Why to functions have parameters and return value types?

I'm filling a few gaps in my existing Swift programming language skills before moving onto the more advanced features.
I have checked Apples... "Swift Programming Language" guide and Google search shows lots of information about the rules around using the parameters, but I am looking for the overall Why , not the How...
Question:
Why is there a need to have parameters and return value types for functions in Swift?
(I am not asking about the parameter names etc., but a higher level (general) question on 'Why')
I have made a number of programs using simple C-Style functions in Swift, without a need for parameters or return values which works fine as I know what the functions should be doing for me.
Simple e.g.
func printName() {
print("John")
}
However, there are 'exceptions' like some in-built Swift functions.
E.g....
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return colors.count
}
etc. for table view or collection view usage .
So the only reason I see for using parameters + return values (type) in functions is to ensure only specific type of data is inputted and outputted.
In other words, its a way to avoid unexpected outcomes. So acting almost like a Switch statement, where if I have a specific condition is met -- a specific output will occur... (in functions... "an action").
Am I correct in this understanding, in trying to understand why / where one needs to use parameters & / or return values types with Functions? Or are there other practical reasons? If so can you provide an example?
Many thanks in advance!!!!
If you don't use parameters, you're tied to use what's visible in your scope.
if your function is inside a ViewController, all properties inside that VC, also global scope variables (horrible)
if your function is in global scope, you can only use global scope symbols (horrible, again)
You really do want to pass in things using parameters. This way you can:
auto check types (compiles is doing for you)
check for optionality
check value ranges
test your functions using Unit Tests. if you use global symbols, you're tied to that symbols, can't change them
less maintenance: changes outside your function doesn't affect you
Also, having a clear return type helps other developers and your future-self to understand what's returning from that function: a tuple? An optional array? A number? Also, having defined output types helps you with testing your functions.
Using only global variables & procedures (chunks of code to process those global vars) could work on a small scale. That's the old approach use with languages like FORTRAN, BASIC, COBOL... The moment your project grows, you need to isolate one part of your code from the other. For that:
use functions & a functional approach
use OOP
Let's imagine a sum function
func sum(a: Int, b:Int) -> Int {
return a + b
}
What happen if we remove the parameter types
func sum(a, b) -> Int {
return a + b // what?
}
Of course this is not allowed by the compiler but let's try to imagine.
Now a and b could be anything (like a String and a UIImage). How could we write the code to sum 2 things and get an Int?
Another test, let's remove the return type
func sum(a:Int, b:Int) -> ??? {
return a + b
}
Now let's try to invoke our crazy function
let tot: Int = sum(1, b: 2)
but since sum could return any kind of value how can we put the result into an Int constant?

Swift for in loop with parentheses

I normally use the for in loop in swift without parentheses, but today I put them on just for kicks thinking they were just optional and it did not worked as expected.
This code works:
if let tasks = getAllTasksWithManagedObjectContext(appDelegate.managedObjectContext){
for task in tasks{
appDelegate.managedObjectContext.deleteObject(task)
}
}
This one does not:
if let tasks = getAllTasksWithManagedObjectContext(appDelegate.managedObjectContext){
for (task in tasks){
appDelegate.managedObjectContext.deleteObject(task)
}
}
I get this errors:
Whats going on here?
You are simply not allowed to use parentheses here.
Take a look at the Language Reference -> Statements and compare the C-style for-loop against the swift for-in
for-statement → for­ for-init­;­expression­;­expression­ ­code-block
for-statement → for­ (for-init­;­expression­;­expression­) ­code-block
vs.
for-in-statement → for ­case(opt) ­pattern ­in ­expression ­where-clause­(opt­) code-block
The first one can be used with or without parentheses - your choice as the developer.
However the later one, the one you are actually asking about does not have a version with ( and ), only the one version without them. That means that it is not allowed to use them parentheses around the "argument" of the loop.
Screenshots from the docs linked above for better readability:
vs.

Would this function be allowed in Swift (if it wouldn't crash the compiler)

I got this function, which is a minimised version of an actual use case:
func f (i:Int) -> <T> (x:T) -> T {
return { x in return x }
}
As you see I would like to compute a generic function based on some input.
But as you can see in Xcode or on swiftstub, this function crashes the compiler.
Does anybody know if Swift is supposed to support such definitions?
This no longer crashes the compiler when I try it on 1.2b3. However, it’s not valid syntax.
If you want to return a function where the type is determined up-front at the time f is called, this would do it:
func f<T>(i:Int) -> T -> T {
return { x in return x }
}
// need to tell the compiler what T actually is...
let g = f(1) as Int->Int
g(2) // returns 2
However, Swift does not support the ability to define “generic” closures, i.e. closures where the type is determined not on creation of the closure, but at the point when that closure is actually called. This would require higher-ranked polymorphism, something that isn’t currently available (though maybe in the future, who knows – would be a very nice feature to have). For now, the placeholders need to be fully determined at the call site.
Keep in mind that the "generic" nature of Swift generics is kind of a misnomer. The genericness is just a template notation; all genericness is compiled away at compile time - that is, all generics used in one part of your code are resolved (specified) by the way they are called in another part of your code.
But for that very reason, you can't return a generic function as a result of a function, because there is no way to resolve the generic at compile time.
So, while crashing the compiler is not nice (and Apple would like to know about it), your code should not compile either, and to that extent the compiler is correct to resist.

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

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.
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.
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