Most these operator discussions seem to go down the same way: "man you can make some really confusing operators, and I hope that doesn't become a thing... but gee writing == is so much nicer than isequalto and can't beat the + operator when adding things together!". People seem convinced that its all or nothing. Lua has such a nice compromise to this: you can overload +, -, ==, etc using special methods (__add, etc.), and you can't overload or create any new operators. Its a completely controlled environment that disarms the "but what if I want to add complex numbers together!" argument while still removing the temptation to create really absurd syntax (which Swift has taken to the next level with emoji).
The Objective-C community also has a language that allows all sorts of weirdness and also (perhaps in part because of that freedom) has a uniquely pervasive emphasis on convention. Wacky stuff is tolerated and even appreciated in the appropriate contexts but generally shunned and avoided otherwise. It seems likely that the Swift community (overlapping in such large part with the Objective-C community) will inherit this.
With regard to Objective-C's ability for weirdness? Its dynamic nature could easily lead to really weird/surprising process flow. It seems like lots of developing Obj-C programmers know about method swizzling but I wouldn't necessarily expect a similarly-experienced C++ programmer to be familiar with such things in practice.
On the conventionality side: Cocoa is known for its consistency in naming and behavior.
Swizzling is a weird one in the community. But if I see #import <objc/runtime.h> something has gone wrong (you have to include that for swizzling and other seemingly dangerous stuff)
Well, C++ has the same restriction and a lot of people's distaste of overloaded operators comes from that language. User-defined operators and overloaded operators are separate features, in fact—OCaml has the former but not the latter.
My personal preference is to allow operator overloading, but to (a) enforce that overloaded operators must have reasonable type signatures (via concepts or similar); (b) restrict overloadable operators to mathematical operators (e.g. not the comma operator), and (c) set a good precedent in the standard libraries and community against using mathematical operators for non-mathematical operations (e.g. don't overload bitshift operators for I/O in the standard libraries).
I for one can't wait to create circular references between objects that then stay alive together for ever and ever using the ❤❤❤ operator.
More seriously, I wonder why user-defined operators are considered any worse than user-defined functions. I mean, I think that they often are, but I wonder why.
Maybe we assume less potential for ambiguity when we read a symbol than when we read a word. The possibility that isEqual: has a bad implementation that doesn't respect transitivity seems more obvious than the possibility that == does.
> I wonder why user-defined operators are considered any worse than user-defined functions.
User-defined functions can take more than two parameters. User-defined operators have one or two parameters (allowing rare exceptions).
User-defined functions can have any signature and specify any contract. To prevent surprises, user-defined operators should return a boolean or a number. Not a Maybe<Number>. Not a return code. Not a LazilyConvertsToFloatWhenYouCopyIt.
That being said, I like user-defined operators and the ability to overload operators. But there are tradeoffs, just like in any engineering decision.
User-defined operators are bad when they betray our expectations of what they should be doing - and by that, I mean if they don't exist in textbooks which are decades/hundreds of years old (and thus, almost universally accepted as part of our languages/cultures), they're gimmicks. That includes =~ for matching regular patterns - nobody would ever expect this to be the case - only someone who has encountered it in an existing language will use it as such.
User defined functions have names that we can understand, because we already share a common language - English. If we started "making up our own words" for functions, then we're doing just as bad as user-defined operators - nobody will recognize what the hell we're doing without looking up their implementations. It's like reading obfusticated code, or code in some language you don't know. If every programmer invents his own operators, good luck ever getting shit done - people don't have the time to learn some arbitrary language you conjure up just for the sake of shaving a few characters off code. Nor should anyone need a PhD in mathematics to understand the strange notations in your examples/proofs.
Operators cannot be searched for in the same way ASCII text can - we need specialized search engines which don't ignore characters - and they generally need to be written on a per-language basis to be useful. I think the time wasted doing this far exceeds the benefits user-defined operators provide.
Also, many unicode characters look alike, and it may be possible to utilize this in malicious ways where arbitrary characters may be used - by assuming someone reading/reviewing code will not look up the code points of every character. Having a limited set of characters makes it pretty simple to distinguish each one, unless you have poor fonts and can't make out differences between 1,I,l etc.
Operators are useful for sure, but they're never necessary. More to the point, they are just functions - treating them specially is silly, because it's much more useful to abstract over functions of any arity than to abstract over only binary functions.
If you watch the video and wondering about the multiple subscripts prepended by '?', this technique is called optional chaining. It also work for properties and methods.
It is kinda similar to how we can invoke methods on 'nil' in Objective-C and not causing any runtime error.
Interesting that the Apple-provided sample app mentioned around 7 minutes in uses "~=" as a custom operator, given that it's already defined for use with pattern matching (match an input with some sort of pattern), and intended to be overloaded for that purpose. I wonder if this is just an oversight?
The pattern matching example he showed from a few other languages uses =~ instead of ~=. This, however, illustrates the potential confusion with operators that appear to be similar at first glance.
13 comments
[ 4.5 ms ] story [ 28.1 ms ] threadOn the conventionality side: Cocoa is known for its consistency in naming and behavior.
Such meta-level code should be encapsulated well and be very useful.
My personal preference is to allow operator overloading, but to (a) enforce that overloaded operators must have reasonable type signatures (via concepts or similar); (b) restrict overloadable operators to mathematical operators (e.g. not the comma operator), and (c) set a good precedent in the standard libraries and community against using mathematical operators for non-mathematical operations (e.g. don't overload bitshift operators for I/O in the standard libraries).
More seriously, I wonder why user-defined operators are considered any worse than user-defined functions. I mean, I think that they often are, but I wonder why.
Maybe we assume less potential for ambiguity when we read a symbol than when we read a word. The possibility that isEqual: has a bad implementation that doesn't respect transitivity seems more obvious than the possibility that == does.
User-defined functions can take more than two parameters. User-defined operators have one or two parameters (allowing rare exceptions).
User-defined functions can have any signature and specify any contract. To prevent surprises, user-defined operators should return a boolean or a number. Not a Maybe<Number>. Not a return code. Not a LazilyConvertsToFloatWhenYouCopyIt.
That being said, I like user-defined operators and the ability to overload operators. But there are tradeoffs, just like in any engineering decision.
User defined functions have names that we can understand, because we already share a common language - English. If we started "making up our own words" for functions, then we're doing just as bad as user-defined operators - nobody will recognize what the hell we're doing without looking up their implementations. It's like reading obfusticated code, or code in some language you don't know. If every programmer invents his own operators, good luck ever getting shit done - people don't have the time to learn some arbitrary language you conjure up just for the sake of shaving a few characters off code. Nor should anyone need a PhD in mathematics to understand the strange notations in your examples/proofs.
Operators cannot be searched for in the same way ASCII text can - we need specialized search engines which don't ignore characters - and they generally need to be written on a per-language basis to be useful. I think the time wasted doing this far exceeds the benefits user-defined operators provide.
Also, many unicode characters look alike, and it may be possible to utilize this in malicious ways where arbitrary characters may be used - by assuming someone reading/reviewing code will not look up the code points of every character. Having a limited set of characters makes it pretty simple to distinguish each one, unless you have poor fonts and can't make out differences between 1,I,l etc.
Operators are useful for sure, but they're never necessary. More to the point, they are just functions - treating them specially is silly, because it's much more useful to abstract over functions of any arity than to abstract over only binary functions.
It is kinda similar to how we can invoke methods on 'nil' in Objective-C and not causing any runtime error.
Just stating if anyone is wondering.