Swift: Priority for the user operator relative to the point (".") Literal

In Swift 3, I wrote a custom operator, the prefix operator § , which I use in a method that takes a String value as it returns a LocalizedString structure (holding down the key and value).

 public prefix func §(key: String) -> LocalizedString { return LocalizedString(key: key) } public struct LocalizedString { public var key: String public var value: String public init(key: String) { let translated = translate(using: key) // assume we have this self.key = key self.value = translated ?? "!!\(key)!!" } } 

(Yes, I know about the awesome L10n enum in SwiftGen , but we are loading our lines from our backend, and this question is more about how to work with custom operators)

But what if we want to get the translated value from the result of the § operator (i.e., the value property from the resulting LocalizedString )

 let translation = §"MyKey".value // Compile error "Value of type 'String' has no member 'value'" 

We can, of course, easily fix this compilation error by crushing it in brackets (§"MyKey").value . But if you do not want to do this. Is it possible to set priority for user statements in relation to a literal ?

Yes, I know that only infix operators can declare priority, but it would be advisable to somehow work with priority in order to achieve what I want:

 precedencegroup Localization { higherThan: DotPrecedence } // There is no such group as "Dot" prefix operator §: Localization 

To note that the Swift compiler must first evaluate §"MyKey" and understand that this is not a string, but actually a LocalizedString (struct).

Feels that this is impossible? What am I missing?

+5
source share
1 answer

. It is not an operator, like all others defined in the standard library, but it is provided by the compiler. Grammar for him Explicit expressions of members .

Having a higher priority than . is not a compiler allowing you to do this, since it is such a fundamental use case. Imagine what you could do if the compiler included such a thing:

 -"Test".characters.count 

If you may have a higher priority than . , the compiler should check all the possibilities:

 (-"Test").characters.count // func -(s: String) -> String (-("Test".characters)).count // func -(s: String.CharacterView) -> String.CharacterView -("Test".characters.count) // func -(s: Int) -> Int 

What will happen

  • Potentially increase compilation time.
  • Be ambiguous
  • Perhaps changing the behavior of existing code when adding overloads

What I suggest you do is to abandon the idea using the new operator, it will only add more cognitive load, suppressing some specific behavior into one obscure character. Here's how I do it:

 extension String { var translatedString : String { return translate(using: self) } } "MyKey".localizedString 

Or if you want to use LocalizedString :

 extension String { var localized : LocalizedString { return LocalizedString(key: self) } } "MyKey".localized.value 

These versions are much more complete.

+5
source

Source: https://habr.com/ru/post/1260712/


All Articles