4

I'm just going through some Swift tuts that are obviously already outdated as of Beta3 ...

func exchange<T>(data:[T], i:Int, j:Int)
{
    let temp = data[i];
    data[i] = data[j];
    data[j] = temp;
}

Playgrounds tells me:

Error: @lvalue $T8 is not identical to T.

How do I change it to make it work?

1

1 Answer 1

11

Arrays in Swift are value types. That means that data is copied when passed into your exchange method, but you are trying to modify the copy to affect the original version. Instead you should do one of two things:

1. Define data as an inout parameter:

func exchange<T>(inout data:[T], i:Int, j:Int)

Then when calling it you have to add an & before the call:

var myArray = ["first", "second"]
exchange(&myArray, 0, 1)

2. Return a copy of the Array (recommended)

func exchange<T>(data:[T], i:Int, j:Int) -> [T]
{
    var newData = data
    newData[i] = data[j]
    newData[j] = data[i]
    return newData
}

I recommend this way over the in-out parameter because in-out parameters create more complicated state. You have two variables pointing to and potentially manipulating the same piece of memory. What if exchange decided to do its work on a separate thread? There is also a reason that Apple decided to make arrays value types, using in-out subverts that. Finally, returning a copy is much closer to Functional Programming which is a promising direction that Swift can move. The less state we have in our apps, the fewer bugs we will create (in general).

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for the fast explanation! Two useful ways to know about!
can you explain, please, why you don't recommend the inout parameters? that is more efficient in the case of huge arrays than making a copy of the array every time when the method is called...
@holex Sure, I updated my answer. I think it is unwise to worry about efficiency when writing code. Understandability and reliability is WAY more important until you run instruments and discover the the method is a huge bottleneck. Also, the compiler should be able to optimize that copying away when appropriate.
@drewag, I understand your point about reliability, but using inout parameters are totally reliable! the only weak point is the developer, but if the developer is under-educated (that leads a poor implementation which leads having more bugs which leads spending more time on fixing bugs, etc...), does not matter which version they use, they will make logical-structural mistakes eventually in a project. however, I guess we all have different debug policies, personally I spend 10-15% of the development time fixing bugs, but I've seen 'developers' who spent 60-65% – and you know what that means.
@holex it is naive to think that all developers are not susceptible to mistakes. I believe it is better to use techniques that minimize that possibility. State is the biggest place for mistakes because no matter how great of a programmer you are, there is only so much state that you can keep track of in your mind, ESPECIALLY when working with other developers, inheriting a code base, or passing off a codebase. Also, using the copy technique allows you to effortlessly use the same techniques in asynchronous code. All that being said, I still listed inout it as a valid solution for a reason.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.