I've been studying for my midterm tomorrow, and I came across this question where I couldn't decide between answers 2 and 3. PlayingCard is a struct, and HANDSIZE is a constant with a value of 5.
The right answer was apparently option 2, but both a friend and I thought that the better choice here would be 3, as we were told that we should use const as good programming practice when we know that the variable isn't going to be changed. Seeing as it isn't changed here, why would option 2 be better than option 3?
/* QUESTION: What should go for the definition of isFlush that detects flushes
1: Nothing
2: bool isFlush(PlayingCard hand[HANDSIZE]) {
3: bool isFlush(const PlayingCard hand[HANDSIZE]) {
4: bool isFlush(PlayingCard ** hand) {
5: bool isFlush(const PlayingCard ** hand) {
6: bool isFlush(PlayingCard *** hand) {
7: bool isFlush(CardFace * hand) {
8: bool isFlush(CardSuit * hand) {
9: bool isFlush(CardSuit suits[HANDSIZE]) {
*/
// missing function defintion
CardSuit suit = hand[0].suit;
for (int i = 1; i < HANDSIZE; i++ ) {
if (suit != hand[i].suit) {
return false;
}
}
return true;
}
as we were told that we should use const as good programming practice
when we know that the variable isn't going to be changed
This is true, but only when you pass a pointer to a variable. If you pass the variable by value there is no advantage that I can see.
In this case I agree that the best answer is 3. It is probably too late to ask the author of the question why the correct answer is 2.
You can use const as a hint that the function will not modify something. You can pass a pointer to non-const thing to a function that declares it will take a pointer to const thing.
We don't have sufficient information to inform you which function declaration will work. I can eliminate options 1, 4, 5, 6, 8 and 9.
I can eliminate option 1 because it would not compile.
I can eliminate options 4, 5, and 6 because you cannot access a pointer with the . operator as is being done in the initialization of suit.
I can eliminate option 8, because a struct or union cannot be compared using !=.
I can eliminate option 9, because the name of the argument is wrong.
Options 8 and 9 are also unlikely because of the recursive definition required of the type CardSuit that is being suggested in the initialization of suit.
You asked:
Seeing as it isn't changed here, why would option 2 be better than option 3?
You seems to have eliminated option 7. I have insufficient information to do so, since PlayingCard might not have a suit member, whereas CardFace might have such a member. If that were the case, the correct answer would be option 7.
But assuming option 7 should be eliminated, then either options 2 or 3 would work for the function. So, to answer your question above in particular, option 3 is superior because it communicates the intention that the function will not modify the elements of the array.
The only advantage option 2 has over option 3 is that it will exclude attempts to call the function with an array of const things. You would only want to do that if the function wished to modify the elements.
Related
I was examining some code on github https://github.com/umlaeute/v4l2loopback/blob/master/v4l2loopback.c and came across this line, which baffles me. Is this some incredibly cool kernel macro or gcc feature that I don't know about? What does the = -1 do?
static int video_nr[MAX_DEVICES] = { [0 ... (MAX_DEVICES-1)] = -1 };
module_param_array(video_nr, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "video device numbers (-1=auto, 0=/dev/video0, etc.)");
The line in question is the first, the next two given for context (this is creating a cmdline-specifiable parameter using a kernel macro http://lxr.free-electrons.com/source/include/linux/moduleparam.h#L103 )
Anyway, what is going on with the array initialization? How does that syntax work?
You've found an example of designated initializers. C99 & C11 don't go quite as far as your example, but they have some pretty flexible support for this kind of behaviour. Your specific example (using the ...) is a GCC extension. From the link:
To initialize a range of elements to the same value, write [first ... last] = value. This is a GNU extension. For example,
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
So that means your example is creating an array of size MAX_DEVICES and initializing every element in that array to -1.
For reference, the only standard-supported behaviour is to assign specific indices, rather than ranges:
[constant-expression] = initializer-value
There is a more complicated example in my copy of the spec:
int a[MAX] = {
1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
Which initializes the first five and last five elements of the array to explicit values. The middle values (if any) would be 0.
Reading this I learn that:
Instances of value types are not shared: every thread gets its own copy.* That means that every thread can read and write to its instance without having to worry about what other threads are doing.
Then I was brought to this answer and its comment
and was told:
an array, which is not, itself, thread-safe, is being accessed from
multiple threads, so all interactions must be synchronized.
& about every thread gets its own copy I was told
if one thread is updating an array (presumably so you can see that
edit from another queue), that simply doesn't apply
that simply doesn't apply <-- Why not?
I initially thought all of this is happening because the array ie a value type is getting wrapped into a class but to my amazement I was told NOT true! So I'm back to Swift 101 again :D
The fundamental issue is the interpretation of "every thread gets its own copy".
Yes, we often use value types to ensure thread safety by providing every thread its own copy of an object (such as an array). But that is not the same thing as claiming that value types guarantee every thread will get its own copy.
Specifically, using closures, multiple threads can attempt to mutate the same value-type object. Here is an example of code that shows some non-thread-safe code interacting with a Swift Array value type:
let queue = DispatchQueue.global()
var employees = ["Bill", "Bob", "Joe"]
queue.async {
let count = employees.count
for index in 0 ..< count {
print("\(employees[index])")
Thread.sleep(forTimeInterval: 1)
}
}
queue.async {
Thread.sleep(forTimeInterval: 0.5)
employees.remove(at: 0)
}
(You generally wouldn't add sleep calls; I only added them to manifest race conditions that are otherwise hard to reproduce. You also shouldn't mutate an object from multiple threads like this without some synchronization, but I'm doing this to illustrate the problem.)
In these async calls, you're still referring to the same employees array defined earlier. So, in this particular example, we'll see it output "Bill", it will skip "Bob" (even though it was "Bill" that was removed), it will output "Joe" (now the second item), and then it will crash trying to access the third item in an array that now only has two items left.
Now, all that I illustrate above is that a single value type can be mutated by one thread while being used by another, thereby violating thread-safety. There are actually a whole series of more fundamental problems that can manifest themselves when writing code that is not thread-safe, but the above is merely one slightly contrived example.
But, you can ensure that this separate thread gets its own copy of the employees array by adding a "capture list" to that first async call to indicate that you want to work with a copy of the original employees array:
queue.async { [employees] in
...
}
Or, you'll automatically get this behavior if you pass this value type as a parameter to another method:
doSomethingAsynchronous(with: employees) { result in
...
}
In either of these two cases, you'll be enjoying value semantics and see a copy (or copy-on-write) of the original array, although the original array may have been mutated elsewhere.
Bottom line, my point is merely that value types do not guarantee that every thread has its own copy. The Array type is not (nor are many other mutable value types) thread-safe. But, like all value types, Swift offer simple mechanisms (some of them completely automatic and transparent) that will provide each thread its own copy, making it much easier to write thread-safe code.
Here's another example with another value type that makes the problem more obvious. Here's an example where a failure to write thread-safe code returns semantically invalid object:
let queue = DispatchQueue.global()
struct Person {
var firstName: String
var lastName: String
}
var person = Person(firstName: "Rob", lastName: "Ryan")
queue.async {
Thread.sleep(forTimeInterval: 0.5)
print("1: \(person)")
}
queue.async {
person.firstName = "Rachel"
Thread.sleep(forTimeInterval: 1)
person.lastName = "Moore"
print("2: \(person)")
}
In this example, the first print statement will say, effectively "Rachel Ryan", which is neither "Rob Ryan" nor "Rachel Moore". In short, we're examining our Person while it is in an internally inconsistent state.
But, again, we can use a capture list to enjoy value semantics:
queue.async { [person] in
Thread.sleep(forTimeInterval: 0.5)
print("1: \(person)")
}
And in this case, it will say "Rob Ryan", oblivious to the fact that the original Person may be in the process of being mutated by another thread. (Clearly, the real problem is not fixed just by using value semantics in the first async call, but synchronizing the second async call and/or using value semantics there, too.)
Because Array is a value type, you're guaranteed that it has a single direct owner.
The issue comes from what happens when an array has more than one indirect owner. Consider this example:
Class Foo {
let array = [Int]()
func fillIfArrayIsEmpty() {
guard array.isEmpty else { return }
array += [Int](1...10)
}
}
let foo = Foo();
doSomethingOnThread1 {
foo.fillIfArrayIsEmpty()
}
doSomethingOnThread2 {
foo.fillIfArrayIsEmpty()
}
array has a single direct owner: the foo instance it's contained in. However, both thread 1 and 2 have ownership of foo, and transitively, of the array within it. This means they can both mutate it asynchronously, so race conditions can occur.
Here's an example of what might occur:
Thread 1 starts running
array.isEmpty evaluates to false, the guard passes, and execution will continue passed it
Thread 1 has used up its CPU time, so it's kicked off the CPU. Thread 2 is scheduled on by the OS
Thread 2 is now running
array.isEmpty evaluates to false, the guard passes, and execution will continue passed it
array += [Int](1...10) is executed. array is now equal to [1, 2, 3, 4, 5, 6, 7, 8, 9]
Thread 2 is finished, and relinquishes the CPU, Thread 1 is scheduled on by the OS
Thread 1 resumes where it left off.
array += [Int](1...10) is executed. array is now equal to [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9]. This wasn't supposed to happen!
You have a wrong assumption. You think that whatever you do with structs a copy will always magically happen. NOT true. If you copy them they will be copied as simple as that.
class someClass{
var anArray : Array = [1,2,3,4,5]
func copy{
var copiedArray = anArray // manipulating copiedArray & anArray at the same time will NEVER create a problem
}
func myRead(_ index : Int){
print(anArray[index])
}
func myWrite(_ item : Int){
anArray.append(item)
}
}
However inside your read & write funcs you are accessing anArray—without copying it, so race-conditions can occur if both myRead and myWrite functions are called concurrently. You have to solve (see here) the issue by using queues.
I'm trying to add functionality to an Array class.
So I attempted to add a sort() similar to Ruby's lexicon.
For this purpose I chose the name 'ricSort()' if deference to Swift's sort().
But the compiler says it can't find an overload for '<', albeit the 'sort({$0, $1}' by
itself works okay.
Why?
var myArray:Array = [5,4,3,2,1]
myArray.sort({$0 < $1}) <-- [1, 2, 3, 4, 5]
myArray.ricSort() <-- this doesn't work.
Here's a solution that is close to what you are looking for, followed by a discussion.
var a:Int[] = [5,4,3,2,1]
extension Array {
func ricSort(fn: (lhs: T, rhs: T) -> Bool) -> T[] {
let tempCopy = self.copy()
tempCopy.sort(fn)
return tempCopy
}
}
var b = a.ricSort(<) // [1, 2, 3, 4, 5]
There are two problems with the original code. The first, a fairly simple mistake, is that Array.sort returns no value whatsoever (represented as () which is called void or Unit in some other languages). So your function, which ends with return self.sort({$0 < $1}) doesn't actually return anything, which I believe is contrary to your intention. So that's why it needs to return tempCopy instead of return self.sort(...).
This version, unlike yours, makes a copy of the array to mutate, and returns that instead. You could easily change it to make it mutate itself (the first version of the post did this if you check the edit history). Some people argue that sort's behavior (mutating the array, instead of returning a new one) is undesirable. This behavior has been debated on some of the Apple developer lists. See http://blog.human-friendly.com/swift-arrays-the-bugs-the-bad-and-the-ugly-incomplete
The other problem is that the compiler does not have enough information to generate the code that would implement ricSort, which is why you are getting the type error. It sounds like you are wondering why it is able to work when you use myArray.sort but not when you try to execute the same code inside a function on the Array.
The reason is because you told the compiler why myArray consists of:
var myArray:Array = [5,4,3,2,1]
This is shorthand for
var myArray: Array<Int> = [5,4,3,2,1]
In other words, the compiler inferred that the myArray consists of Int, and it so happens that Int conforms to the Comparable Protocol that supplies the < operator (see: https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/Comparable.html#//apple_ref/swift/intf/Comparable)[1]. From the docs, you can see that < has the following signature:
#infix func < (lhs: Self, rhs: Self) -> Bool
Depending on what languages you have a background in, it may surprise you that < is defined in terms of the language, rather than just being a built in operator. But if you think about it, < is just a function that takes two arguments and returns true or false. The #infix means that it can appear between its two functions, so you don't have to write < 1 2.
(The type "Self" here means, "whatever the type is that this protocol implements," see Protocol Associated Type Declaration in https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_597)
Compare this to the signature of Array.sort: isOrderedBefore: (T, T) -> Bool
That is the generic signature. By the time the compiler is working on this line of code, it knows that the real signature is isOrderedBefore: (Int, Int) -> Bool
The compiler's job is now simple, it just has to figure out, is there a function named < that matches the expected signature, namely, one that takes two values of type Int and returns a Bool. Obviously < does match the signature here, so the compiler allows the function to be used here. It has enough information to guarantee that < will work for all values in the array. This is in contrast to a dynamic language, which cannot anticipate this. You have to actually attempt to perform the sort in order to learn if the types can actually be sorted. Some dynamic languages, like JavaScript, will make every possible attempt to continue without failing, so that expressions such as 0 < "1" evaluate correctly, while others, such as Python and Ruby, will throw an exception. Swift does neither: it prevents you from running the program, until you fixed the bug in your code.
So, why doesn't ricSort work? Because there is no type information for it to work with until you have created an instance of a particular type. It cannot infer whether the ricSort will be correct or not.
For example, suppose instead of myArray, I had this:
enum Color {
case Red, Orange, Yellow, Green, Blue, Indigo, Violet
}
var myColors = [Color.Red, Color.Blue, Color.Green]
var sortedColors = myColors.ricSort() // Kaboom!
In that case, myColors.ricSort would fail based on a type error, because < hasn't been defined for the Color enumeration. This can happen in dynamic languages, but is never supposed to happen in languages with sophisticated type systems.
Can I still use myColors.sort? Sure. I just need to define a function that takes two colors and returns then in some order that makes sense for my domain (EM wavelength? Alphabetical order? Favorite color?):
func colorComesBefore(lhs: Color, rhs: Color) -> Bool { ... }
Then, I can pass that in: myColors.sort(colorComesBefore)
This shows, hopefully, that in order to make ricSort work, we need to construct it in such a way that its definition guarantees that when it is compiled, it can be shown to be correct, without having to run it or write unit tests.
Hopefully that explains the solution. Some proposed modifications to the Swift language may make this less painful in the future. In particular creating parameterized extensions should help.
The reason you are getting an error is that the compiler cannot guarantee that the type stored in the Array can be compared with the < operator.
You can see the same sort closure on an array whose type can be compared using < like an Int:
var list = [3,1,2]
list.sort {$0 < $1}
But you will get an error if you try to use a type that cannot be compared with <:
var URL1 = NSURL()
var URL2 = NSURL()
var list = [URL1, URL2]
list.sort {$0 < $1} // error
Especially with all the syntax you can leave out in Swift, I don't see a reason to define a method for this. The following is valid and works as expected:
list.sort(<)
You can do this because < actually defines a function that takes two Ints and returns a Bool just like the sort method is expecting.
Suppose i have the following enumerated literal
enum
{
valueA = 5,
valueB = 7,
valueC = 9,
valueD = 14,
valueE = 15
}myEnumType;
and i want to loop through each literal
eg
for (enumType myValEnum = valueA; myValEnum <= valueE; myValEnum++)
{
MyFunction(mValEnum);
}
will that work or will I end up calling MyFunction with values 5,6,7,8,9,10,11,12,13,14,15 ?
You can't do that, there's no support for a "foreach" type of iteration over the enumeration in C. Basically, enumerations are just aliased integers, with little extra support.
You need to use a mapping table, that allows you to map consecutive indices to values of the enumerated type:
static const myEnumType myEnumMap[] = { valueA, valueB, valueC, valueD, valueE};
then you can use a plain loop over that array:
for(size_t i = 0; i < sizeof myEnumMap / sizeof *myEnumMap; ++i)
{
const myEnumType ie = myEnumMap[i];
/* process ie */
}
Note that the type of myEnumMap is the type of your enumeration, it's not a plain "array of integers".
This has the downside of requiring the enum to be enumerated twice (once in its own definition, then again in the myEnumMap initializer). It's possible to work around that using macro trickery (such as X macros), but there's no real convenient/easy way to do it.
Directly it is not possible to loop through each enum literal. You can do that indirectly by using an array of integers. Assign each enum literals to array elements sequentially and then you can loop through each array element.
I am not sure, if this is helpful, but I had the following thoughts:
We have to save the possible values of the enum somewhere, because this information doesn't exist in memory, so we need something like an array with the possible values:
enum {
valueA = 5,
valueB = 7,
valueC = 9,
valueD = 14,
valueE = 15
} myEnumType;
const int myEnumTypeArr[] = { 5, 7, 9, 14, 15 };
where it's possible to not store that array but to create a temporary object whenever needed (e.g. we could wrap the array contents into a macro).
I don't think that's a good solution, though, because if you change your enum, you must change the array. If you forget to do so, the compiler won't warn you and it may result in hard-to-find bugs.
So maybe the following is helpful: You use the array for the values and the enum constants as indexes:
enum { valueA, valueB, valueC, dummy } myEnumType; // dummy must stay at last position
const int myEnumTypeArr[] = { 5, 7, 9 };
so you use myEnumTypeArr[valueA] rather than valueA directly (with the drawback, that it's no longer a constant, e.g. can't be used as a case label) and maybe something like that (somewhat ugly, though)
static_assert( sizeof myEnumTypeArr / sizeof *myEnumTypeArr == dummy );
to prevent the aforementioned bug.
HTH
You can't do it using enum and loops.
Your loop
for (enumType myValEnum = valueA; myValEnum <= valueE; myValEnum++)
{
MyFunction(mValEnum);
}
iterates from 5 to 15(5,6,7,8,9,10,11,12,13,14,15). According to my knowledge pointer to enum's also can't help you here.
I was examining some code on github https://github.com/umlaeute/v4l2loopback/blob/master/v4l2loopback.c and came across this line, which baffles me. Is this some incredibly cool kernel macro or gcc feature that I don't know about? What does the = -1 do?
static int video_nr[MAX_DEVICES] = { [0 ... (MAX_DEVICES-1)] = -1 };
module_param_array(video_nr, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "video device numbers (-1=auto, 0=/dev/video0, etc.)");
The line in question is the first, the next two given for context (this is creating a cmdline-specifiable parameter using a kernel macro http://lxr.free-electrons.com/source/include/linux/moduleparam.h#L103 )
Anyway, what is going on with the array initialization? How does that syntax work?
You've found an example of designated initializers. C99 & C11 don't go quite as far as your example, but they have some pretty flexible support for this kind of behaviour. Your specific example (using the ...) is a GCC extension. From the link:
To initialize a range of elements to the same value, write [first ... last] = value. This is a GNU extension. For example,
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
So that means your example is creating an array of size MAX_DEVICES and initializing every element in that array to -1.
For reference, the only standard-supported behaviour is to assign specific indices, rather than ranges:
[constant-expression] = initializer-value
There is a more complicated example in my copy of the spec:
int a[MAX] = {
1, 3, 5, 7, 9, [MAX-5] = 8, 6, 4, 2, 0
};
Which initializes the first five and last five elements of the array to explicit values. The middle values (if any) would be 0.