I have a functionBuilder
#_functionBuilder
struct MyBuilder {
static func buildBlock(_ numbers: Int...) -> Int {
var result = 0
for number in numbers {
result += number * 2
}
return result
}
}
Function
func myFunc(#MyBuilder builder: () -> Int) -> Int {
builder()
}
use
let a = myFunc {
10
20
}
print(a) // print 60 is work!
but
let b = myFunc {
10
}
print(b) // print 10?
Why is b not 20?
I try add other buildBlock
static func buildBlock(number: Int) -> Int {
return number * 2
}
But not working :(
Any idea?
Any idea?
What is happening in the failing case is that { 10 } is being treated as a closure of type () -> Int directly and the compiler doesn't appear to consider the function builder at all. The code that is produced is simply a function which returns 10.
This appears to a "feature" where the recognition of { 10 } as a simple closure overrides its possible recognition as a use of the function builder. This may just be a compiler issue or worse it might be a language definition problem...
Please head to feedbackassistant.apple.com and file a report.
The accepted answer is correct, it is just passing the value and ignoring the builder.
But it's a bug, not a feature.
It's fixed on Swift 5.3, which is only available on Xcode 12 (currently in beta).
Related
In The Swift Programming Language, it says:
Functions can also take a variable number of arguments, collecting them into an array.
func sumOf(numbers: Int...) -> Int {
...
}
When I call such a function with a comma-separated list of numbers (`sumOf(1, 2, 3, 4), they are made available as an array inside the function.
Question: what if I already have an array of numbers that I want to pass to this function?
let numbers = [1, 2, 3, 4]
sumOf(numbers)
This fails with a compiler error, “Could not find an overload for '__conversion' that accepts the supplied arguments”. Is there a way to turn an existing array into a list of elements that I can pass to a variadic function?
Splatting is not in the language yet, as confirmed by the devs. Workaround for now is to use an overload or wait if you cannot add overloads.
Here's a work around that I found. I know it's not exactly what you want, but it seems to be working.
Step 1: Declare the function you'd like with an array instead of variadic arguments:
func sumOf(numbers: [Int]) -> Int {
var total = 0
for i in numbers {
total += i
}
return total
}
Step 2: Call this from within your variadic function:
func sumOf(numbers: Int...) -> Int {
return sumOf(numbers)
}
Step 3: Call Either Way:
var variadicSum = sumOf(1, 2, 3, 4, 5)
var arraySum = sumOf([1, 2, 3, 4, 5])
It seems strange, but it is working in my tests. Let me know if this causes unforeseen problems for anyone. Swift seems to be able to separate the difference between the two calls with the same function name.
Also, with this method if Apple updates the language as #manojid's answer suggests, you'll only need to update these functions. Otherwise, you'll have to go through and do a lot of renaming.
You can cast the function:
typealias Function = [Int] -> Int
let sumOfArray = unsafeBitCast(sumOf, Function.self)
sumOfArray([1, 2, 3])
You can use a helper function as such:
func sumOf (numbers : [Int]) -> Int { return numbers.reduce(0, combine: +) }
func sumOf (numbers : Int...) -> Int { return sumOf (numbers) }
I did this (Wrapper + Identity Mapping):
func addBarButtonItems(types: REWEBarButtonItemType...) {
addBarButtonItems(types: types.map { $0 })
}
func addBarButtonItems(types: [REWEBarButtonItemType]) {
// actual implementation
}
I know this response does not answer your exact question, but I feel its worth noting. I too was starting to play with Swift and immediately ran into a similar question. Manojlds answer is better for your question, I agree, but again, another workaround I came up with. I do happen to like Logan's better too.
In my case I just wanted to pass an array:
func sumOf(numbers: Array<Int>) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
var someNums = [8,7,2,9,12]
sumOf(someNums)
sumOf([10, 15, 20])
Just wanted to share, in case anyone else was thinking like me. Most of the time I would prefer pass the array like this, but I don't think the "Swiftly" yet. :)
Swift 5
This is an approach with #dynamicCallable feature that allows to avoid overloading or unsafeBitCast but you should make a specific struct to call:
#dynamicCallable
struct SumOf {
func dynamicallyCall(withArguments args: [Int]) -> Int {
return args.reduce(0, +)
}
}
let sum = SumOf()
// Use a dynamic method call.
sum(1, 2, 3) // 6
// Call the underlying method directly.
sum.dynamicallyCall(withArguments: [1, 2, 3]) // 6
I'm not talking about pointers to C functions, but to a method within a Swift type.
struct Test: GeneratorType {
var methodPointer: mutating () -> Bool? // Non-working guess
var which: Bool
init() {
which = false
methodPointer = which ? &testMethod1 : &testMethod2 // Also non-working guess
}
//...
}
The compiler says "mutating" isn't legal as part of a function declaration. (Actually, it just suggests a semi-colon there.) And for the pointer initialization (after I remove mutating), the compiler thinks I'm trying to call the functions and use their results instead. I want to use the methods as objects in-and-of themselves here, not as a function call. Later on I want to use the pointed-to method within next; without figuring this out, I'll have to resort to an enumeration flag and manually choosing which method to call within next.
I hope there's some part of closure mechanics that allows this. Maybe something like this page, which describes functions returning functions. But none of the examples I've seen mention mutating methods.
See if this helps you.
class Something {
var f: ( () -> Int )?
let f1 = { () -> Int in /* do some action here */ return 1}
let f2 = { () -> Int in /* do some action here */ return 2}
func ff(which: Bool) {
f = which ? f1 : f2
}
func act() {
if let f = f {
f()
}
}
}
Here is how I do it -
class FcnArgs { //#goal pass a fcn as arg
class func demo() {
let fPtr = funcToPointTo; //#type '((Int)->String)'
print(fPtr(4));
}
class func funcToPointTo(_ i : Int) -> String {
print("I Was passed \(i)");
return "I was returned";
}
}
FcnArgs.demo() output:
I Was passed 4
I was returned
I have a code that I need to run exactly n times in Swift. What is the shortest possible syntax for that?
I am currently using the for loop but it is a lot of typing.
for i in 0..<n { /* do something */ }
Is there a shorter/nicer way for running same code n times in Swift?
Speaking of syntax, you might define your own shortest syntax:
extension Int {
func times(_ f: () -> ()) {
if self > 0 {
for _ in 0..<self {
f()
}
}
}
func times(_ f: #autoclosure () -> ()) {
if self > 0 {
for _ in 0..<self {
f()
}
}
}
}
var s = "a"
3.times {
s.append(Character("b"))
}
s // "abbb"
var d = 3.0
5.times(d += 1.0)
d // 8.0
Sticking with a for loop - you could extend Int to conform to SequenceType to be able to write:
for i in 5 { /* Repeated five times */ }
To make Int conform to SequenceType you'll could do the following:
extension Int : SequenceType {
public func generate() -> RangeGenerator<Int> {
return (0..<self).generate()
}
}
You have several ways of doing that:
Using for loops:
for i in 1...n { `/*code*/` }
for i = 0 ; i < n ; i++ { `/*code*/` }
for i in n { `/*code*/` }
using while loops:
var i = 0
while (i < n) {
`/*code*/`
` i++`
}
var i = 0
repeat {
` /*code*/`
`i++`
} while(i <= n)
for _ in 1...5 {
//action will be taken 5 times.
}
you could use functional programming on a range instead of a loop, for shorter and "nicer" syntax for example
(0..<n).forEach{print("Index: \($0)")}
Other answers mention defining your own syntax for that. So - that can be fine for a tiny personal project, or as a learning experience. But defining your own syntax for something so trivial and basic in a large project would be maintenance and readability hell.
You could do something like this:
10⨉{ print("loop") }
Using a custom operator and an extension on Int:
infix operator ⨉ // multiplication sign, not lowercase 'x'
extension Int {
static func ⨉( count:Int, block: () ->Void ) {
(0..<count).forEach { _ in block() }
}
}
ABakerSmith's answer updated for Swift 4:
extension Int: Sequence {
public func makeIterator() -> CountableRange<Int>.Iterator {
return (0..<self).makeIterator()
}
}
Use:
for i in 5 {
//Performed 5 times
}
Shorter and (I think) clearer:
for i in 1...n { } // note: this will fail if n < 1
or
for i in n { }
In Swift, what you have is the shortest syntax for performing a loop operation.
Swift provides two kinds of loop that perform a set of statements a
certain number of times:
The for-in loop performs a set of statements for each item in a
sequence.
The for loop performs a set of statements until a specific
condition is met.
If you want to run it infinite times, well try using a while.
There are a lot of answers here, highlighting just how creative you can be, with Swift.
I needed an array so I did this
extension Int {
func of<T>(iteration: (Int) -> T) -> [T] {
var collection = [T]()
for i in 0..<self {
collection.append(iteration(i))
}
return collection
}
}
fun strings() -> [String] {
return 4.of { "\($0) teletubby" }
}
for-loops are a common way to repeat code. Here is an example of using a for-loop to hide six outlets, versus writing the same code for six outlets. Plus if you make another outlet all you have to do is add it to the array.
let array = [outLet0, outlet1, outlet2, outLet3, outLet4, outLet5]
for outlet in array {
outlet.hidden = true
}
Versus writing it like this:
outlet0.hidden = true
outlet1.hidden = true
outlet2.hidden = true
outlet3.hidden = true
outlet4.hidden = true
outlet5.hidden = true
ONLY 5 CHARACTERS (not including n or code)
r(){}
If you're just testing things and need a REALLY short line, try this. Emphasis on using this for testing, not in production, because no one will know what is going on without documentation.
define this somewhere globally
func r(_ n : UInt, _ c: #escaping () -> Void) { for _ in 0..<n { c() } }
call this when you want to run it
r(5) { /*code*/ }
Swift is so awesome, just write your own function or extension and you got it ;) 100 of options there, everyone can do it its own way just look at those answers here.
Or better, write it as you already do, as is common when apps are build in team, as everyone would do it differently anyway and all projects need those extension to be written again or own libs to have and maintain just for stupid thing, that you can write just by some standard way, as you already did with your for loop.
The only loop shorter than that is an infinite while loop:
while (true) {
}
But you would still have to increase a counter and check it in the loop to break the loop, and in the end it wouldn't be shorter.
extension Array {
func sum() -> Int {
var sum = 0
for num in self {
sum += num
}
return sum
}
}
[1,2,3].sum()
This code shows what I would like to do. Though i get an error on the this line: sum += num. The error i get is: Could not find an overload for '+=' that accepts the supplied arguments.
I assume the error has something to do with the fact that Array can contain lots of different types, not just Int, so it's bugging out. But how to fix?
There isn't currently a way to extend only a particular type of Array (Array<Int> in this case). That'd be a great request to file at bugreport.apple.com
In the meantime you can do this (not in an extension):
func sum(ints:Int[]) -> Int {
return ints.reduce(0, +)
}
All that's needed is an explicit cast to Int:
extension Array {
func Sum() -> Int {
var sum = 0
for num in self {
sum += (num as Int)
}
return sum
}
}
println([1,2,3].Sum()) //6
In The Swift Programming Language, it says:
Functions can also take a variable number of arguments, collecting them into an array.
func sumOf(numbers: Int...) -> Int {
...
}
When I call such a function with a comma-separated list of numbers (`sumOf(1, 2, 3, 4), they are made available as an array inside the function.
Question: what if I already have an array of numbers that I want to pass to this function?
let numbers = [1, 2, 3, 4]
sumOf(numbers)
This fails with a compiler error, “Could not find an overload for '__conversion' that accepts the supplied arguments”. Is there a way to turn an existing array into a list of elements that I can pass to a variadic function?
Splatting is not in the language yet, as confirmed by the devs. Workaround for now is to use an overload or wait if you cannot add overloads.
Here's a work around that I found. I know it's not exactly what you want, but it seems to be working.
Step 1: Declare the function you'd like with an array instead of variadic arguments:
func sumOf(numbers: [Int]) -> Int {
var total = 0
for i in numbers {
total += i
}
return total
}
Step 2: Call this from within your variadic function:
func sumOf(numbers: Int...) -> Int {
return sumOf(numbers)
}
Step 3: Call Either Way:
var variadicSum = sumOf(1, 2, 3, 4, 5)
var arraySum = sumOf([1, 2, 3, 4, 5])
It seems strange, but it is working in my tests. Let me know if this causes unforeseen problems for anyone. Swift seems to be able to separate the difference between the two calls with the same function name.
Also, with this method if Apple updates the language as #manojid's answer suggests, you'll only need to update these functions. Otherwise, you'll have to go through and do a lot of renaming.
You can cast the function:
typealias Function = [Int] -> Int
let sumOfArray = unsafeBitCast(sumOf, Function.self)
sumOfArray([1, 2, 3])
You can use a helper function as such:
func sumOf (numbers : [Int]) -> Int { return numbers.reduce(0, combine: +) }
func sumOf (numbers : Int...) -> Int { return sumOf (numbers) }
I did this (Wrapper + Identity Mapping):
func addBarButtonItems(types: REWEBarButtonItemType...) {
addBarButtonItems(types: types.map { $0 })
}
func addBarButtonItems(types: [REWEBarButtonItemType]) {
// actual implementation
}
I know this response does not answer your exact question, but I feel its worth noting. I too was starting to play with Swift and immediately ran into a similar question. Manojlds answer is better for your question, I agree, but again, another workaround I came up with. I do happen to like Logan's better too.
In my case I just wanted to pass an array:
func sumOf(numbers: Array<Int>) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
var someNums = [8,7,2,9,12]
sumOf(someNums)
sumOf([10, 15, 20])
Just wanted to share, in case anyone else was thinking like me. Most of the time I would prefer pass the array like this, but I don't think the "Swiftly" yet. :)
Swift 5
This is an approach with #dynamicCallable feature that allows to avoid overloading or unsafeBitCast but you should make a specific struct to call:
#dynamicCallable
struct SumOf {
func dynamicallyCall(withArguments args: [Int]) -> Int {
return args.reduce(0, +)
}
}
let sum = SumOf()
// Use a dynamic method call.
sum(1, 2, 3) // 6
// Call the underlying method directly.
sum.dynamicallyCall(withArguments: [1, 2, 3]) // 6