Ramsay Consulting
Ramsay Consulting

Reputation: 593

Can one set a "computed constant" in a Swift `struct`?

For convenience in naming constants I would like to do the following in Swift (my real case is less trivial) so I could refer to IntegerConstants.SIX in later code. However, SIX cannot be given a value because ONE and TWO do not have values till the struct has been initialized .. bit of a "Catch-22"

struct IntegerConstants {
   let ONE = 1.0
   let TWO = 2.0
   let SIX = (ONE + TWO) * TWO
}

Is there a way to do this, or an equivalent that creates a named constant of the form "GROUP.VALUE", that I have not yet discovered?

Upvotes: 6

Views: 2451

Answers (3)

GetSwifty
GetSwifty

Reputation: 7746

You have two (good) options here as far as I'm concerned.

  1. make it a computed property. This is pretty common for this type of thing, the only downside is the calculation is done every time the property is accessed, but as long as it's cheep it shouldn't be a big problem.

    struct IntegerConstants {
        let ONE = 1.0
        let TWO = 2.0
        var SIX: Double {
           get { return (ONE + TWO) * TWO }
        }
    }
    
  2. Move your constants outside the struct to be global. This will be identical in behavior to what you want to do, but it adds additional constants.

    fileprivate let ONE_CONST = 1.0
    fileprivate let TWO_CONST = 2.0
    struct IntegerConstants {
        let ONE = ONE_CONST
        let TWO = TWO_CONST
        let SIX = (ONE_CONST + TWO_CONST) * TWO_CONST
    }
    

    or

    fileprivate let ONE_CONST = 1.0
    fileprivate let TWO_CONST = 2.0
    fileprivate let SIX_CONST = (ONE_CONST + TWO_CONST) * TWO_CONST
    
    struct IntegerConstants {
        let ONE = ONE_CONST
        let TWO = TWO_CONST
        let SIX = SIX_CONST
    }
    

Upvotes: 3

John Montgomery
John Montgomery

Reputation: 7096

If you're using this to group constants, as with IntegerConstants.six, what you actually want to do is make them static. This also solves your error since you don't need to access a self.

struct IntegerConstants {
    static let one = 1
    static let two = 2
    static let six = (one + two) * two
}

Upvotes: 3

Alexander
Alexander

Reputation: 63157

You sure can, but you need to do it in an initializer:

struct IntegerConstants {
   let ONE = 1.0
   let TWO = 2.0
   let SIX: Double

   init() {
        SIX = (ONE + TWO) * TWO
    }
}

But there are a few really big issues with this code.

  1. The IntegerConstants struct actually contains Doubles
  2. Constants like this should be static. There's no reason for them to be bound to an instance.
  3. Given that this struct should now only contain static members, making instances of it wouldn't make much sense, so it should be switched to a case-less enum, so that no instances of it can be made.
  4. Swift follows the convention of Using UpperCamelCase for static members and types. You should follow that INSTEAD_OF_USING_YELLING_CASE.
  5. The IntegerConstants struct and its members should not even exist in the first place. Just use the literals directly! IntegerConstants.SIX does not solve the magic number issue. It's just a terrible way of way of just saying 6.

Upvotes: 2

Related Questions