How do you modify array parameter in swift - 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
}

Related

How can I change an inout parameter from within a escaping closure?

I was trying to modify a parameter of function from within a escaping closure as below:
var completion = [()->Void]()
func addCompletion(closure: #escaping ()->Void) {
completion.append(closure)
}
func testAdd(v: inout Int) {
addCompletion{
v = 1 // Compiler tells 'Escaping closure captures 'inout' parameter 'v'
print("hello1 \(v)")
}
}
var x = 0
testAdd(v:&x)
for comp in completion {
comp()
}
I was wondering if there is another way to let escaping closure change surrounding variable (as function's inout parameter), besides making it into reference type as a class object.
inout is specified to have a "copy-in copy-out" behaviour. The value of x is copied when you call the function. In the function body, the copy of x can be modified, or whatever. Then, when the function returns, the copy is copied again, and assigned to the original x. "Call-by-reference" could happen as an optimisation.
This explains why you can't modify an inout parameter in an escaping closure. The swift compiler can't possibly know when every escaping closure returns, to copy the modified value back.
You can use an actual pointer:
func testAdd(v: UnsafeMutablePointer<Int>) {
addCompletion{
v.pointee = 1 // you just need to change all references to "v" to "v.pointee"
print("hello1 \(v.pointee)")
}
}
Alternatively, if you don't like pointers, you can also do this trick (adapted from my other answer):
func testAdd(modifyV: #escaping ((inout Int) -> Void) -> Void) {
addCompletion{
modifyV { v in // here you can change v however you like!
v = 1
print("hello1 \(v)")
}
}
}
You just need to change the caller to:
testAdd { $0(&x) }

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.

Swift closure capture array by reference

In Swift Collections are pass by value by default and we can user inout to make it pass by reference in function arguments but how can we do it in closure capture variables?
var list = [1, 2, 3]
func edit(inout list: [Int]) {
list.append(4)
dispatch_async(dispatch_get_main_queue()) {
list.append(5)
}
}
edit(&list)
...// after dispatch_async was executed
NSLog("\(list)")
Result will be [1, 2, 3, 4]
How can I modify the original variable () inside closure?
UPDATE:
Actually I have a workaround to handle this case by putting the array into an object so I can pass this object to the function by reference and we can modify the same array instance inside the function. but I want see any clever way to archive that
For getting a variable escape from a closure you need #escaping, check this out. A workaround is to put a completion function as an argument rather than an inout variable.
class MyClass {
static func edit(_ list: [Int], _ completion: #escaping ([Int]) -> ()) {
var list = list
list.append(4)
DispatchQueue.main.async() {
list.append(5)
completion(list)
}
}
}
var myList = [1, 2, 3]
MyClass.edit(myList) { (list) in
myList = list
print("My list after editing: \(myList)")
}
print("My list without editing: \(myList)")
Note: The above example is for Swift 3 where inout parameters are not allowed to be captured in closures. Based on your post, you may be using a lower version of Swift where you might be able to use inout rather than setting a mutable copy of the list: var list = list. However, the logic is very similar.
For more information, check the Limiting inout capture to #noescape contexts in Swift evolution:
Swift's behavior when closures capture inout parameters and escape
their enclosing context is a common source of confusion. We should
disallow implicit capture of inout parameters except in #noescape
closures.

Why doesn’t my Swift array extension work?

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.

How can I convert between related types through a common initializer?

I'm trying to build up a family of types that can be converted to each other. For example, Float and Double can be converted to each other through their initializers. I'd like to not have to create an exhaustive list of initializers showing that each type can convert to every other type.
I tried to do something like this in a Playground, but it crashes:
protocol FloatConvertible {
init(_ x:FloatConvertible)
}
extension FloatConvertible {
init(_ x:FloatConvertible){self.init(Self(x))}
}
extension Float:FloatConvertible {}
extension Double:FloatConvertible {}
func transmute<T:FloatConvertible, U:FloatConvertible>
(a:T, b:U) -> T {
return T(b)
}
transmute(Float(3.1), b: Double(2.6))
My eventual goal isn't just to do the conversion, but to multiply a by b like so:
func *<T:FloatConvertible, U:FloatConvertible> (a:T, b:U) -> T{
return a * T(b)
}
So that I can express the multiply.
Is there a way to do this? I think part of the problem is winding up with a structure that looks like Double(Double(Double(Double(...))), but I don't think I can put a constraint that ensures T != U.
The problem is that in your init(_ x:FloatConvertible), Swift cannot infer what the concrete type of x is. It just knows that it's a FloatConvertible. Therefore when you try to do Self(x), while it can infer the concrete type of Self, it doesn't know which initialiser you want to call, meaning that it will default to your init(_ x:FloatConvertible) initialiser, thus creating an infinite loop.
If you give your custom initialiser an argument name, you'll see that Swift complains that it can't find the correct initialiser:
protocol FloatConvertible {
init(c x:FloatConvertible)
}
extension FloatConvertible {
init(c x:FloatConvertible) {
// error: missing argument name 'c:' in call
// (i.e it can't find the concrete type's initialiser)
self.init(Self(x))
}
}
A potential solution therefore is to resolve this at runtime by switching over the concrete types that x could be. However this isn't nearly as good as resolving this statically, as you can benefit from increased safety and in some cases increased performance.
In order to do this statically, you could add a generic _asOther 'shadow' function to your protocol that can convert a given floating point type to another, as well as adding the concrete type's initialisers to your protocol requirement.
This will save you from having to list out all the possible combinations of conversions – you can now just invoke _asOther from your initialiser.
protocol FloatConvertible {
init(_ other:Float)
init(_ other:Double)
init(_ other:CGFloat)
init(fromOther x:FloatConvertible)
func _asOther<T:FloatConvertible>() -> T
}
extension FloatConvertible {
init(fromOther x:FloatConvertible) {self = x._asOther()}
}
// note that we have to implement these for each extension,
// so that Swift uses the concrete types of self, preventing an infinite loop
extension Float : FloatConvertible {
func _asOther<T:FloatConvertible>() -> T {return T(self)}
}
extension Double : FloatConvertible {
func _asOther<T:FloatConvertible>() -> T {return T(self)}
}
extension CGFloat : FloatConvertible {
func _asOther<T:FloatConvertible>() -> T {return T(self)}
// note that CGFloat doesn't implement its own initialiser for this,
// so we have to implement it ourselves
init(_ other:CGFloat) {self = other}
}
func transmute<T:FloatConvertible, U:FloatConvertible>(value: T, to: U.Type) -> U {
return U(fromOther: value)
}
let f = transmute(value: CGFloat(2.6), to: Float.self)
print(type(of: f), f) // prints: Double 2.59999990463257
In the initialiser, _asOther will be called on the input value, with the type of self being inferred for the generic parameter T (in this context self is guaranteed to be a concrete type). The _asOther function will then get called on x, which will return the value as the given destination type.
Note that you don't have to use the fromOther: argument label for your custom initialiser – this will still work without any label. Although I would strongly advocate for using it to catch any problems with your code at compile time (Swift would accept code that would cause infinite loops at runtime otherwise).
Also as a side note, you should maybe re-think your design for how you want your * overload to work. It would make more sense to be returning the more precise type that you input into it (i.e Float * Double = Double) – otherwise you're just needlessly losing precision.