0

I am trying to understand property wrappers.

I have another question of mine on SO, where I was trying to create a property wrapper like this:

extension String {

  func findReplace(_ target: String, withString: String) -> String
  {
    return self.replacingOccurrences(of: target,
                                     with: withString,
                                     options: NSString.CompareOptions.literal,
                                     range: nil)
  }
}


  @propertyWrapper
  struct AdjustTextWithAppName<String> {
    private var value: String?


    init(wrappedValue: String?) {
      self.value = wrappedValue
    }

    var wrappedValue: String? {
      get { value }
      set {
        if let localizedAppName = Bundle.main.localizedInfoDictionary?["CFBundleName"] as? String {
          let replaced = value.findReplace("$$$", withString: localizedAppName)

        }
        value = nil
      }
    }

  }

That was not working because the line value.findReplace was showing an error

Value of type String? has no name findReplace

As soon as someone suggested me to change the struct line to

struct AdjustTextWithAppName {

the whole thing started working.

Why? I cannot understand why <String> term on the struct was shadowing the extension to the String type I have created.

Why is that?

Duck
  • 34,902
  • 47
  • 248
  • 470
  • 1
    But this is a duplicate off the [question](https://stackoverflow.com/questions/59965636/trying-to-make-a-wrapper-for-a-property-that-should-adjust-a-string) you asked earlier today, why ask the same thing twice? – Joakim Danielson Jan 29 '20 at 16:50
  • Not a duplicate. In the first question I was trying to understand WHAT was wrong. In this question I am trying to understand WHY. – Duck Jan 29 '20 at 16:52

2 Answers2

1

Replace <String> with the common generic type <T> and you'll see the issue immediately

 @propertyWrapper
  struct AdjustTextWithAppName<T> {
    private var value: T?


    init(wrappedValue: T?) {
      self.value = wrappedValue
    }

    var wrappedValue: T? {
      get { value }
      set {
        if let localizedAppName = Bundle.main.localizedInfoDictionary?["CFBundleName"] as? String {
            let replaced = value.findReplace("$$$", withString: localizedAppName) // Value of type 'T' has no member 'findReplace'

        }
        value = nil
      }
    }
  }

Now the error is more understandable

Value of type 'T' has no member 'findReplace'

vadian
  • 274,689
  • 30
  • 353
  • 361
0

I cannot understand why <String> term on the struct was shadowing the extension to the String type I have created.

Why wouldn't it? You explicitly requested for there to be a generic type parameter to AdjustTextWithAppName called String. The compiler gave you precisely what you asked for.

Alexander
  • 59,041
  • 12
  • 98
  • 151
  • I thought struct created structures, not types. In my mind AdjustTextWithAppName would create a structure called AdjustTextWithAppName of type String, as Array will create an array of strings. Why the same syntax creates two different things is beyond me. – Duck Jan 29 '20 at 16:02
  • 1
    @SpaceDog "Why the same syntax creates two different things is beyond me." you're brute forcing your way through learning Swift by a process of trail, error, frustrated StackOverflow post, reluctantly accepted answer, rinse and repeat. You should spend some times learning the fundamentals, because you'll just stay perpetually stuck in this cycle of frustration. – Alexander Jan 29 '20 at 16:05
  • The keyword `struct` does declare structures. Structures are types, so it obviously also declares types. `In my mind AdjustTextWithAppName would create a structure called AdjustTextWithAppName of type String` Welp, that's simply wrong. The `< >` after a type identifier is a list of generic type parameters. "of type String" would be expressed as a subtype relationship, spelt as `subtype: supertype`, which isn't possible for `String`, because `String` is a struct, and structs can't be subtyped. – Alexander Jan 29 '20 at 16:07
  • `as Array will create an array of strings` By the logic of your statement preceding this one, you would conclude that this should "create a structure called `Array` of type `String`", which doesn't make sense. What's really going on is that `Array` is a struct, with one generic type parameter (called `Element`), declared as `struct Array` ([see for yourself](https://github.com/apple/swift/blob/dd094018dee55a189464b629b79f72a195e14f11/stdlib/public/core/Array.swift#L300)). – Alexander Jan 29 '20 at 16:11
  • I am not doing trial and error. Property wrappers is something I cannot wrap (intentional pun) my head around. The concept is simple but the syntax is lunatic. Lunacy is winning the war in Swift and the syntax is every time more nonsensical. – Duck Jan 29 '20 at 16:12
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/206867/discussion-between-alexander-reinstate-monica-and-spacedog). – Alexander Jan 29 '20 at 16:18