# Example of attributes with current version of Swift

**URL:** <https://forums.swift.org/t/example-of-attributes-with-current-version-of-swift/15662>\
**Category:** Using Swift\
**Created:** [August 30, 2018, 8:03am UTC](https://forums.swift.org/t/example-of-attributes-with-current-version-of-swift/15662 "2018-08-30T08:03:48Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Joanna\_Carter](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joanna_carter/32/1581_2.png) [@Joanna\_Carter](https://forums.swift.org/u/Joanna_Carter)\
**Post date:** [August 30, 2018, 8:03am UTC](https://forums.swift.org/t/example-of-attributes-with-current-version-of-swift/15662/1 "2018-08-30T08:03:48Z")

</div>

Having seen several posts about the desire for attributes in Swift and having the same desire myself, I thought I would play with implementing something with Swift as it is now.

```swift
public protocol Attribute { }

public protocol Attributable
{
  static func getAttributes() -> [Attribute]
}

public struct Serializable : Attribute
{
  public private(set) var targetType: Any.Type
  
  public init(_ targetType: Any.Type)
  {
    self.targetType = targetType
  }
}

public struct SerializableProperty : Attribute
{
  public private(set) var keyPath: AnyKeyPath
  
  public private(set) var isSerializable: Bool
  
  public init(keyPath: AnyKeyPath, isSerializable: Bool = true)
  {
    self.keyPath = keyPath
    
    self.isSerializable = isSerializable
  }
}

public struct Person
{
  public var firstName: String
  
  public var lastName: String
  
  public var fullname: String
  {
    return "\(firstName) \(lastName)"
  }
}

extension Person : Attributable
{
  public static func getAttributes() -> [Attribute]
  {
    return [
            Serializable(Person.self),
            SerializableProperty(keyPath: \Person.fullname, isSerializable: false)
           ]
  }
}

```

Then, to recover the attributes elsewhere:

```swift
  {
    let testType: Any.Type = Person.self
    
    if let attributableType = testType as? Attributable.Type
    {
      let attributes = attributableType.getAttributes()
      
      for attribute in attributes
      {
        switch attribute
        {
          case let serializableType as Serializable:
            print("\(serializableType.targetType)")
          
          case let serializableProperty as SerializableProperty:
            print("\(serializableProperty.isSerializable) : \(serializableProperty.keyPath)")
          
          default:
            print("default")
        }
      }
    }    
  }

```

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [August 30, 2018, 3:42pm UTC](https://forums.swift.org/t/example-of-attributes-with-current-version-of-swift/15662/2 "2018-08-30T15:42:02Z")

</div>

I've had some thoughts around this area too, though for the purposes of customizing encoding using Codable rather than another mechanism. In that case it seemed interesting to extend CodingKeys:

```swift
extension Person.CodingKeys: CustomTreatmentForMyEncoder {
  func wantsCustomTreatmentForMyEncoder() -> Bool {
    switch self {
    case .firstName: return true
    case .lastName: return false
    }
  }
}

```

But that's limited to coding. I also like the use of key paths in your version, but I can see why the default CodingKeys implementation doesn't do that: most of the time it'd be unnecessary code bloat.

---

<div class="post-metadata">

**Author:** ![Joanna\_Carter](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joanna_carter/32/1581_2.png) [@Joanna\_Carter](https://forums.swift.org/u/Joanna_Carter)\
**Post date:** [August 30, 2018, 5:14pm UTC](https://forums.swift.org/t/example-of-attributes-with-current-version-of-swift/15662/3 "2018-08-30T17:14:28Z")

</div>

Hi Jordan

The problem with explicitly declaring CodingKeys is that, by so doing, you implicitly decide on which properties participate in the Codable process. Therefore, you wouldn't want to use `wantsCustomTreatmentForMyEncoder()` simply for flagging properties as Codable or not. I presume you were thinking of using it for "special" coding?

Anyhow, your idea got me thinking again and here is another technique for my example using the Serializable protocol, which you could use instead of attributes:

```swift
public protocol SerializableProperties
{
  static func isSerializable(for keyPath: AnyKeyPath) -> Bool
}

extension Person : SerializableProperties
{
  public static func isSerializable(for keyPath: AnyKeyPath) -> Bool
  {
    switch keyPath
    {
      case \Person.firstName:
        return true
      case \Person.lastName:
        return true
      case \Person.fullname:
        return false
      default:
        fatalError("keyPath not found")
    }
  }
}

```

Of course, it still doesn't address the feasibility of attributes, but it is an interesting side track 😉

---

<div class="post-metadata">

**Author:** ![Joanna\_Carter](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joanna_carter/32/1581_2.png) [@Joanna\_Carter](https://forums.swift.org/u/Joanna_Carter)\
**Post date:** [August 30, 2018, 5:30pm UTC](https://forums.swift.org/t/example-of-attributes-with-current-version-of-swift/15662/4 "2018-08-30T17:30:25Z")

</div>

Or, to cater for Codable with keypaths, how about this:

```swift
protocol CodableForKeyPaths : Codable
{
  static func isCodable(for keyPath: AnyKeyPath) -> Bool
}

extension Person : CodableForKeyPaths
{
  static func isCodable(for keyPath: AnyKeyPath) -> Bool
  {
    return keyPath == \Person.fullName ? false : true
  }
}
```
