back
74 comments
Explicit optionals are great. But I feel some of the other convenience features like type inference, trailing closures, different copy behavior of arrays, and operator overloading have the potential of being abused to produce cryptic code. What's your opinion?
Maybe I'm just lucky, but I've never seen operator overloading abused, and I've written my fair share of C++. Bad developers usually don't learn about these things in the first place, they just spew mountains of poorly-abstracted code.

Ruby lets you do far worse things if you dig deep enough, but nobody ever complains about that.

I've always thought of the stdlib overloading of << in streams to be, well, maybe not an abuse on the scale you see in the obfuscated C contests but at least a place where operator overloading makes code harder to read and understand.
Honestly, I can see why C++ overrode it in the first place though - does anybody really give a crap about the "<<" operator? Why does a language need to dedicate a whole operator to bitshifting?

I assume Stroustrup et al took a look at the meaningless "<<" and decided it was available for whatever use they saw fit.

Slight counter point re: ruby, I complain A LOT about ruby's and the communities tendency to monkey patch everything. It's a dangerous practice that needs to be REALLY well thought out. just like C++ and the operator overloading, I've had bad and good experiences with both. I don't think they need to be removed from the languages but I do think good experienced developers should loudly and quite often proclaim the dangers of over use.
I'm with you there. I hate when anything extends built-in types. Since all code uses built-in types, you can quickly end up in debugging hell.
I think it comes down to culture, not language features.

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.

> Ruby lets you do far worse things if you dig deep enough, but nobody ever complains about that.

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.

Trailing closures turn out to be magic when creating APIs and mini-DSLs. That slight reduction of friction that unifies regular language syntax with user-defined functions is often the difference between a high usable extension and a kludge.
Do you happen to have any good examples? They look like a great feature but I'm less familiar with how they've already been used in other languages.
Scala is full of many libraries that take advantage of trailing closures. I think their standard library Future/Promise API is good example: http://docs.scala-lang.org/overviews/core/futures.html

Edit: Another popular one is the ScalaTest unit testing framework: http://www.scalatest.org

Take a look at one of the tutorials on writing a Ruby DSL. E.g. http://rubylearning.com/blog/2010/11/30/how-do-i-build-dsls-...
I think Ruby is the major banner-carrier for this feature. It is actually more awkward in Ruby to have non-trailing closures.
The latter two, yes. Operator overloading is a loaded gun and you need to make sure you aim carefully. And Array identity and mutability semantics are just straight-up broken. But type inference tends to be good for readability in my experience, and trailing closures seem clear enough that I don't see how they have any more potential for abuse than anything else.
Operator overloading can potentially be abused because in Swift you are not limited to standard operators like in C++.

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.

I think the danger of abuse is stronger when you overload existing operators than when you make up new ones. The latter can't fool you on its semantic and behavior.
I bet we will see some interesting examples of fooling in obfuscated Swift contests.

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]

I don't know whether this is reassuring or worrying, but Haskell has long (always?) pursued this strategy of allowing even more flexible operator names. From http://www.haskell.org/onlinereport/lexemes.html:

> 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
They go so far that the operator name can even be prefixed by the lexeme (?) for single-line comments (--) :)

> (--|) = (+)

I'm quite fond of being able to define new operators. Particularly in functional languages, it allows you to effectively extend the language. For example, F#'s designers didn't include the usual monad operators. It's easy enough to define your own >>=, though, so life is still good. Similarly, ML developers can create their own forward application ( |> ) operator to also get good access to a useful feature that isn't included by default.

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.

> Operator overloading can potentially be abused because in Swift you are not limited to standard operators like in C++.

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.

Any language feature has the potential to be abused to create cryptic code.
Sure, the effect of operator overloading is no different than that of using undescriptive names. Except with operator overloading, the name is almost guaranteed to be undescriptive.
To reductio ad absurdum, we shouldn't even include arithmetic operators for numerical types because of ambiguities regarding truncating decimal places. After all, myInt1 / myInt2 is dangerously undescriptive so really all integer division should use

Math.DivideToFloat(myInt1, myInt1) or Math.DivideToInteger(myInt1, myInt2)

I must disagree strongly. With operator overloading, the name is guaranteed to be highly descriptive. Think about all that's implied by something as simple as + or /. They might seem superficially undescriptive, but they carry a lot of context due to the huge amounts of history these symbols have.

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.

Language design has to balance expressiveness with maintainability, and there is absolutely no question that some additions lean far more to the former than the latter.

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 can certainly understand how that sentiment arose back in the dark ages of early operator-overloading abuse.

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?
It's true that I can't provide evidence that scientific computing NEEDS operating overloading beyond my own anecdotal experience. However, I've also never seen any support that operator overloading muddies code, besides other people's anecdotal experience.

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)
Do you prefer the C library interface for working on strings to the way that Java handles them, then?

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.

Operator overloading is really, really good if you're writing numerical code. It's sad that people abused it enough to give it a bad reputation.
Of course they do. But as long as the standard libraries restrain them selves, the culture of the language shouldn't go overboard (I hope).
This fear should be reserved for language features which effectively require cryptic code to be useful. For example, Perl's large family of built-in variables with bizarre symbols for names, or the proliferation of redundant and nested template types for things like iterators in C++ before C++11 added type inference.

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.

>>For example, Perl's large family of built-in variables with bizarre symbols for names

There has been "use English;" since at least Perl 5.8, which is about a decade old iirc.

How would you even be able to abuse inference? If someone leaves some types to be inferred and someone reading that code is confused, the compiler already knows the type of the function so it should be able to spit it out for him in something like a REPL or even to 'inline' it in the source code.

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.

I've known some developers who were uncomfortable with abstraction in general, and like to have everything be as explicit as possible. So when reading code along the lines of:

    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.

Here's what I had in mind. Let's say class S is subclass of class C. Now,

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.

I guess inference can be used to mask some smelliness of deeply nested generics. It seems FUD-like to raise these types of concerns solely in the abstract, though.
Thanks for posting that. I don't know if it was the HN Hug of Death or a coincidence or what, but the VPS spiked to 100% CPU and became completely unresponsive, even in the console accessed through the host's web panel. A reboot has fixed it... for now.
It's back up now
Don't know whether it's just because a lot of the library code hasn't been fully moved to this model yet, but I'm still finding most (possibly all) of the iOS API code to use the same error:&error) approach that Objective C uses.
Approximately none of the iOS APIs have been adjusted for Swift yet.

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.

I'm guessing you're right. Their veil of internal secrecy wasn't lifted until very recently, and their design does signal a longer-term transition is in play.

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....

That's because all of the existing frameworks are written in Objective-C. Rewriting the frameworks in Swift is probably an even bigger undertaking than the Swift language itself (and one can't just change the frameworks to fit Swift's idioms for compatibility reasons).
It's a small thing but I think let/var deserved a mention too (my C code is littered with const everywhere).
He did say he was going to write a series of articles about Swift. Give him time. :-)

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.)

Scala, Ocaml, SML, Haskell, Swift, C# (the Nullable type) and many other languages have Optionals/Maybes/Nullable types (all names for the same thing).

I agree Optional's should booster safety (in the iOS/OS X world) if Swift can convince everyone to start using them.

People are probably most familiar with them, I think, in the form of Haskell's Maybe monad. (Though that has the extra feature of black-holing computations that try to operate on Nothing.)