Providing default instance arguments for (recursive) extension in Swift - swift

I was having fun while practicing a Kata.
I wanted to implement one of the functions in my solution as an extension of Int, because I liked the idea of having pretty syntax. The function, in itself, looks like this:
func decomposed(_ n: Int) -> [Int] {
if n > 10 {
return n.decomposed(n / 10) + [n % 10]
} else {
return [n]
}
}
Now, I've tried to implement it as an extension. Due to the fact that I would like to use it like 420.decomposed(), I figured that I would need the instance as the default argument. I proceeded with:
extension Int {
func decomposed(_ n: Int = self) -> [Int] {
if n > 10 {
return n.decomposed(n / 10) + [n % 10]
} else {
return [n]
}
}
}
This is the part, however, in which it gets trickier. I'm being told by the compiler that error: cannot find 'self' in scope.
Having read about the methods in the docs, I've resorted to using Int? default argument. Now, the extension is implemented as:
extension Int {
func decomposed(_ n: Int? = nil) -> [Int] {
var _n = n ?? self
if _n > 10 {
return _n.decomposed(_n / 10) + [_n % 10]
} else {
return [_n]
}
}
}
I don't like the look of the _n, though.
I would love to use self as the default argument. Is that possible? Or are we stuck with hackity hacks until the judgement day?

Wrote a quick implementation to highlight the usage of extensions:
import Foundation
func main() {
print(2.test()) // prints 2
print(12.test()) // prints 3
print(42.test()) // prints 6
}
extension Int {
func test() -> Int {
if self <= 10 {
return self
}
return (self % 10) + (self/10).test();
}
}
main()
You don't need to pass self as an argument, since that will not work. By default, self will be available for use inside the extension methods (since that follows the object oriented paradigm).

You need to remove n as a parameter, replace every use of n in the function with self (since that's what's being operated on), and convert the function syntax to the method syntax in the recursion:
extension Int {
func decomposed() -> [Int] {
if self > 10 {
return (self / 10).decomposed() + [self % 10]
} else {
return [self]
}
}
}

In your function decomposed, you aren't using self and n anywhere together you can either make your decomposed method accept no parameter and use self from the function:
extension Int {
func decomposed() -> [Int] {
if self > 10 {
return (self / 10).decomposed() + [self % 10]
} else {
return [self]
}
}
}
or if you plan to pass any parameter then you can just define a top level function instead of using extension:
func intDecomposed(_ n: Int) -> [Int] {
if n > 10 {
return n.decomposed(n / 10) + [n % 10]
} else {
return [n]
}
}
You can use the above method inside the decomposed extension method providing self as parameter:
extension Int {
func decomposed() -> [Int] {
return intDecomposed(self)
}
}

Related

swift recursion: function vs closure

This compiles:
let badger = get_closure()
func get_closure() -> (Int) -> Void {
return { (x: Int) -> Void in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
}
badger(1)
This doesn't with circular reference errors:
let badger = get_closure()
let get_closure = { () -> (Int) -> Void in
return { (x: Int) -> Void in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
}
badger(1)
Why? I thought the func syntax is just sugar for the second more explicit syntax.
The fact that the first one works is a long-standing bug/quirk in the compiler, not an intended feature. It's based on undefined behavior that the compiler has trouble detecting. You can demonstrate that it's a quirk of top-level declarations by wrapping your working code in a function and see that it fails very similarly to your second example:
func f() {
let badger = get_closure()
func get_closure() -> (Int) -> Void { // ERROR: Closure captures 'badger' before it is declared
return { (x: Int) -> Void in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
}
badger(1)
}
The key feature of top-level, global declarations like badger is that they're lazily evaluated, so the assignment actually happens after the declaration of the function. In your second example, both variables are lazy, so the order comes back in. But it's dangerous to rely on this fact, as discussed in the linked forum posts.
When exploring subtle Swift behavior, I always recommend building a commandline app and placing your test code inside of a function to eliminate the weirdness of both Playgrounds and top-level executable code. (Playgrounds isn't relevant in this case, but it comes up a lot.)
It's hard to understand where this approach should be used, but if you really want to, then try this:
let get_closure: (Int) -> Void = { x in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
let badger = get_closure
badger(1)
The order of initialization of dependent variables is usually important. If you assign a value after the closure, there will be no error:
let get_closure = { () -> (Int) -> Void in
return { (x: Int) -> Void in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
}
let badger = get_closure()
badger(1)

Cannot convert type of Int to expected value [MyCustomType]

Xcode 8.3.3 is giving me this Swift 3 error on this line
values2[index] = nextValue(currentValue)
Cannot convert value of type 'Int' to expected argument type 'Card'
Here's my code:
//
// Card.swift
// match
//
// Created by quantum on 05/09/2017.
// Copyright © 2017 Quantum Productions. All rights reserved.
//
import UIKit
class Card: NSObject {
var quantity = 0
var fill = 0
var shape = 0
var color = 0
override var description : String {
return "Q" + String(quantity) + "/F" + String(fill) + "/S" + String(shape) + "/C" + String(color)
}
override init() {
super.init()
}
static func properties() -> [String] {
return ["quantity", "fill", "shape", "color"]
}
static func isMatch(cards: [Card]) -> Bool {
for property in self.properties() {
var sum = 0
for card in cards {
sum = sum + (card.value(forKey: property) as! Int)
}
if !([3, 6, 9, 7].contains(sum)) {
return false
}
}
return true
}
static func deck(_ values: [Int], _ index: Int, _ max: Int, _ acc: [Card]) -> [Card]{
let currentValue = values[index]
var values2 = values
if currentValue >= max {
if index == 0 {
return acc
}
values2[index] = 0
values2[index-1] = values2[index-1] + 1
return deck(values, index - 1, max, acc)
} else {
var acc2 = acc
let card = Card()
for (index, element) in self.properties().enumerated() {
card.setValue(values[index], forKey: element)
}
acc2.append(Card())
values2[index] = nextValue(Card())
return deck(values2, index, max, acc2)
}
}
func nextValue(_ v: Int) -> Int {
if (v == 0) {
return 1
} else if (v == 1) {
return 2
}
return 4
}
static func deck() -> [Card] {
return deck([1,1,1,1], 4, 3, [Card]())
}
}
this is inside of my Card class.
Strangely, if I try (this is wrong, I'm testing the compiler error)
values2[index] = nextValue(Card())
I get the error Cannot assign the value of type (Int) -> Int to type 'Int'.
Swift thinks my Card is an Int? I'm confused as to what's happening.
I expected to get the call nextvalue with the variable currentvalue, which should be an Int.
It's a bad error message from the compiler.
Your problem is that deck is declared static, but you're trying to call nextValue which is not declared static. This means that nextValue implicitly takes a hidden argument, self, but deck isn't providing it.
If you add static to the func nextValue declaration, it will work like you expect. (You'll get an error on the line referring to self.properties instead, but you'll be closer.)
To make this work properly, you probably want all these functions to be non-static instead. Just think about how this code gets called initially (i.e. how you get your first instance of Card).
A static method cannot call an instance method: the idea makes no sense, as there is no instance. Thus your reference to nextValue is impossible. That is why the line is problematic. How can a static method deck call an instance method nextValue?

Multiple index types in Swift

In Swift (a language I'm still fairly new to), I'm trying to define a class that allows indexing using either an Int or Range<Int>. For example:
var m = Matrix(rows: 10, cols: 10)
var v = m[1, 0..<10]
The two ways I can think of allowing this issue is to either adding an extension to the Range class:
extension Range {
init(_ intValue:Element) {
self.init(start: intValue, end: intValue.successor())
}
}
or to create an enum that allows for either type:
enum IndexType {
case value(Int)
case range(Range<Int>)
init(_ v:Int) {
self = .value(v)
}
init(_ r:Range<Int>) {
self = .range(r)
}
}
However, neither solution works as intended, as I still need to specify the type manually. For example, given the function:
func slice(indices:IndexType...) -> [Double] {
// ...
}
I can't then just do:
slice(1, 3...4, 5)
but instead have to do:
slice(IndexType(1), IndexType(3...4), 5)
Is there a way to accomplish this in Swift? I'm used to c++, which would do type inference automatically, but the same doesn't appear to work with Swift.
One similar question I found was:
Swift Arrays of Multiple Types
However, I really would like to avoid the use of Any as I know the two types it should be.
protocol MatrixIndex {
var Matrix_range: Range<Int> { get }
}
extension Int : MatrixIndex {
var Matrix_range: Range<Int> {
get {
return Range<Int>(start: self, end: self+1)
}
}
}
extension Range : MatrixIndex {
var Matrix_range: Range<Int> {
get {
return Range<Int>(start: self.startIndex as! Int, end: self.endIndex as! Int)
}
}
}
class Matrix {
subscript(row: MatrixIndex, column: MatrixIndex) -> () {
get {
print("getting \(row.Matrix_range) \(column.Matrix_range)")
}
set(newValue) {
print("setting \(row.Matrix_range) \(column.Matrix_range)")
}
}
}

Swift SequenceType not working

I'm trying to implement a SequenceType / GeneratorType example and getting an error that doesn't quite make sense.
Here's the code:
// Here's my GeneratorType - it creates a random-number Generator:
struct RandomNumberGenerator:GeneratorType {
typealias Element = Int
mutating func next() -> Element? {
return Int(arc4random_uniform(100))
}
}
When I call this (in Playgrounds) it works perfectly well:
var randyNum = RandomNumberGenerator()
randyNum.next() // this shows a valid random number in the Gutter
// And calling it from within a println also works:
println("randyNum = \(randyNum.next()!)")
So far so so good.
Next is the SequenceType:
struct RandomNumbersSequence:SequenceType {
typealias Generator = RandomNumberGenerator
var numberOfRandomNumbers:Int
init(maxNum:Int) {
numberOfRandomNumbers = maxNum
}
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
}
}
That's what's generating an error: 'Type RandomNumberSequence' does not conform to protocol 'SequenceType'. (Xcode is showing this error right on that first line of the declaration struct RandomNumbersSequence:SequenceType statement.)
I actually think the logic of my for loop may be wrong - meaning I won't get the results I actually want - but regardless, in terms of satisfying what the SequenceType Protocol is requiring, I think I got that much right.
So what's causing this error?
This isn’t quite how generators work. Assuming you want to serve up a set number of random numbers, you have the right idea about taking a maximum as a parameter, but you need to store that in the generator, as well, plus some state for where it is up to.
The idea with a generator is that it stores its state, and every time you call next() you return the next element. So if you want to generate a run of up to n numbers, you could do something like the following:
struct RandomNumberGenerator: GeneratorType {
let n: Int
var i = 0
init(count: Int) { self.n = count }
mutating func next() -> Int? {
if i++ < n {
return Int(arc4random_uniform(100))
}
else {
return nil
}
}
}
Note, you don’t need a for loop here. Just each time next() is called, i is incremented, until it reaches the max, then the generator starts returning nil.
The purpose of SequenceType is to serve up fresh generators:
struct RandomNumberSequence: SequenceType {
let n: Int
init(count: Int) { self.n = count }
func generate() -> RandomNumberGenerator {
return RandomNumberGenerator(count: n)
}
}
Given this, you can now use it to generate a sequence of a fixed number of random integers:
let seq = RandomNumberSequence(count: 3)
for x in seq {
// loops 3 times with x being a new random number each time
}
// every time you use seq, you get a new set of 3 numbers
",".join(map(seq,toString)) // prints 3 comma-separated random nums
// but when you create a generator, it gets “used up”
var gen = seq.generate()
println(gen.next()) // prints a random number
println(gen.next()) // prints another random number
println(gen.next()) // prints the third
println(gen.next()) // prints nil
println(gen.next()) // and will keep printing nil
gen = seq.generate()
println(gen.next()) // will print the first of a new set of 3 numbers
Creating these stateful generators is quite a common problem, so the standard library has a helper struct, GeneratorOf, that allows to you skip defining them. It takes a closure that each time it is called should return the next value to generate:
struct RandomNumbersSequence: SequenceType {
let maxNum: Int
init(maxNum: Int) { self.maxNum = maxNum }
func generate() -> GeneratorOf<Int> {
// counter to track how many have been generated
var n = 0
return GeneratorOf {
// the closure “captures” n
if n++ < self.maxNum {
return Int(arc4random_uniform(100))
}
else {
return nil
}
}
}
}
The error message you're seeing:
'Type RandomNumberSequence' does not conform to protocol 'SequenceType'
Always means that your class or struct is missing something that the protocol declares as required.
In this case, we're missing the generate() -> Generator method. "But, it's right there!" you say? Well, it is, but it's not compiling.
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
}
The problem is, what if you initialize your struct with numberOfRandomNumbers less than or equal to 0? Your loop executes zero times and generate can't return anything.
I'm not sure exactly what logic you're trying to to do in this loop, but we can fix the compilation errors by simply a adding a return statement that will return a Generator:
func generate() -> Generator {
for i in 1...numberOfRandomNumbers {
var randNum = Generator()
randNum.next()
return randNum
}
return Generator()
}
This won't do what you're trying to accomplish. This isn't how generators are supposed to work. But it will fix the generate() -> Generator method and allow your struct to now conform to the protocol.
With Swift 3, you can choose one of the three RandomNumbersSequence implementations in order to solve your problem.
1. Using a struct that conforms to Sequence protocol and a struct that conforms to IteratorProtocol protocol
The following Playground code shows how to implement a RandomNumbersSequence struct that conforms to Sequence and that uses a RandomNumbersIterator struct that conforms to IteratorProtocol protocol:
import Darwin // required for arc4random_uniform
struct RandomNumbersIterator: IteratorProtocol {
let maxNum: Int
var n = 0
init(maxNum: Int) {
self.maxNum = maxNum
}
mutating func next() -> Int? {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
}
struct RandomNumbersSequence: Sequence {
let maxNum: Int
init(maxNum: Int) {
self.maxNum = maxNum
}
func makeIterator() -> RandomNumbersIterator {
return RandomNumbersIterator(maxNum: maxNum)
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
let randomSequence = RandomNumbersSequence(maxNum: 3)
var randomGenerator = randomSequence.makeIterator()
randomGenerator.next() // may return: 4
randomGenerator.next() // may return: 8
randomGenerator.next() // may return: 3
randomGenerator.next() // will return: nil
2. Using a struct that conforms to Sequence and IteratorProtocol protocols
The following Playground code shows how to implement a RandomNumbersSequence struct that conforms to Sequence and IteratorProtocol protocols:
import Darwin // required for arc4random_uniform
struct RandomNumbersSequence: Sequence, IteratorProtocol {
let maxNum: Int
var n = 0
init(maxNum: Int) {
self.maxNum = maxNum
}
mutating func next() -> Int? {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
var randomSequence = RandomNumbersSequence(maxNum: 3)
randomSequence.next() // may return: 4
randomSequence.next() // may return: 8
randomSequence.next() // may return: 3
randomSequence.next() // will return: nil
3. Using AnyIterator and a struct that conforms to Sequence
As an alternative to the previous implementation, you can use AnyIterator<T> as the return type of the makeIterator method inside your Sequence protocol conforming struct. The following Playground code shows how to implement it with your RandomNumbersSequence struct:
import Darwin // required for arc4random_uniform
struct RandomNumbersSequence: Sequence {
let maxNum: Int
init(maxNum: Int) {
self.maxNum = maxNum
}
func makeIterator() -> AnyIterator<Int> {
var n = 0
let iterator: AnyIterator<Int> = AnyIterator {
n += 1
return n <= self.maxNum ? Int(arc4random_uniform(10)) : nil
}
return iterator
}
}
Usage #1:
for value in RandomNumbersSequence(maxNum: 3) {
print(value)
}
/*
may print:
5
7
3
*/
Usage #2:
let randomArray = Array(RandomNumbersSequence(maxNum: 3))
print(randomArray)
/*
may print: [7, 6, 1]
*/
Usage #3:
let randomSequence = RandomNumbersSequence(maxNum: 3)
let randomGenerator = randomSequence.makeIterator()
randomGenerator.next() // may return: 4
randomGenerator.next() // may return: 8
randomGenerator.next() // may return: 3
randomGenerator.next() // will return: nil

Swift: Function returning an Array of IntegerType

I would like to create a function that takes an NSData parameter, and, depending on what it reads from the NSData it returns an Array<Int8>, Array<Int16>, Array<Int32>, or Array<Int64>.
Basically, I need to return an array of IntegerType, with the specific subtype being determined at runtime.
I am stuck at the signature declaration of the function. (The inside would just be a simple switch, that would create the specific array type and return it).
The following very basic test does not compile
class Test {
func test(data:NSData) -> Array<IntegerType> {
return [1, 2, 3]
}
}
EDIT
It seems to be currently not possible, not because of having to return an array of a protocol type, but because the IntegerType protocol uses Self. Here is an interesting related question
IntegerType is a protocol, so the following should work:
class Test {
func test(data:NSData) -> Array<T: IntegerType> {
[1, 2, 3]
}
}
You can use enum with associated values for that:
enum IntArray {
case Int8([Swift.Int8])
case Int16([Swift.Int16])
case Int32([Swift.Int32])
case Int64([Swift.Int64])
}
class Test {
func test(data:NSData) -> IntArray {
return IntArray.Int8([1, 2, 3]);
}
}
on user side:
let obj = Test()
let array = obj.test(dat)
switch array {
case .Int8(let ary):
// here, ary is [Int8]
...
case .Int16(let ary):
// here, ary is [Int16]
...
case .Int32(let ary):
// here, ary is [Int32]
...
case .Int64(let ary):
// here, ary is [Int64]
...
}
As others have said in the comments, this won't work if you are trying to determine the function's return type at runtime. Swift generics only work at compile time, so changing the return type based off of what's in an NSData won't work.
If you can determine the return type at compile time, then you can use a generic function declaration like so:
func test<T: IntegerType>(data: NSData) -> Array<T> {
return [1, 2, 3]
}
Note: If you don't specify the type explicitly in your function somehow, then you'll need to define the variable the value returned from the function is assigned to. Like so:
var int8Array: Array<Int8> = test(NSData())
Since none of the generic based solutions are working, why don't you try returning [Any] and just check the return type as follows:-
func test(data:NSData) -> [Any]
{
var value1:Int8 = 1
var value2:Int8 = 2
return [value1,value2]
}
var x = test(NSData())
for xin in x
{
var intxin = xin as? Int8
if intxin != nil
{
println(intxin!)
}
}
The way I solved my problem was by defining the following protocol:
protocol IntegerArrayProtocol {
init(rawData: NSData!, length: Int)
func count() -> Int
subscript(index:Int) -> Int { get }
}
This deals with all the operations I need to perform on the array:
Read it from raw memory
Count how many elements it has
Access its elements by index, always returning Ints, regardless of the underlying integer
type
Then, I created a parameterized class that implements the protocol:
final class IntegerArray<T: ConvertibleToInteger>: IntegerArrayProtocol {
let arr: [T]
init(rawData: NSData!, length: Int){
//create array and allocate memory for all elements
arr = Array<T>(count: length, repeatedValue: T.zero())
// read it from the NSData source
// ....
}
func count() -> Int{
return arr.count
}
subscript(index:Int) -> Int {
get {
return arr[index].asInt()
}
}
}
The parameter types T should be able to convert themselves to Int, and should have a zero value (used when I initialize the array). For that, I created the ConvertibleToInteger protocol, which is used above to restrict the possible Ts:
protocol ConvertibleToInteger {
class func zero() -> Self
func asInt() -> Int
}
Then, I extended every type that I would like to create arrays of:
extension Int8: ConvertibleToInteger{
static func zero() -> Int8{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int16: ConvertibleToInteger{
static func zero() -> Int16{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int32: ConvertibleToInteger{
static func zero() -> Int32{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
extension Int64: ConvertibleToInteger{
static func zero() -> Int64{
return 0
}
func asInt() -> Int{
return Int(self)
}
}
Finally, to read an array from NSData, I created the following function:
func readArray(rawData: NSData, length: Int): IntegerArrayProtocol? {
qBytes = // read from NSData how many bytes each element is
switch(qBytes){
case 1:
return IntegerArray<Int8>(rawData: rawData, length: length)
case 2:
return IntegerArray<Int16>(rawData: rawData, length: length)
case 3 ... 4:
return IntegerArray<Int32>(rawData: rawData, length: length)
case 5 ... 8:
return IntegerArray<Int64>(rawData: rawData, length: length)
default:
return nil
}
}