Is a Static Boolean a Reference Type in Swift

Is a static boolean a reference type in Swift?

Bool is a struct in Swift; structs are value types. It doesn't matter if it's static var, class var, let, var, etc., the type is what matters--so no, Bool is value type.

I think you are not 100% on all of the terminology (mostly because Apple doesn't really cover it much in documentation as usual, lol).

There are "Swift Types" (Bool, Int, your classes/structs, etc), and "Variable/Constant Types" (which hold data in a memory register, such as references or actual-values), as well as "Memory Register Write/Read Types" (variable vs vonstant, mutable vs immutable, var vs let).

Don't be frustrated.. It's a bit confusing for everyone... Especially at first and without great documentation. (I tried learning C++ pointers early age and it was way over my head).

Here's a good reference material: (towards the bottom)
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html

Basically, if you want to hold a reference to something, you have to use a Reference Type memory register. This means using a class instance Static makes no difference:

/* Test1: */

struct Hi {
static var sup = "hey"
}

var z = Hi.sup
Hi.sup = "yo"

print(z) // prints "hey"

/* Test 2: */

class Hi2 {
static var sup = "hey"
}

var z2 = Hi2.sup
Hi2.sup = "yo"

print(z2) // Prints "hey"

If you feel like you need a pointer to something that isn't inside of a class, then you can use UnsafeMutablePointer or something like that from OBJc code.

Or, you can wrap a bool inside of a class object (which are always references).

final class RefBool {
var val: Bool
init(_ value: Bool) { val = value }
}

And here is some interesting behavior for reference types using let:

let someBool: RefBool

someBool = RefBool(true)
someBool = RefBool(false) // wont compile.. someBool is a `let`
someBool.val = false // will compile because of reference type and member is `var`

How to pass a reference to a Boolean rather than its value?

I gave you partially wrong information the other day ( I was having a brain fart), and need to apologize for that. I had overlooked something in my testing...

Here is what you need if you don't want to make the RefBool instances as I suggested (requires more legwork, not recommended):

/// Mutates a boolean:
func toggle(_ boolean: inout Bool) -> Bool {
boolean ? (boolean = false) : (boolean = true)
return boolean
}

/// Static state manager for Booleans
struct IsOn {

private static var
_previewAudio = false,
_previewVisual = false,
_timerDisplal = false,
_quickStart = false

enum State { case toggle, get }

static func previewAudio(_ toggleVal: State = .get) -> Bool {
if toggleVal == .toggle { toggle(&_previewAudio) }; return _previewAudio
}

// ... others
}

Testing:

let referenceToPA = IsOn.previewAudio

print ( IsOn.previewAudio() ) // False (default pram works)
print ( referenceToPA(.get) ) // False (can't use default pram)

referenceToPA(.toggle)

print ( IsOn.previewAudio() ) // True
print ( referenceToPA(.get) ) // True

IsOn.previewAudio(.toggle)

print ( IsOn.previewAudio() ) // False
print ( referenceToPA(.get) ) // False



But honestly, it would be easier to just do the RefBool from my other answer, then you wouldn't need the enum or the functions:

/// Holds a boolean in .val:
final class RefBool { var val: Bool; init(_ boolean: Bool) { val = boolean } }

/// Static state manager for Booleans
struct IsOn {
static var
previewAudio = RefBool(false),
previewVisual = RefBool(false),
timerDisplal = RefBool(false),
quickStart = RefBool(false)
}

Convenience Funcs (not necessary):

/// Mutates a boolean:
func toggle(_ boolean: inout Bool) -> Bool {
boolean ? (boolean = false) : (boolean = true)
return boolean
}

/// Mutates .val:
func toggle(_ refBool: RefBool) -> Bool {
refBool.val ? (refBool.val = false) : (refBool.val = true)
return refBool.val
}

Testing2:

let refToPA = IsOn.previewAudio

refToPA.val = true

print(refToPA.val) // true
print(IsOn.previewAudio.val) // true

toggle(&refToPA.val)

print(refToPA.val) // false
print(IsOn.previewAudio.val) // false

toggle(refToPA) // Using our fancy second toggle

print(refToPA.val) // true
print(IsOn.previewAudio.val) // true

When to use static constant and variable in Swift?

When you define a static var/let into a class (or struct), that information will be shared among all the instances (or values).

Sharing information

class Animal {
static var nums = 0

init() {
Animal.nums += 1
}
}

let dog = Animal()
Animal.nums // 1
let cat = Animal()
Animal.nums // 2

As you can see here, I created 2 separate instances of Animal but both do share the same static variable nums.

Singleton

Often a static constant is used to adopt the Singleton pattern. In this case we want no more than 1 instance of a class to be allocated.
To do that we save the reference to the shared instance inside a constant and we do hide the initializer.

class Singleton {
static let sharedInstance = Singleton()

private init() { }

func doSomething() { }
}

Now when we need the Singleton instance we write

Singleton.sharedInstance.doSomething()
Singleton.sharedInstance.doSomething()
Singleton.sharedInstance.doSomething()

This approach does allow us to use always the same instance, even in different points of the app.

Swift: Boolean value remains the same for all instances of class despite assignments in for loop

What happened

You only made one instance. You then made an array that contains 80 references to that single instance. See for yourself, try:

for shoe in shoes {
print(ObjectIdentifier(shoe))
}

You'll see that all references point to a singular object.

What you're probably looking for

is this:

let shoes = (0..<80).map { _ in ShoeInfo() }

The map call will invoke the closure once for each of the 80 integers in the range 0..<80, which will cause 80 distinct shoe objects to be instantiated.

Helpful background

Array(repeating:_count:_) takes its parameters by value (notice there's no inout). Thus, when you call it, whatever you pass as an argument to the repeating parameter, gets copied.

For classes, "copying" entails making a new references to the exact same heap allocated object. It's also usually retained in the process (increasing its reference count by one), but that's not important here. Thus, when you called Array(repeating: ShoeInfo(), count: 80), only a single ShoeInfo instance was made, and the code then copied it 80 times, meaning it made 80 copied references to the same one instance.

For structs, "copying" entails fully copying them, member-wise. When you tried Array(repeating: ShoeInfoAsAStruct(), count: 80), you would be creating one ShoeInfoAsAStruct(), which would then be copied into each of the 80 slots of the array, causing 80 full copies. You end up with 80 distinct copies at the end, each of which you can edit separately. That's why switching to a struct worked.

Is Swift Pass By Value or Pass By Reference

Types of Things in Swift

The rule is:

  • Class instances are reference types (i.e. your reference to a class instance is effectively a pointer)

  • Functions are reference types

  • Everything else is a value type; "everything else" simply means instances of structs and instances of enums, because that's all there is in Swift. Arrays and strings are struct instances, for example. You can pass a reference to one of those things (as a function argument) by using inout and taking the address, as newacct has pointed out. But the type is itself a value type.

What Reference Types Mean For You

A reference type object is special in practice because:

  • Mere assignment or passing to function can yield multiple references to the same object

  • The object itself is mutable even if the reference to it is a constant (let, either explicit or implied).

  • A mutation to the object affects that object as seen by all references to it.

Those can be dangers, so keep an eye out. On the other hand, passing a reference type is clearly efficient because only a pointer is copied and passed, which is trivial.

What Value Types Mean For You

Clearly, passing a value type is "safer", and let means what it says: you can't mutate a struct instance or enum instance through a let reference. On the other hand, that safety is achieved by making a separate copy of the value, isn't it? Doesn't that make passing a value type potentially expensive?

Well, yes and no. It isn't as bad as you might think. As Nate Cook has said, passing a value type does not necessarily imply copying, because let (explicit or implied) guarantees immutability so there's no need to copy anything. And even passing into a var reference doesn't mean that things will be copied, only that they can be if necessary (because there's a mutation). The docs specifically advise you not to get your knickers in a twist.

What is DarwinBoolean type in Swift

Short answer:

  • Bool is the native Swift type for truth values.
  • DarwinBoolean is the Swift mapping of the "historic" C type Boolean.
  • ObjCBool is the Swift mapping of the Objective-C type BOOL.

You would use Bool in your Swift code unless one of the other types
is required for interoperability with existing Core Foundation or
Objective-C functions.


More about DarwinBoolean:
DarwinBoolean is defined in Swift as

/// The `Boolean` type declared in MacTypes.h and used throughout Core
/// Foundation.
///
/// The C type is a typedef for `unsigned char`.
public struct DarwinBoolean : BooleanType, BooleanLiteralConvertible {
public init(_ value: Bool)
/// The value of `self`, expressed as a `Bool`.
public var boolValue: Bool { get }
/// Create an instance initialized to `value`.
public init(booleanLiteral value: Bool)
}

and is the Swift mapping of the "historic" C type Boolean from
MacTypes.h:

/********************************************************************************

Boolean types and values

Boolean Mac OS historic type, sizeof(Boolean)==1
bool Defined in stdbool.h, ISO C/C++ standard type
false Now defined in stdbool.h
true Now defined in stdbool.h

*********************************************************************************/
typedef unsigned char Boolean;

See also the Xcode 7 Release Notes:

The type Boolean in MacTypes.h is imported as Bool in contexts that
allow bridging between Swift and Objective-C types.

In cases where the representation is significant, Boolean is imported
as a distinct DarwinBoolean type, which is BooleanLiteralConvertible
and can be used in conditions (much like the ObjCBool type).
(19013551)

As an example, the functions

void myFunc1(Boolean b);
void myFunc2(Boolean *b);

are imported to Swift as

public func myFunc1(b: Bool)
public func myFunc2(b: UnsafeMutablePointer<DarwinBoolean>)

In myFunc1 there is an automatic conversion between the native
Swift type Bool and the Mac Type Boolean.
This is not possible in myFunc2 because the address of a variable
is passed around, here DarwinBoolean is exactly the Mac Type Boolean.

In previous versions of Swift – if I remember correctly – this mapped
type was called Boolean, and has been renamed to DarwinBoolean later.


More about ObjCBool:
ObjCBool is the Swift mapping of the Objective-C type BOOL,
this can be signed char or the C/C++ bool type, depending on the
architecture. For example, the NSFileManager method

- (BOOL)fileExistsAtPath:(NSString *)path
isDirectory:(BOOL *)isDirectory

is imported to Swift as

func fileExistsAtPath(_ path: String,
isDirectory isDirectory: UnsafeMutablePointer<ObjCBool>) -> Bool

Here the BOOL return value is converted to Bool automatically,
but the (BOOL *) is kept as UnsafeMutablePointer<ObjCBool>
because it is the address of a variable.

Is it possible to alter a bool value by calling an extension method on the same variable in c#?

You can do it by accepting the this bool object by reference:

public static class Utilities
{
//-----------------------------vvv
public static void Toggle(this ref bool variable)
{
variable = !variable;
}
}

class Program
{
static void Main(string[] args)
{
bool b1 = true;
Console.WriteLine("before: " + b1);
b1.Toggle();
Console.WriteLine("after: " + b1);
}
}

Output:

before: True
after: False

Note: this feature is available only from C# 7.2. See here.

Difference between == and ===

In short:

== operator checks if their instance values are equal, "equal to"

=== operator checks if the references point the same instance, "identical to"

Long Answer:

Classes are reference types, it is possible for multiple constants and variables to refer to the same single instance of a class behind the scenes. Class references stay in Run Time Stack (RTS) and their instances stay in Heap area of Memory. When you control equality with == it means if their instances are equal to each other. It doesn't need to be same instance to be equal. For this you need to provide a equality criteria to your custom class. By default, custom classes and structures do not receive a default implementation of the equivalence operators, known as the “equal to” operator == and “not equal to” operator != . To do this your custom class needs to conform Equatable protocol and it's static func == (lhs:, rhs:) -> Bool function

Let's look at example:

class Person : Equatable {
let ssn: Int
let name: String

init(ssn: Int, name: String) {
self.ssn = ssn
self.name = name
}

static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.ssn == rhs.ssn
}
}

P.S.: Since ssn(social security number) is a unique number, you don't need to compare if their name are equal or not.

let person1 = Person(ssn: 5, name: "Bob")
let person2 = Person(ssn: 5, name: "Bob")

if person1 == person2 {
print("the two instances are equal!")
}

Although person1 and person2 references point two different instances in Heap area, their instances are equal because their ssn numbers are equal. So the output will be the two instance are equal!

if person1 === person2 {
//It does not enter here
} else {
print("the two instances are not identical!")
}

=== operator checks if the references point the same instance, "identical to". Since person1 and person2 have two different instance in Heap area, they are not identical and the output the two instance are not identical!

let person3 = person1

P.S: Classes are reference types and person1's reference is copied to person3 with this assignment operation, thus both references point the same instance in Heap area.

if person3 === person1 {
print("the two instances are identical!")
}

They are identical and the output will be the two instances are identical!

Accessing a static struct conforming to a protocol via an enum

To quote another related SO (Cannot assign to property: function call returns immutable value)

This is compiler's way of telling you that the modification of the struct is useless

If you want to have the same object passed to you when you call that function, you should use classes.

structs are value types whereas classes are reference types

This means that if you get a reference to a class (i.e. your ofType function) and you change it, it gets changed on its actual object (your perfInfo location object).

But when you use structs, your ofType function returns a copy of your perfInfo location object, so even if the compiler allows changing of isEnabled, it only gets changed in your copy, not on the main object.

Your fix is simple: just change the structs into classes. That's all.



Related Topics



Leave a reply



Submit