I'm trying to declare a custom postfix operator that calculates the factorial of a given number, is there a way to make this function recursive (number-1)!!?
postfix operator !! {}
postfix func !! (number: Double) -> Double {
if (number <= 1) { return 1.0 }
return number * (number-1)!!
}
I believe this is impossible simply because it conflicts with the ! which is used for unwrapping optionals.
From The Swift Programming Language: Keywords and Puncutation
The following tokens are reserved as punctuation and can’t be used as custom operators: (, ), {, }, [, ], ., ,, :, ;, =, #, #, & (as a prefix operator), ->, `, ?, and ! (as a postfix operator).
However, in my opinion, if this is the case then it's a bug that postfix operator !! {} is valid. I'd recommend filing a bug.
You could get around this by using ‼ for example (Double exclamation mark; U+203C).
It's doable, but not if you use !!- it interprets it as two implicit optional deferences. Some other symbol will work - e.g:
postfix operator £ {}
postfix func £(number : Double) -> Double {
if number<=1 {
return 1.0
}
return number * (number-1)£
}
We need to specify postfix operator on file level:
import UIKit
postfix operator !
struct A {
var a = 5
var b = 10
}
extension A {
static postfix func !(m: A) -> A {
return A(a: -m.a, b: -m.b)
}
}
var obj1 = A(a:45, b: 46)
var obj4 = obj1!
Now, obj4 values will be -45, -46
Related
I tried to overload the + operator on the String class to be able to add an int to a String. 'A'+1 should produce 'B'. But it does not work in dartpad. How can I make it work?
extension StringExt on String {
String operator +(int i) {
return String.fromCharCode(this.codeUnitAt(0) + i);
}
}
void main() {
String s = 'A';
print('A' + 1);
}
You cannot add an extension method named + on String since String already has an operator named +.
Dart can only have one member with each name on each class (no member overloading), and extension members have lower priority than existing instance members.
You can actually call the extension +, but you need to explicitly invoke the extension to avoid String.operator+ taking precedence:
print(StringExt('A') + 1);
That removes most of the advantage of having a short operator.
As mentioned, you can use a different name:
extension CharCodeInc on String {
String operator /(int i) => String.fromCharCode(codeUnitAt(0) + i);
}
...
print("A"/2); // prints "C"
Too bad all the good names are taken (at least + and * on strings).
I have a Swift application.
I'm getting the error Expected expression after '?' in ternary expression from Xcode compiler
in
private func getContentPre(highlight: Highlight) -> String!
{
highlight.contentPre.count == 0 ? return ">" : return highlight.contentPre
}
Apple docs says:
why isn't it possible to return in ternary expression like using if statement?
You should re-write your function like this. This will evaluate the count of the contentPre variable and return the appropriate response.
private func getContentPre(highlight: Highlight) -> String! {
return highlight.contentPre.count == 0 ? ">" : highlight.contentPre
}
However as it would appear that contentPre would be a String you should use .isEmpty as it is more performant that checking the length of a String
private func getContentPre(highlight: Highlight) -> String! {
return highlight.contentPre.isEmpty ? ">" : highlight.contentPre
}
return does not return anything - I mean, to the function what calls it. Ternary operator's parameters must be expressions.
In Swift 3, I have written a custom operator prefix operator § which I use in a method taking a String as value returning a LocalizedString struct (holding key and value).
public prefix func §(key: String) -> LocalizedString {
return LocalizedString(key: key)
}
public struct LocalizedString {
public var key: String
public var value: String
public init(key: String) {
let translated = translate(using: key) // assume we have this
self.key = key
self.value = translated ?? "!!\(key)!!"
}
}
(Yes I know about the awesome L10n enum in SwiftGen, but we are downloading our strings from our backend, and this question is more about how to work with custom operators)
But what if we wanna get the translated value from the result of the § operator (i.e. the property value from the resulting LocalizedString)
let translation = §"MyKey".value // Compile error "Value of type 'String' has no member 'value'"
We can of course easily fix this compile error by wraping it in parenthesis (§"MyKey").value. But if do not want to do that. Is it possible to set precedence for custom operators in relationship to the 'dot' literal?
Yes I know that only infix operators may declare precedence, but it would make sense to somehow work with precedence in order to achieve what I want:
precedencegroup Localization { higherThan: DotPrecedence } // There is no such group as "Dot"
prefix operator §: Localization
To mark that the Swift compiler first should evaluate §"MyKey" and understand that is not a string, but in fact an LocalizedString (struct).
Feels unlikely that this would be impossible? What am I missing?
The . is not an operator like all the other ones defined in the standard library, it is provided by the compiler instead. The grammar for it are Explicit Member Expressions.
Having a higher precedence than the . is nothing the compiler should enable you to do, as it's such a fundamental use case. Imagine what you could do if the compiler enabled such a thing:
-"Test".characters.count
If you could have a higher precedence than ., the compiler has to check all possibilities:
(-"Test").characters.count // func -(s: String) -> String
(-("Test".characters)).count // func -(s: String.CharacterView) -> String.CharacterView
-("Test".characters.count) // func -(s: Int) -> Int
Which would
Potentially increase the compile time a lot
Be ambiguous
Possibly change behaviour of existing code upon adding overloads
What I suggest you to do is abandon the idea with a new operator, it's only going to be adding more cognitive load by squashing some specific behaviour into a single obscure character. This is how I'd do it:
extension String {
var translatedString : String {
return translate(using: self)
}
}
"MyKey".localizedString
Or if you want to use your LocalizedString:
extension String {
var localized : LocalizedString {
return LocalizedString(key: self)
}
}
"MyKey".localized.value
These versions are much more comprehensive.
I have the next code:
protocol Flyable {
var airspeedVelocity: Double { get }
}
func topSpeed<T: CollectionType where T.Generator.Element == Flyable>(collection: T) -> Double {
return collection.map { $0.airspeedVelocity }.reduce(0) { max($0, $1) }
}
I understood, by reading the Swift Documentation that:
You write a where clause by placing the where keyword immediately after the list of type parameters, followed by constraints for associated types or equality relationships between types and associated types.
This is the example given on the docs:
func allItemsMatch<C1: Container, C2: Container where
C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, _ anotherContainer: C2) -> Bool {
// code
}
Note that when expressing that the associated type ItemType of the C1 type must conform to Equatable protocol you use : and not ==, why is that not the case in my example, where I have to use == to state that the Element associated type of T.Generator must conform with Flyable?
When changing == with : the compiler complains with this:
error: cannot invoke 'topSpeed' with an argument list of type '([Flyable])' note: expected an argument list of type '(T)'
You can achieve this without using Generics.
protocol Flyable {
var airspeedVelocity: Double { get }
}
func topSpeed(collection: [Flyable]) -> Double {
return collection.map { $0.airspeedVelocity }.reduce(0) { max($0, $1) }
}
class Airplane: Flyable {
var airspeedVelocity: Double = 10
}
class Rocket: Flyable {
var airspeedVelocity: Double = 50
}
topSpeed([Airplane(),Rocket()]) //50
I've found the reason here. The where clause has the next grammar:
conformance-requirement → type-identifier:type-identifier
same-type-requirement → type-identifier==type
So, when you want to state that your type parameter conforms to certain protocol you use :. BUT, when you want your type to be exactly of a certain type, you use ==. In my example, I wanted to take as a parameter a collection of Flyable. So, when trying to use : the compiler complained because Flyable doesn't conform to Flyable. Flyable IS Flyable, thus I must use == (or do something like what #Rahul Katariya answered)
Apparently Xcode doesn't let me modify the UI (iOS) from a background thread. I have to type:
let res = somethingReturningaString()
dispatch_async(dispatch_get_main_queue(), {
self.txtError.text = res!
})
My idea was: 'hey, let's simplify my life and define a custom operator, so I can type something like:'
prefix operator ~> {}
prefix func ~> (closure: ()-> ()) {
dispatch_async(dispatch_get_main_queue(), closure)
}
//usage example
~> {self.txtError.text = res!}
Apparently the operator of type '()' cannot be applied to '()->()'
Does anybody know how to declare this to get this working?
The swift compiler got a little confused there. You must not ever separate a unary operator from its operand, meaning there must not be a whitespace in between.
Consider the following example code
let k = 12
~> {
self.txtError.text = res!
}
Swift now expects ~> to be a binary operand because there is a whitespace.
binary operator '~>' cannot be applied to operands of type 'Int' and '() -> ()'
If you insert a ; after the first line:
let k = 12;
~> {
self.txtError.text = res!
}
You receive something a little bit more helpful:
Unary operator cannot be separated from its operand
Which simply means that there must in fact be no whitespace.
Fix
Remove the whitespace:
~>{ self.txtError.text = res! }