Conflicting Definition of Swift Struct and Array

Memory access conflict with structs and observer pattern

If you're observing "a thing," then that "thing" has an identity. It's a particular thing that you're observing. You can't observe the number 4. It's a value; it has no identity. Every 4 is the same as every other 4. Structs are values. They have no identity. You should not try to observe them any more than you'd try to observe an Int (Int is in fact a struct in Swift).

Every time you pass a struct to a function, a copy of that struct is made. So when you say self.model = model, you're saying "make a copy of model, and assign it to this property." But you're still in an exclusive access block because every time you modify a struct, that also makes a copy.

If you mean to observe ModelObject, then ModelObject should be a reference type, a class. Then you can talk about "this particular ModelObject" rather than "a ModelObject that contains these values, and is indistinguishable from any other ModelObject which contains the same values."

Crash in Swift struct definition. Have workaround but would like to improve understanding

This code should crash in either debugging or release mode.

endIndex definition-

The array’s “past the end” position—that is, the position one greater
than the last valid subscript argument.

You should get an "Index out of range" error while debugging

Swift - pass struct to a method?

@Mike S's answer above is correct, but if you want to use this for any type you'll need a generic function:

func removeOne<T>(inout array: Array<T>) {
array.removeLast()
}

var array = ["1", "2", "3"]
removeOne(&array)

How to implement a Swift protocol across structs with conflicting property names

The desired feature from explicit interface implementations is that they are statically dispatched, right? If you use Description on a BusStop, it will be an optional string, but if you use Description on a Stop, it will be a non-optional string.

In Swift, extension members are statically dispatched, so you can make use of this to achieve something similar:

extension Stop where Self == BusStop {
// Since the type of "self" here is BusStop, "Description" refers to the one declared in BusStop
// not this one here, so this won't cause infinite recursion
var Description : String { return self.Description ?? "" }
}

extension Stop where Self == TrainStop {
var Latitude: Double { return self.Latitude ?? 0 }
var Longitude: Double { return self.Longitude ?? 0 }
}

This code shows that this works:

let busStop = BusStop(Code: "ABC", Description: "My Bus Stop", Latitude: 0, Longitude: 0)
print(type(of: busStop.Description)) // Optional<String>
let stop: Stop = busStop
print(type(of: stop.Description)) // String

However, I still don't think this is good Swift code. It is often bad to just directly translate an API from one language to another. If I were you, I would make Longitude, Latitude and Description in Stop to be all optionals.

Variable name conflicts with built-in function

You can say Swift.type(of:whatever).

Struct value types in Swift

It copies the pointer to the instance. I just tested this in a playground.

struct MyStruct {
var instance: MyClass
}

class MyClass {
var name: String
init(name: String) {
self.name = name
println("inited \( self.name )") // Prints "inited Alex" only once
}
}

var foo = MyClass(name: "Alex") // make just one instance
var a = MyStruct(instance: foo) // make a struct that contains that instance
var b = a // copy the struct that references the instance

foo.name = "Wayne" // Update the instance

// Check to see if instance was updated everywhere.
a.instance.name // Wayne
b.instance.name // Wayne

What is different though, is that it's now two different references to the same object. So if you change one struct to a different instance, you are only hanging it for that struct.

b.instance = MyClass(name: "Vik")

// a and b no longer reference the same instance
a.instance.name // Wayne
b.instance.name // Vik

The playground is a great way to test out questions like these. I did not know the answer definitively when I read this question. But now I do :)

So don't be afraid to go play.

Comparing large sets of integers individually versus array

Yes, it would generally require more memory to make a copy of the properties. Also, a struct with many properties does not have the kind of copy-on-write benefits that an Array does. (Copy-on-write is not something you get for free in Swift. It's something that has to be implemented in the data type, and Array implements it.)

I would be very tempted to use a Dictionary as your storage here, rather than hundreds of properties. Dictionaries also have copy-on-write, so if there are many copies of the initial state, you could save some copies there. (I'm assuming they're not really "initial1" and "initial2". If they have a clear order and indexing, then an Array would be correct choice.) I typically have to tell people to use structs instead of Dictionaries, but it's possible this would be an exception. (I'm interested why there are so many integer properties, though.)

I'd also look at @dynamicMemberLookup, which might simplify your life significantly.

Note that if these are "initial" and "current" I would definitely split them into two objects rather than merging them with parallel properties. It should be obj.current.property rather than obj.currentProperty IMO. That would preserve your ability to do obj.current != obj.initial without having to make a massive copy.

Swift4: why and when is simultaneous access to separate struct elements illegal?

As you correctly state, in practice there is no conflicting access in your code. The question is whether Swift recognises that or plays safe.

Turning to The Swift Programming Language (Swift 4.2), which is as close as we can get to a formal definition of Swift we find in the Memory Safety chapter:

Conflicting Access to Properties

Types like structures, tuples, and enumerations are made up of individual constituent values, such as the properties of a structure or the elements of a tuple. Because these are value types, mutating any piece of the value mutates the whole value, meaning read or write access to one of the properties requires read or write access to the whole value.

Here you can read "Because these are value types" as "In Swift it was decided that for composite values type", i.e. Apple made a choice and defined things this way, other languages might make other choices.

So by that statement your code is conflicting. However a few paragraphs later an Apple writes about relaxing this specification:

In practice, most access to the properties of a structure can overlap safely.

[An example similar to yours except it uses a local variable]

The compiler can prove that memory safety is preserved because the two stored properties don’t interact in any way.

So Apple is saying in the case of local variables the compiler can determine there is no overlapping access and relax the restriction that access to any member is treated as access to the whole.

But you are using an instance variable of a class. A few paragraphs later Apple states:

Specifically, it can prove that overlapping access to properties of a structure is safe if the following conditions apply:

  • You’re accessing only stored properties of an instance, not computed properties or class properties.

  • The structure is the value of a local variable, not a global variable.

  • The structure is either not captured by any closures, or it’s captured only by nonescaping closures.

And from your code we can say that it appears ", not a global variable" here is not exhaustive, it means anything other than "a local variable".

Of course I say it appears here as we all know that Swift is a loosely defined moving target and its compiler and semantics will probably be different next Tuesday ;-)

HTH



Related Topics



Leave a reply



Submit