Why doesn’t my Swift array extension work? - swift

I am trying to run this code, and this error is being triggered
Cannot invoke 'append' with an argument list of type '(Int)'
What am I doing wrong?
extension Array {
mutating func random100() {
for _ in 0 ... 99 {
self.append(Int(arc4random() % 10)) // Cannot invoke 'append' with an argument list of type '(Int)'
}
}
}

You must constraint your extension to Int types :
extension RangeReplaceableCollection where Iterator.Element == Int {
mutating func random100() {
for _ in 1...100 {
append(Int(arc4random_uniform(10)))
}
}
}
And as you cannot directly constraint Array, you must constraint the protocol where the append method is defined.
Then you can use it on any array of Int:
var myArray = [3,5,6]
myArray.random100()

What do you really want? If you want a method that gives you a hundred random Ints, you’d better create a static method on Array. Mutating any array in general does not make sense – what if it’s a list of strings?
Take a look at arc4random_uniform to avoid modulo bias. I don’t know if the bias would be apparent in this case, but it’s a good practice to use arc4random_uniform anyway.

Related

How do you modify array parameter in swift

I need to manipulate data inside a byte array using swift. The compiler will not permit the following:
var a:[UInt8] = [1,2,3,4,5]
func tt(a:[UInt8]) {
a[2]=10
}
tt(a:a)
The compiler complains:
Cannot assign through subscript: 'a' is a 'let' constant
What is the correct way to create functions that can modify large byte arrays. (They are very large)
I am aware there are Unsafe pointer options, but I am trying various types of unsafe pointer parameters and none of them seem to work or they report even more obscure compiler errors, so I thought I would ask here. i.e.
func tt(a:UnsafePointer<[UInt8]>) {
a[2]=a[3]
}
func tt(a:UnsafeMutablePointer<[UInt8]>) {
a[2]=a[3]
}
func tt(a:[UInt8]) {
a[2]=10
}
In above function, the function parameter a is a let constant, you can't change it inside the function.
You need to use inout parameter to be able to modify this.
var a: [UInt8] = [1,2,3,4,5]
func tt(a: inout [UInt8]) {
a[2] = 10
}
tt(a: &a)
Each value passed inside a function parameter is a constant, to be able to mutate it you need to sign it as inout
func tt(a: inout [UInt8]){
a[2]=10
}

How can I get ElementType of an Array for building an Extension?

I want make a custom Enumerated function, for that reason I need to know the type of value in my array, how can I read that information, here what I tried but need correction:
extension Array {
typealias EnumeratedType<T> = [(index: Int, item: T)] // T: is the type of Elements of Array!
func customEnumerated() -> EnumeratedType<ElementType> {
var enumeratedTypeArray: EnumeratedType<ElementType> = EnumeratedType()
self.sorted().forEach { item in
enumeratedTypeArray.append((index: enumeratedTypeArray.count, item: item))
}
return enumeratedTypeArray
}
}
From the documentation, we can see that Array is declared as:
struct Array<Element>
So the element type is called Element. You can declare your method like this:
extension Array where Element : Comparable {
// note that this doesn't need to be generic, because the type alias is in the scope of the array
typealias EnumeratedType = [(offset: Int, element: Element)]
func customEnumerated() -> EnumeratedType {
// you can simplify the forEach call to this
.init(sorted().enumerated())
}
}
Note that the constraint Element : Comparable is required, as that makes the parameterless overload of sorted available.
I would suggest that you declare the extension on the most general type possible, so that your method is available to as many types as possible, and return an EnumeratedSequence (same as what enumerated returns) instead. This way you don't need your own EnumeratedType type alias.
// It just so happens that the element type of a Sequence is also called "Element"
// See https://developer.apple.com/documentation/swift/sequence/2908099-element
extension Sequence where Element : Comparable {
func customEnumerated() -> EnumeratedSequence<[Element]> {
sorted().enumerated()
}
}
As you can see in the documentation, the name of Array’s sole generic type parameter is Element.

Selecting types for an Array extension

I'm trying to extend the Array.contains function to allow an optional parameter and return false when the parameter is nil. I started with this:
extension Array {
func contains(_ element: Element?) -> Bool {
if let element = element {
return self.contains(element)
} else {
return false
}
}
}
When the argument is nil, the calling code correctly finds my version of the function. However, the self.contains inside this function doesn't call the original version -- it calls itself and creates an infinite loop. Is there a way make the self.contains line call the original function?
Next, I tried replacing self.contains with a different implementation, but I couldn't think of anything that didn't require constraining the extension to Element: Equatable, like this:
extension Array where Element: Equatable {
func contains(_ element: Element?) -> Bool {
if let element = element {
return (self.firstIindex(of: element) != nil)
} else {
return false
}
}
}
However, that makes the function unavailable to element types like UIButton, Dictionary and other things I need to use it with. How does the original contains function do this for these types? (I searched and couldn't find the source code for it.)
Next, I removed the constraint and changed the method signature to disambiguate between my extension function and the original function:
extension Array {
func contains(optional element: Element?) -> Bool {
if let element = optional {
return self.contains(element)
} else {
return false
}
}
}
But when I change the method signature, a compiler error tells me that the self.contains line now requires Element to conform to Equatable.
How is the original function exempt from this limitation, while a function with a slightly different signature requires it?
I feel like this should be trivial, but I've spent hours on it and can't find a working setup. Can someone show me a solution?
After seeing #Sweeper's comment about UIButton and Dictionary being equatable, I tried again with that constraint. I was seeing errors before with arrays of UIButtons, but not this time, so those must have been triggered by something else. However, the errors with what I thought were Dictionaries were actually just plain structs. I used this answer to make my structs comform to Equatable, and now everything works as intended.
In fact, with the Equatable constraint added, the infinite loop no longer occurs, so I can go back to the first version of my function:
extension Array where Element: Equatable {
func contains(_ element: Element?) -> Bool {
if let element = element {
return self.contains(element)
} else {
return false
}
}
}
Apparently there is a version of contains() that doesn't have the Equatable constraint, which is what I was calling when using structs before, and what my custom function was calling with self.contains(). Anyway, these are the lessons learned:
When creating a variation of a native function, add the same type constraints as the original.
Conform custom structs to Equatable for ease of use with collections.

Swift: why mutating function can not be static

I have a theoretical question, I did not find related topics.
At some point, I decided that it would be nice to have a small extension for an array:
var array = [Int]()
array += 1
The code is quite simple:
extension Array {
mutating static func +=(lhs: Array, rhs: Element) {
lhs.append(rhs)
}
}
To achieve this we align with two factors that make perfect sense to me:
Array is a struct and this operation requires a mutation
Infix operator reload requires a static function
Unfortunately, it is impossible due Swift does not allow mutating functions to be static. And this is the part I don't quite understand.
Your += mutates the first argument, not the Array type.
Therefore it must not be declared mutating (which makes no
sense for a static method because you cannot mutate the type), but the first parameter must be inout:
extension Array {
static func +=(lhs: inout Array, rhs: Element) {
lhs.append(rhs)
}
}
var array = [Int]()
array += 1
print(array) // [1]
Because mutating doesn't mean "mutates anything", but rather, "mutates self". Your function attempts to mutate lhs, not self.
Your current code won't work because lhs is being passed by value. The lhs parameter is a local copy of whatever argument the caller supplied to it, thus any changes your function makes will be local to the function and won't persist. You'll need to instead have lhs be passed by reference, by delcaring it as a inout Array.
By using static keyword before method name means, we call method by struct/class name (Not by an object) so we don't have any object here.
By using mutating keyword, we are mutating 'self' object.
So while using static we don't have any object to mutate.

Check if a type implements a protocol

I am writing a library that creates extensions for default Swift types.
I would like to have a check on my Array extensions whether a certain type implements a certain protocol. See this method for example:
extension Array {
/// Compares the items using the given comparer and only returns non-equal values
/// :returns: the first items that are unique according to the comparer
func distinct(comparer: (T, T) -> Bool) -> [T] {
var result: [T] = []
outerLoop: for item in self {
for resultItem in result {
if comparer(item, resultItem) {
continue outerLoop
}
}
result.append(item)
}
return result
}
}
Now I'd like to rewrite this method to check if T is Equatable as such:
/// Compares the items using the given comparer and only returns non-equal values
/// :returns: the first items that are unique according to the comparer
func distinct(comparer: ((T, T) -> Bool)?) -> [T] {
var result: [T] = []
outerLoop: for item in self {
for resultItem in result {
if isEquatable ? comparer!(item, resultItem) : item == resultItem {
continue outerLoop
}
}
result.append(item)
}
return result
}
where isEquatable is a Bool value that tells me if T is Equatable. How can I find this out?
There isn’t a good way to do this in Swift at the moment.* This is why functions like sorted are either free-functions, or in the case of the member, take a predicate. The main problem with the test-and-cast approach you’re looking for is that Equatable and similar protocols have an associated type or rely on Self, and so can only be used inside a generic function as a constraint.
I’m guessing your goal is that the caller can skip supplying the comparator function, and so it will fall back to Equatable if available? And crash if it isn’t? The problem here is that the function is determining something at run time (the argument is Equatable) when this really ought to be determinable at compile time. This is not great - it’s much better to determine these things fully at compile time.
So you can write a free function that requires Equatable:
func distinct<C: CollectionType where C.Generator.Element: Equatable>
(source: C) -> [C.Generator.Element] {
var seen: [C.Generator.Element] = []
return filter(source) {
if contains(seen, $0) {
return false
}
else {
seen.append($0)
return true
}
}
}
let uniques = distinct([1,2,3,1,1,2]) // [1,2,3]
and then if you tried to call it with something that wasn’t comparable, you’d get a compile-time error:
let incomparable = [1,2,3] as [Any]
distinct(incomparable) // compiler barfs - Any isn’t Equatable
With the runtime approach, you’d only find this out when you ran the program.
The good news is, there are upsides too. The problem with searching an array for each element is the function will be very slow for large arrays, because for every element, the list of already-seen elements must be searched linearly. If you overload distinct with another version that requires the elements be Hashable (which Equatable things often are), you can use a set to track them:
func distinct<C: CollectionType where C.Generator.Element: Hashable>
(source: C) -> [C.Generator.Element] {
var seen: Set<C.Generator.Element> = []
return filter(source) {
if seen.contains($0) {
return false
}
else {
seen.insert($0)
return true
}
}
}
At compile time, the compiler will choose the best possible version of the function and use that. If your thing is hashable, that version gets picked, if it’s only equatable, it’ll use the slower one (this is because Hashable inherits from Equatable, and the compiler picks the more specialized function). Doing this at compile time instead of run time means you pay no penalty for the check, it’s all determined up front.
*there are ugly ways, but since the goal is appealing syntax, what’s the point… Perhaps the next version will allow constraints on methods, which would be nice.