Hacker News new | comments | show | ask | jobs | submit login
Go Home Swift Compiler, You’re Drunk (atomicobject.com)
144 points by micahalles on Apr 26, 2016 | hide | past | web | favorite | 28 comments

(FWIW, I just pushed a fix for this bug.)

EDIT: To be clear, addressing these kinds of issues is something we've been aggressively pursuing for Swift 3, and will continue to do so.

Is this construct commonly used in swift or is it an edge case? I've seen people referring to it as an edge case, but at the same time this is code which I find my self writing pretty often in other languages, for example when initializing data for unit tests.

The problem, by the way, is that the use of nested literals (string and dictionary, here) causes the compiler to do a very large search to resolve the types. A quoted string, e.g. "foo", could be any type that conforms to StringLiteralConvertible. It's evaluating all permutations of potential type assignments to each literal that appears.

I thought they fixed this, though. I filed it for Array<Array<Int>> long ago, and they patched that case. https://twitter.com/kongtomorrow/status/565844856690339841

Jeez. Is there some sort of hint to indicate that a string is just a string? Otherwise that seems like it will always be slow.

Well, yes; it's called type annotation (as noted in comments both here and at the original article). Telling the compiler it's "just a String" (or more precisely a dictionary containing strings) cuts the compile time to 100ms.

Yes, the type inference in this case could use some improvement -- maybe guess the simplest possible interpretation first, and search the space of alternatives in the background, assuming there's a mechanism to go back for a do-over if any are eventually found...?

The background check would still take 12 hours in this case.

Unless you solve the [1] Entscheidungsproblem, taking two symbolic expressions (ie. two complex types) and finding if they are equal is unsolved and thought to be equivalent to solving the halting problem. [2] SAT style solvers are the best we have at the moment. Heuristics can be improved, of course. But we are really just shooting for common use cases in a turing complete language. Which really means...in a universe of infinite code and types that can be created - we are choosing to speed up our compiler for certain ones at the dismay of others. Overall though, since Swift is going to be used for making mostly trivial mobile apps, I don't really hold the academic high hat over it, let it take all the assumptions it wants.

[1] https://en.wikipedia.org/wiki/Entscheidungsproblem

[2] https://en.wikipedia.org/wiki/Boolean_satisfiability_problem

How many other two year old languages are there in large scale use? It's not surprising there are issues in compiling things. I've used so many languages early on since I started in the 80's and you can always find some syntax the compiler doesn't like. Given the pedigree of the people building Swift who also built the entire llvm system it's pretty good for something still in diapers.

Now take XCode, that is some real drunk.

Swift development began in 2010.

The work around was discussed on reddit, which is add the type information for the dictionary:


"edit: for the code, it's just changing let myCompany to

let myCompany: [String: [String: [String: String]]]'

I recently wrote a tool to report Swift block compile times, since this kind of thing can be unpredictable. At Hipmunk we run it every night to find out how we can make our builds faster.

Another common culprit of slow compile times is usage of lazy var.


Thanks, Steve! I'm well aware of the type checker's problems with 'lazy', and it's something I hope to address soon.

While you're here, I should say: first, thanks for your work, and second, it would be nice if the compiler could log the timing data in a consolidated form so my script wouldn't be necessary. :-) Regex-parsing and aggregating a bunch of log lines seems dicey.

Unfortunately, debug-time-function-bodies isn't an "officially" supported flag, so improving it isn't a high priority right now.

...That said, we'd be more than happy to take improvement PRs in this area, if you're feeling up for it!

I'm going to have to try this tomorrow. My builds seem to have gotten slower in the past week or two; hopefully I find something.


I guess this means in large application you should always annotate your types. It should be enforced with a linter.

I've been using Swift for a couple of months now. While I appreciate that type inference makes for more concise and cleaner code, it also impedes code comprehension. The absence of explicit types forces me, reading an unfamiliar piece of code, to work harder to figure out the type of each expression. This is especially true for expressions of type Optional<T>.

(But at least each expression has a type. While I love Python and have used it for many years, I don't like the uncertainty about types.)

If you're using Xcode, you can option-click a variable and (if Xcode's indexing is working, which is not a certainty) it'll show you the inferred type for that variable. This can help when looking at some new code and trying to figure out what all the bits really are.

Yeah, I know, but it's been unreliable.

In fact, this documentation effect is the only positive effect of static typing that has actual scientific support, unlike the supposed and oft-claimed safety/correctness benefits.

So while type-inference is a neat idea in theory, maybe it's not such a good idea in practice.

I'm not sure why you say the safety/correctness benefits are not real. In a large code base, with multiple developers, it is easy to get someone misusing a function, passing one type when a different one is expected. I know that some people in the python world recommend unit testing to guard against this sort of thing, but to me, that is a poor substitute for static type checking.

Not at all. Most code doesn't suffer from this problem. It's a pathological case.

The code that triggered this long type inference loop seems pretty normal. It's not like Damas-Milner's pathological case (deeply nested instantiations of type schemas), which is genuinely uncommon.

Nested collection literals aren't very common. It certainly doesn't justify requiring something like `let x = f()` to have a type annotation.

Wow, this is so sad, that compiler has to be extremely bad implemented

It's just a bug. It's pretty easy to accidentally have such cases in a generic type inference algorithm, particularly one with implicit conversions. Other similar languages have had pathological cases in type inference too.

>It's just a bug [..]

>Other similar languages have had pathological cases in type inference, too

These two statements are slightly contradictory. If this is common, then it's not just a bug, but a difficulty in implementing type inference.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact