is it possible to define your own comparison operator? shall be easy, but how exactly?
my attempt:
infixoperator <> : ComparisonPrecedence
func <> <T: Equatable>(a: T?, b: T?) -> Bool { return a != b
}
func test(a: Error?) {
a <> nil// Binary operator '<>' cannot be applied to operands of type 'Error?' and '_'
(1, 1) <> (0, 0) // Binary operator '<>' cannot be applied to two '(Int, Int)' operands
}
There are a couple of things here.
First, you don't have to write T?, you can use T. It will allow you to compare nil because Optional<T> (which is the actual type for an optional, String? and Optional<String> are the same) can be used as T in your comparison function. If you change your code to:
func <> <T: Equatable>(a: T, b: T) -> Bool {
return a != b
}
You run into a problem that says Error isn't Equatable because protocols (Error is a protocol) can't conform to protocols. So that makes sense.
The second error Binary operator '<>' cannot be applied to two '(Int, Int)' operands won't go away because tuples aren't Equatable either. You'll need a specific overload of <> that accepts tuples:
Note that the error messages on master are more helpful:
operator.swift:8:5: error: value of protocol type 'Error' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols
a <> nil
^
operator.swift:3:6: note: required by operator function '<>' where 'T' = 'Error'
func <> <T: Equatable>(a: T?, b: T?) -> Bool {
^
operator.swift:9:10: error: type '(Int, Int)' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols
(1, 1) <> (0, 0)
^
operator.swift:3:6: note: required by operator function '<>' where 'T' = '(Int, Int)'
func <> <T: Equatable>(a: T?, b: T?) -> Bool {
^
if i did so then i'd have to make all my types equatable even if they don't have to be.
class C {}
var c: C?
c <> nil // Operator function '<>' requires that 'C' conform to 'Equatable'
i also considered having isNil / isNonNil on Optional type to make nil checks more explicit.
this is the working solution i found:
infixoperator <> : ComparisonPrecedence
extension Equatable { staticfunc <> (a: Self, b: Self) -> Bool { return a != b
}
}
extension Optional { staticfunc <> (a: Wrapped?, b: _OptionalNilComparisonType) -> Bool { return a != b
}
staticfunc <> (a: _OptionalNilComparisonType, b: Wrapped?) -> Bool { return a != b
}
}
extension BinaryInteger { staticfunc <> (a: Self, b: Other) -> Bool where Other : BinaryInteger { return a != b
}
}
don't ask what _OptionalNilComparisonType is... i just copied/pasted it from a similar "func !=" of Optional type.
the int functions were needed as otherwise Int(0) <> Int32(0) complained (and it works with the != version)
so tuples are not Equatable even if we can compare them? weird.
this is very unfortunate and not scalable. but in reality in my code base i've encountered only two instances of such tuple types that i compared with !=, so i just changed the comparison to ~(a == b) (~ - is my analog of !)
given these changes now the only instances of ! in my code base are those associated with something unsafe (be it optional unwrap or implicit optionals or unsafe type cast)
That's nice. I'd love to be able to replace != with <> as well. Could you please share the complete working code and all the cases, especially for tuple? Thank you.
I also would like to change &&, ||, and ! with ∧, ∨, and ¬ respectively. If I have to use symbols, I prefer to use the correct symbols.
for infix operations you'd want to specify the precedence.
as for tuples - i don't know how to solve this in a generic manner. my issue was with "!=" and "!" specifically, so when i have this in the code:
someTuple != someTuple2
(which was surprisingly rare) i just changed it to:
~(someTuple == someTuple2)
how do you enter those? i can switch to unicode hex input and type alt + 2227 / 2228, etc - not very convenient. or copy / paste from elsewhere - ditto. i am not very familiar how to make a custom keyboard layout. another way - add those as favourites to Emoji & Symbols window - probably the best one i found so far.
i tried those symbols in the past - not my cup of tea. while i can see a value of making "non screaming" versions of "not" and inequality operators (for example to make those screaming ! more prominent, i'd also like them in red and bold if i could), changing from && to ∧ is probably a step too far on my book.
i got a feeling that others have a similar sentiment in regards to (not) using those non-ascii unicode characters for custom operators. leading us to a situation that that area of swift is not used (and probably wouldn't exist if swift was designed today).
On my keyboard ∨ is four home‐row keystrokes (¤, d, i, s, [...junction]) vs eight much more awkward ones for || (⇪, ⇧⌥¤, ⇧⌥¤, ⇪), so it actually saves me effort. But that is likely not the case for developers who learned their trade in an ANSII‐centric environment.
This seems to be headed off topic, but since it is your own thread, I’ll answer anyway.
It’s a custom layout. (I use too many human languages every day to switch endlessly back and forth.) The ¤ key is a clever dead key that allows me to begin typing the name of a symbol, and as soon as there are enough letters for it to be unambiguous, it is replaced by the symbol itself. It allows punting spellable things like & and @ off of the base layout to make room for more important letters, and it means I don’t really need to remember the locations of infrequently used characters, because I only have to be able to name them. Publishing the code is on my (long) to‐do list.
can not you use "let" for wahr/falsch for some reason?
You can, but I don’t know how stored variables and inlining interoperate across module boundaries. As an @inlinable computed var, it is more certain that the compiler will optimize them back down to just true and false under the hood.
Swift classifies those characters as operators, so they aren’t valid for identifiers. But it was a good idea.
Well that’s embarrassing. Normally so do I.
That code is very old. Since that was written, extensions of unowned types to conform to unowned protocols have proven to be dangerous. I would not have written a Comparable conformance like that today. I haven’t gone to the effort of refactoring it into a wrapper, since I cannot imagine any other ordering for Bool, so it presumably doesn’t matter which conformance is chosen at runtime. But if someone does encounter a bug because of it, it will be dealt with promptly.
Basic, SQL, Visual Basic, ML, Pascal, Simula, Modula-2, AGOL, Eiffel and several others use <> for inequality testing. I think some spreadsheets do as well.
I just uploaded the generator library to GitHub: SDGKeyboardDesign. It isn’t a polished product yet, and it has no documentation, but I’ve seen you around here enough to know you can figure it out on your own. In the interest of responding quickly, I just slapped a copyright notice on it for now, so I can sort out licensing later. But you hereby have permission to put it to personal, non‐commercial use.
In short, initialize a KeyboardLayoutBundle structure however you’d like and call its generate(in:) method to create a layout bundle that can be installed on macOS under Library/Keyboard Layouts and activated in the system preferences. The main initializers do have documentation comments. Specifically, Symbol.key is the key you’ve been asking about. If you have questions, feel free to ask them over on GitHub.