I'm trying to create my own custom operator !!
postfix operator !! //error
static postfix func !! (optionalValue: Optional<T>) -> T {
// realisation
}
I get error message
Expected operator name in operator declaration
in the declarations.
Only a restricted set of characters can be used for custom operators, and some operators are reserved and cannot be overloaded.
The precise rules are documented in Lexical Structure. In particular (emphasis added):
Although you can define custom operators that contain a question mark (?), they can’t consist of a single question mark character only. Additionally, although operators can contain an exclamation mark (!), postfix operators can’t begin with either a question mark or an exclamation mark.
Also
your operator is generic, so you have to declare T as the placeholder type with <T>,
the function must not be static unless defined inside a type.
Working example:
postfix operator =!!
postfix func =!! <T> (optionalValue: Optional<T>) -> T {
// realization
}
Here is an example
//Define a operator
prefix operator √
//create a function and perform the operation.
prefix func √(lhs: Double) -> Double {
return sqrt(lhs)
}
//Do operation
let someVal:Double = 25
let squareRoot = √someVal // result is 5
Related
I've done some searching and can't seem to find a solution for my below issue. I'm fairly new to swift so working through some issues. I have the below function which is just a stub containing the signature of the function and a return value just to get it to compile.
The test code is what I've been given, I did not write this and unfortunately cannot alter it.
My issues is that when I run it, it says that the test that calls this function has an "Ambiguous call to member '=='". I cannot alter the test code. Whatever the issue is must be in my function signature i'm assuming but could use some help.
Function That I am writing (That I assume contains the issue):
func contains(target: StringOrInt, compare: Character ) -> Bool {
return false
} // contains
Test that calls the function (I'm not allowed to edit this and did not write it):
func test_contains_cons_2_strings_3() {
let list1 = MyList.cons("foo", MyList.cons("bar", MyList.empty))
assertEquals(testName: "test_contains_cons_2_strings_3",
expected: true,
received: list1.contains(target: "bar", compare: ==))//Error is on this line '=='
} // test_contains_cons_2_strings_3
Error:
main.swift:807:67: error: ambiguous reference to member '=='
received: list1.contains(target: "foo", compare: ==))
Also note that "StringOrInt" is a protocol that I've defined that acts as an extension on both Int and String. This is done because the test code (Which i did not write and cannot edit) passes both strings and ints to this same variable and function.
Thanks advance for any help, I really appreciate it!
I think you want to compare two strings by passing "==" operator and return a Boolean value.If so you can use the below method,
func myList(_ compare:((String, String) -> Bool)) -> Bool {
return compare("foo","bar")
}
myList(==)
I was able to figure this out using the below. I implemented an enum of generic type and the nan extension on that enum. I then used this generic type within the contains function to represent multiple types instead of StringOrInt. Thanks everyone for the comments and the help.
enum implemented:
indirect enum my_list<A> {
case cons(A, my_list<A>)
case empty
}
I then implemented in extension for this enum "extension my_list" and placed the contains function within the extension.
contains function signature/stub:
func contains(target: A, compare:((A, A) -> Bool))
-> Bool {
return true
}// contains
In math it is common to write the amount of a number x as |x|. I would like to adopt a similar method to my code. My try on this looks like this:
prefix operator |
postfix operator |
extension Int {
lazy var absolute = false
static prefix func | (right: Int) -> Int {
assert(right.absolute, "Missed closing absolute value bar.")
right.absolute = false
if right < 0 {
return -value
}
return value
}
static postfix func | (left: Int) -> Int {
assert(!left.absolute, "Missed opening absolute value bar.")
left.absolute = true
return left
}
}
(I think this code won't compile as you cannot add stored properties in extensions as far as I know. It is only there to demonstrate my attempt. I added this functionality to my custom types.)
Despite the fact that this feels like a rather bad solution to me, another problem with this code is, that it won't throw any error, if I forget the opening bar. The assert will only break the running program whenever I call another amount function after forgetting the opening bar in the previous amount function call.
Let me know if you have a better solution!
Thanks.
Let me first say that I don't think this is a good idea. It's much more trouble than it's worth. But here goes:
prefix operator |
postfix operator |
prefix func | <T: Comparable & SignedNumeric>(f: () -> T) -> T {
return f()
}
postfix func | <T: Comparable & SignedNumeric>(n: T) -> () -> T {
return { abs(n) }
}
|42| // returns 42
|(-42)| // returns 42
The idea is that the postfix operator returns a function that is then used as the argument to the prefix operator, which then returns the end result. I originally had it the other way around (the prefix operator returning the function), but the compiler did not like that – it seems the postfix operator has a higher precedence.
The advantage of returning a function is that |42 doesn't compile (because the argument types don't match) and while 42| compiles, you will get an error as soon as you use it in a computation because of a type mismatch.
If you use this with literals, you still have to parenthesize negative numbers because Swift can't parse two consecutive prefix operators. I also haven't tested this very much, there may be other edge cases where it doesn't compile.
In the section Basic Operators, the Swift Programming Language guide states that ++ is a valid operator:
“More complex examples include the logical AND operator && (as in if
enteredDoorCode && passedRetinaScan) and the increment operator ++i,
which is a shortcut to increase the value of i by 1.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/gb/jEUH0.l
However, when attempting this in a playground;
import UIKit
let i = 0
i++
A build error shows:
swift Unary operator '++' cannot be applied to an operand of type 'Int'
Why?
Yeah, not the best-worded compiler error.
The problem is that you have declared i using let. Since integers are value types, this means i is immutable – it cannot be changed once assigned a value.
If you declare i as var i = 0 the code compiles.
You have defined i as immutable with let. Try var i = 0 instead.
Also, if you are changing the value of the variable of a value type (structures or enumerations) inside one of it's methods, you have to define that method as mutating:
mutating func modify() {
++i
}
I don't want to have to define asString.
protocol ConvertibleToString {var asString: String {get}}
extension Int: ConvertibleToString {
var asString: String {return String(self)}
}
If I understand your question correctly – no, I don't think you can't define an "implicit" conversion that detects and uses a matching init from a specific type. The only way to convert from one type to another in Swift is to explicitly call an init for the "to" type that takes the "from" type, or a function or method on the "from" type that returns the "to" type. There's no way of implementing a protocol that says "use the init for this type with other type, if one is available".
By the way, your ConvertibleToString protocol is essentially a version of Printable (with asString in place of description). So if what you want is to know if something is convertible to a string, you can just check for conformance to Printable. Though note one gotcha – String is not Printable. You can use toString(thing) to convert anything to a string, and it will use Printable where available (and do nothing to convert strings), though this does have the side-effect of giving you a default for non-printable types that you may not want depending on your need.
Note you can require convertibility from something via a protocol:
protocol ConvertibleFromInt {
init(Int)
}
extension String: ConvertibleFromInt { }
extension UInt64: ConvertibleFromInt { }
func gimmeFromInt<T: ConvertibleFromInt>(i: Int) -> T {
return T(i)
}
let s: String = gimmeFromInt(5)
let ui: UInt64 = gimmeFromInt(5)
Is there a way in Swift to assign conditional expressions similar to this
let foo = if (bar == 2) {
100
} else {
120
}
(or with a switch case).
(Don't want to have to use ternary operator for this).
This kind of assignement is good for functional style / immutability. The expressions have a return value in this case.
Note: it's a general question, this is just simplified example, imagine e.g. a switch case with a lot of values, pattern matching, etc. You can't do that with ternary operator.
Btw also note that there are languages that don't support ternary operator because if else returns a value, so it's not necessary, see e.g. Scala.
You can use a closure to initialize an immutable:
let foo: Int = {
if bar == 2 {
return 100
} else {
return 120
}
}()
The advantage of using a closure is that it's a function, so you can use any complex logic inside, implemented in a clean way and not through nested ternary operators. It can be a switch statement, it can be obtained as the return value of a function followed by some calculations, it can be a pattern matching case, it can be a combination of them all, etc.
Said in other words, it's the same as initializing with the return value of a function, but the difference is that the function is inline and not somewhere else, with readability benefits.
Just for completeness, if the variable is mutable, you can use deferred initialization:
var foo: Int
// Any statement here
if bar == 2 {
foo = 100
} else {
foo = 120
}
// Other statements here
myFunc(foo)
so you can declare a mutable variable, and initialize it anywhere in the same scope, but before using it the variable must be initialized.
Update: Since Swift 2.0, deferred initialization also works with immutables.