Ruby lets you do far worse things if you dig deep enough, but nobody ever complains about that.
I assume Stroustrup et al took a look at the meaningless "<<" and decided it was available for whatever use they saw fit.
Objective-C allows much the same monkey-patching craziness as Ruby, but the feature is almost always used to just add additional convenience methods to system classes in a fairly safe and sane manner.
You can do much worse (and I certainly have), but it's pretty rare.
Well, people _used_ to, but we developed cultural tendencies to reduce those kinds of issues. The last time I was bit by a bug like this was years ago.
Edit: Another popular one is the ScalaTest unit testing framework: http://www.scalatest.org
https://developer.apple.com/library/prerelease/ios/documenta...
According to the documentation you can declare an operator composed by an arbitrary list of this characters "/ = - + * % < > ! & | ^ . ~". You can recreate C++ stream operators (<<, >>), Ruby combined comparison (<=>), and so on.
For example one can define operators called <>, =<, =>, and !=
You can do interesting stuff with pre- and suffix operators, too. For example, the XML comments <!-- and --> could be a prefix- and suffix operator pair.
Also, you could define operators that look conspicuously like comments, at least to some of your readers.
[disclaimer: I don't have access to the code; I just read the documentation. That documentation seems to imply that // starts a comment _and_ can be used to implement a custom operator. Even if that isn't possible (fairly likely, I would say, you can still try using --- or /// as your operator]
> Operator symbols are formed from one or more symbol characters, as defined above …
where 'above' is:
symbol -> ascSymbol | uniSymbol<special | _ | : | " | '>
ascSymbol -> ! | # | $ | % | & | * | + | . | / | < | = | > | ? | @
| \ | ^ | | | - | ~
uniSymbol -> any Unicode symbol or punctuation> (--|) = (+)
In languages that don't allow you to overload operators at all, the alternative is to use explicit function syntax. That can sometimes be a short path unreadable to code that's littered with pyramids of doom.
In languages that only allow you to overload existing operators, you end up with monstrosities like C++'s << and >> operators, which overload the bit-shift operators with new and completely unrelated semantics. It's that kind of shenanigans that give operator overloading such a bad name.
It is both a blessing and a curse, as far as potential for abuse is concerned.
You pointed out the downside of arbitrary operator names. The downside of operator overloading on fixed operator names is that you are limited in your choice of operators, so instead of choosing a more distinct operator, you sometimes have to go with things that are kind-of-the-same, or maybe not close at all. And instead you also have the problem of misleading people, for example by using the +-operator for set union, while the reader thinks you are adding together numbers.
Math.DivideToFloat(myInt1, myInt1) or Math.DivideToInteger(myInt1, myInt2)
The problem with operator overloading isn't a lack of descriptiveness, but using them for things they don't describe. If you overload / to perform network IO or something, the problem isn't that / is an undescriptive name, the problem is that it means "numeric division". It's no different than if you wrote a function called "divide" that did network IO.
Operator overloading, as mentioned, is something that seems fantastic when you're banging out a bunch of code. When you return to that code a month later, however, with no context, it leads to mystery code with completely undefined behavior without tracing back through every constituent. We constantly see people make the (unsupported) claim that scientific coding simply needs operator overloading, and while I can't speak specifically to that industry, in the financial industry operator overloading is how you end up with terrible, mystery-meat code.
I'm starting to wonder, however, whether the horror stories are continuing to propagate long after anyone has seen a real, living monster.
If I'm browsing someone else's code today in a modern development environment and I encounter a function I don't know it's generally pretty easy to navigate to the definition (if it's in the codebase) or documentation (if it's not).
If operator overloading is just a function with a name that happens to be a string of symbols and with infix application at the call site, can't I find out about it just as easily?
What's the difference between
myMysteryFunction(a,b)
and a + b
…if I know that the type of a and b isn't something ordinary like an int or a float?The simple example I always come back to is how hard it is to find the bug in the following code:
divide(add(multiply(-1,b),multiply(-1,sqrt(add(multiply(b,b),multiply(multiply(-3,a),c))))),multiply(2,a))
versus finding the same bug operator overloaded version (-b-sqrt(b^2-3*a*c))/(2*a)After all, Java allows statements like "string3 = string1 + string2;", which is much more ambiguous than C's "strcpy( string3, string1 ); strcat( string3, string2 );" (or a modern equivalent where those functions are namespaced in a string class).
I work on 3D games. Sometimes I work in languages (c++, c#, shader languages) that allow me to use operator overloading (and thus infix notation) for 3D vectors and matrices. And sometimes I work in languages (actionscript, java, javascript) that don't allow me to use operator overloading and infix notation for vector and matrix math.
The code in the latter set of languages is much, much, much less readable by nearly any reasonable measure.
For features which just allow cryptic code, it's basically the fear that you won't be able to resist it, or that other people won't. People who want to write cryptic code will figure out how to do it no matter what language they use and what features it has. The solution is to either educate them or not work with their code, not try to restrict languages in a vain attempt to make it impossible to write bad code in them.
There has been "use English;" since at least Perl 5.8, which is about a decade old iirc.
Maybe you mean that people should write some types as some kind of assertion in case the code changes (and it compiles again, coincidentally because the change produced valid but different types, somehow)? I guess the same could be said for always putting certain assertions in the code in order to make sure that assumptions are sound, for example putting "@Override" on all methods that are intended to be overrided methods in Java. And again, since types are inferred, I guess it is conceivable that it can be automated like a code-style thing as a hook, since the compiler knows the type.
var employee = employeeRepository.Get(12345);
return employee.Name;
they'll see the code as untrustworthy because without an explicit type name, you've got no idea what kind of thing 'employee' is.I suppose there's also the 'making excessive generics too easy' issue, though personally I'm not certain that excessive generics are necessarily so terrible. Oftentimes the alternative is to litter your codebase with a bunch of one-off classes that bloat the codebase without adding any value. I think I side with the camp that cites that practice as one of the things that used to really suck about working in Java.
var myVariable = S()
when changed to
var myVariable = C()
will not cause any compiler error in rest of the code. Still, it may be a logical requirement for myVariable to hold instances of type S only. Yes, the programmer can explicitly declare type if s/he wants to, but I guess apple APIs will promote the culture of using type inference. Though hopefully apple will set the best tone possible of swift coding style in their APIs.
Also, at least for Swift 1.0, they won't be. Swift does not guarantee a stable ABI right now or for 1.0. They guarantee binary compatibility with the OS, and ABI compatibility with any application frameworks that are compiled alongside the application (because, well, those can't change), but no compatibility between frameworks and applications. The only way to get that compatibility is to stick to Obj-C APIs (or, well, pure C APIs, but that's no better).
What this means is system frameworks will not be able to take advantage of things like generics or multiple return types until sometime in the future, past Swift 1.0. Of course, they couldn't justify doing that today anyway, because they need to maintain Obj-C compatibility for all of the Obj-C code that still exists.
The real work of modernizing the libraries probably began only after WWDC.
There was a job listing posted to llvm-dev after the keynote that gives a few clues.
http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-June/073669....
The main "aha" point of this article for me was the way optional values eliminate a whole class of programming errors that are pervasive in the "C family" of languages, and does so in a rather elegant way. (Apparently Scala has a similar capability, but I'm not familiar with Scala.)
I agree Optional's should booster safety (in the iOS/OS X world) if Swift can convince everyone to start using them.