DEV Community

Juan Dorado
Juan Dorado

Posted on

Subscripts: Dynamic Member Lookup

Previously I have about subscripts, a really basic post to get involved with subscripts.

And a second one to see related to their parameters and static ones.

Now, let's see another topic related to them... Dynamic Member Lookup.

First of all, what comes in your mind when you hear about Swift language?

If you think about safety we are just right now on the same path.

One of the greatest features in Swift is that it is a safety language.

Unlike Python or PHP. But hey!, I'm not saying they are not safe, I'm just saying they are relaxed on that aspect.

But don't misunderstand me, everybody can write bad code on any language, it is that we just need to think much more on what we are doing on the code.

Just try to run "Hey Swift" + 5.3 on a playground in Xcode... that's right! it is going to complain as soon as it tries to compile it. (Of course it make sense because how are you going to sum a String with a Double).

Now, it was too much talk!... what is this for? - Answer this is as easy that just say provide arbitrary dot-syntax to your type.

You could be thinking, but Swift already provides dot-syntax - That's true, let's dive in on our example.

Example

struct Character {

  let name: String
  let costume: Costume

  enum Costume: String {
    case `default`
    case stars
    case re3Style
  }
}
Enter fullscreen mode Exit fullscreen mode

We have our struct, and if we create an instance of our struct, we can get the properties using dot-syntax right?.

let jill = Character(name: "Jill Valentine", costume: .re3Style)

jill.name
jill.costume
Enter fullscreen mode Exit fullscreen mode

Let's extend our struct with another property.

struct Character {

  // ...

  let quickSlots: [QuickSlot: String]

  enum QuickSlot {
    case up
    case left
    case right
    case down
  }

  // ...
}
Enter fullscreen mode Exit fullscreen mode

The quick slots in the game will be the shortcuts to access to equipment from our items.

Now we will set this in our initializer

let jill = Character(..., quickSlots: [.up: "Beretta 92FS", .right: "M26 Hand Grenade"])
Enter fullscreen mode Exit fullscreen mode

If we plan to access to the quick slot with the key up, we will need to do something like this.

jill.quickSlots[.up] // Beretta 92FS
jill.quickSlots[.down] // nil
Enter fullscreen mode Exit fullscreen mode

But if I would like to access to them with something like this...

jill.up
jill.down
Enter fullscreen mode Exit fullscreen mode

dot-syntax issue

Here comes the Dynamic Member Lookup

First we need to add this core attributed @dynamicMemberLookup, and to make it work this needs the required subscript method subscript(dynamicMember:)

So our struct will look like this.

@dynamicMemberLookup
struct Character {

  let name: String
  let costume: Costume
  var quickSlots: [QuickSlot: String]

  enum Costume: String {
    case `default`
    case stars
    case re3Style
  }

  enum QuickSlot: String {
    case up
    case left
    case right
    case down
  }

  subscript(dynamicMember key: String) -> String? {
    guard let quickSlotKey = QuickSlot(rawValue: key) else { return nil }
    return quickSlots[quickSlotKey, default: "No Item"]
  }
}
Enter fullscreen mode Exit fullscreen mode

I use : String on the QuickSlot enum to be easier to access by its rawValue

Now if we try to use our previous dot-syntax call we get this.

jill.up // Beretta 92FS
jill.down // No Item
Enter fullscreen mode Exit fullscreen mode

Although this seems great, be careful because you can use whatever dot-syntax variable, even if this doesn't exist.

jill.asdfsdfsdf // nil
Enter fullscreen mode Exit fullscreen mode

dynamicMemberLookup is evaluated at runtime not at compile time.

You can use dynamicMemberLookup for your own purposes but the main one is to interact with codes like Python.

Also as quick tip:

  • You can inherit dynamicMemberLookup from your base class to your children.
  • You can use class subscripts that works such as static subscripts
  • These can be used with keypath (but that will be a topic for other day).

I think this subscript posts work for you!.
It is just practice, so practice, practice, practice.

Happy coding 👨‍💻!

Top comments (0)