[swift-evolution] String Comparison (was: Strings in Swift 4)
Jonathan Hull
jhull at gbis.com
Tue Jan 24 03:06:22 CST 2017
Breaking this into a different thread…
One suggestion which I haven’t seen (maybe it is too crazy) is the idea of introducing shadowing of operators within a scope (similar to variables).
Now this would need a TON of design work to make it actually work, but the gist would be:
if blah == foo {
//We can override/shadow the ‘<‘ operator within this scope as long as the signature is the same
let (<) = String.comparisonOperation(case: .insensitive, locale: .current) //Here we grab a closure produced by a static function on String
if a < b { //Within this scope < will be case insensitive
//Stuff
}
}
//Outside of the scope, < is back to it’s lovable self
Thoughts on the general idea?
Thanks,
Jon
> I know you want to defer this for now, so feel free to set this part of the email aside, but here's a quick list of solutions I've ballparked:
>
> 1. Your "one operand carries the options" solution.
>
> 2. As I mentioned, do something that effectively overloads comparison operators to return them in a symbolic form. You're right about the ambiguity problem, though.
>
> 3. Like #2, but with slightly modified operators, e.g.:
>
> if localized(fu &< br, case: .insensitive) { … }
>
> 4. Reintroduce something like the old `BooleanType` and have *all* comparisons construct a symbolic form that can be coerced to boolean. This is crazy, but actually probably useful in other places; I once experimented with constructing NSPredicates like this.
>
> protocol BooleanProtocol { var boolValue: Bool { get } }
>
> struct Comparison<Operand: Comparable> {
> var negated: Bool
> var sortOrder: SortOrder
> var left: Operand
> var right: Operand
>
> func evaluate(_ actualSortOrder: SortOrder) -> Bool {
> // There's circularity problems here, because `==` would itself return a `Comparison`,
> // but I think you get the idea.
> return (actualSortOrder == sortOrder) != negated
> }
> }
> extension Comparison: BooleanProtocol {
> var boolValue: Bool {
> return evaluate(left.compared(to: right))
> }
> }
>
> func < <ComparableType: Comparable>(lhs: ComparableType, rhs: ComparableType) -> Comparison {
> return Comparison(negated: false, sortOrder: .before, left: lhs, right: rhs)
> }
> func <= <ComparableType: Comparable>(lhs: ComparableType, rhs: ComparableType) -> Comparison {
> return Comparison(negated: true, sortOrder: .after, left: lhs, right: rhs)
> }
> // etc.
>
> // Now for our special String comparison thing:
> func localized(_ expr: Comparison<String>, case: StringCaseSensitivity? = nil, …) -> Bool {
> return expr.evaluate(expr.left.compare(expr.right, case: case, …))
> }
>
> 5. Actually add some all-new piece of syntax that allows you to add options to an operator. Bad part is that this is ugly and kind of weird; good part is that this could probably be used in other places as well. Strawman example:
>
> // Use:
> if fu < br %(case: .insensitive, locale: .current) { … }
>
> // Definition:
> func < (lhs: String, rhs: String, case: StringCaseSensitivity? = nil, …) -> Bool { … }
>
> 6. Punt on this until we have macros. Once we do, have the function be a macro which alters the comparisons passed to it. Bad part is that this doesn't give us a solution for at least a version or two.
More information about the swift-evolution
mailing list