Hacker News new | past | comments | ask | show | jobs | submit login
Swift: Commonly Rejected Changes (github.com/apple)
221 points by ingve on Dec 31, 2015 | hide | past | favorite | 87 comments



This is a good reference to many existing discussions. While I will likely not have time to contribute to Swift it's cool to be able to look at these and see why things are the way they are.

> Replace {} Brace Syntax with Python-style indentation: Surely a polarizing issue, but Swift will not change to use indentation for scoping instead of curly braces..

I'm happy this won't happen. As much as I like Python the scoping based on spaces messes me up far too frequently and I yearn to be able to use braces to define my blocks. No idea if I'm in the minority or majority here but I like the explicitness of my braces :)


There's a good reason to keep the {} syntax beyond polarization: it enables you to programatically change/fix indentation, because the supposed levels can be recognized by the level of {}. That's something you can't so in a Pythonesquely structured code.


Why does it make sense to have this particular syntactic redundancy and not one of the many others that has been proposed? You could make a similar argument that Algol-style 'if' / 'fi' pairs help eliminate brace errors where you accidentally close the wrong construct, but clearly they have not been popular in recent years.


Syntax highlighting and code folding in editors/IDEs kind of killed the argument for if/fi or Pascalesque begin/end... even in C++, to terminate heavily parened expressions, I can just thrash ) until my editor tells me I'm done, then run it through clang-format to clean it up.


There's definitely something to that. I think a related reason why syntactic redundancy (e.g. semicolons, which thankfully Swift and Go have made optional) has been reduced in newer languages is that compilation is no longer an actual batch job, and thus error recovery during compiler parsing isn't as big of a concern as it once was. If your program is damaged in a way that the compiler can't parse it, the turnaround time is seconds rather than hours.

You can have similar editor support for indentation syntax, where the editor shows scope markers, code folding, scope coloring, etc. in a particular style chosen by the programmer. The editor could even show you the matching beginning construct after you deindent. The important difference is that redundancy in the user interface can be separated from redundancy in the language's grammar, and personal preference can be used to determine the former. The "mash closing braces" scenario you refer to is generally eliminated with indentation syntax; a single deindent can be the equivalent to multiple braces.


IDE features also kill the argument against Python-style indentation.

It's not like experienced Python programmers are constantly getting confused by their IDEs and wondering what scope a line is in.


One advantage of not using {} for blocks is that they are available for other purposes, like generics or templates, instead of the terrible <>, combinations like (::) or unicode characters.


Why are <> so terrible? I mean, they’re more accessible than {}.

<> is next to shift on the keyboard, {} is AltGr+7/9.


> Why are <> so terrible? I mean, they’re more accessible than {}.

The problem is parsing complexity, they have to be disambiguated from the corresponding operators (also the right shift `>>`), so either the syntax has to be such that they can't appear in the same context and can be trivially differentiated, or you got yourself an exponentially harder to parse language.


That can be solved relatively simply with lookahead, can't it?


Nope, because you can have arbitrary constant expressions within template instantiations.

foo<bar<1> could be interpreted as "foo<(bar < 1)>" or "foo < bar<1>"

It's undecidable without symbol lookup.


Seriously? Some people either have a really weak mental model of a language or want to see problems where there are none.

With the same right one could argue that {} can't be used for generics etc. since most people also have to write JS from time to time and it will confound the hell out of their language parser when switching languages.


> Seriously? Some people either have a really weak mental model of a language or want to see problems where there are none.

Er… mate I'm talking about actual parsers here, as in the stuff that follows the tokenizer…


Oh OK, but that's a solved problem.


It would be solved if languages using these forms didn't require more complex parser than languages not using these forms. That is not the case, and it is thus not solved in any meaningful sense of the term.


I'm not sure what you mean here, {} looks just as accessible on the keyboard as <> to me.


Not everyone is on US keyboard ;)


I use a French desktop keyboard and I've remapped left ctrl / left cmd / right cmd / right ctrl (it's a Mac) to { [ ] }. When used as modifiers they of course still perform their original function. Works like a charm, no AltGr necessary.


Can {} (or any symbolic scoping) be considered a syntactic redundancy if it allows auto-formatting and auto-indentation of your code? It may be a redundancy to the compiler, but to the code editor it is useful information.

While I tend to write code to match whatever style guide I am following, I know a few programmers who write extremely messy, poorly indented code and then just hit the magic Clang-auto-format hotkey every now and then to clean up their file. In a whitespace significant language it is not possible to infer the correct indentation if not explicitly provided.


You can just use tabs or indent by single spaces, and have the autoformatter fix it afterwards. Alternately, use a proper editor.


There are editors that do such things. However, I've never seen one that does it well. It tends to break down if you're editing code and have a temporary intermediate stage that's syntactically invalid. It's also not great in the face of copy-pasting, especially if you're rearranging code in ways that breaks blocks. You're easily left with code that's been "autocorrected" resulting in everything after a certain point being indented one level too much or too little. In a brace-using language that would correspond to an extra closing brace (or a missing closing brace), and it's easy to fix. In an indent language, fixing it is more of a hassle.

Also if you have unmatched braces, that's generally a trivial parse error - the compiler (or linter) will check that and find that every time. But with indents, if the outcome of some code refactoring accidentally broke the indent and everything after some point is over-indented, that tends to superficially work (I've actually made that mistake several times in coffeescript).

Additionally, diffing tools I know of can be set to ignore whitespace, which makes common code changes much easier to understand. If, on the other hand, you do that with an indent-sensitive language you're going to miss indent-changes entirely. That's just a practical tooling problem - you could write a diff that works just as well for indent-based languages - but it's a practical problem nonetheless.

All in all, I think it's a much better idea to have braces. If you think they're ugly, use your syntax highlighter to deemphasize them. A smart code editor could even omit the braces entirely in normal, syntactically valid code (which I'm not suggesting is necessarily a good idea, but it's possible).


Because Swift was designed to be easy to pick up by most programmers. And those are used to curly braces, from JavaScript, to languages that they teach in college, like Java, PHP, C, etc...


Which actually beings up the point, when will higher education make the switch over??


Why should they switch over?


Actually, higher education is now switching over... from Scheme, ASM and C, Haskell and Co to Java, Java and Java. Oh, and Java.


I think java is a rather good learning language.

There is almost no magic, which is good when learning new stuff. The actual computer is sort of still there. The IDEs are free and good. The environment and APIs are really stable so 10 year old code compiles and runs, and the syntax is traditional. It's not a toy language so it's useful too.

The major drawbacks is that there are a lot of crappy "enterprisy" code out there.

I really liked learning Scheme though (in 1994 or so). I think every php- and javascript-damaged kid really needs a big dose of Scheme, just as we needed it to heal some of the damage that came from Basic and C. (COBOL seems to be very hard to cure)

Clojure does not strike me as anywhere near as "clean" as Scheme, but maybe it's an alternative.

Perhaps a good first year should include courses that uses Java, Scheme and Prolog?


Well, what my uni used to have until 2015 was this:

First semester you have 3 courses going into programming from 3 different angles:

- Racket – functional programming, algorithms, etc

- DLX processor design and logical circuits (ended with ARM assembler) – the technical side

- Math – obviously, the pure mathematical side of it

Then, second semester, we did Java, C, complex algorithms and data structures, low-level programming, etc.

I’d say this is a nice way to go at it, because after the first year you have a rough overview how everything, from electron level to malloc, from simple algorithms to a webserver, works.


Not only Java, but also Julia, which is easier to learn and faster than e.g. Python or MATLAB (vide MIT Courses).


Also makes for easier code generation. Generated Haskell code often uses braces-and-semicolon, whereas almost no hand-written code does.


The downside is that if by pasting or typing you end up with too few or too many }s, the entire rest of the file gets messed up, nesting everything under the current function or ending a class early - in the eyes of the compiler, making it produce a torrent of meaningless error messages, and of the editor if you hit the reindent shortcut. This happens to me all the time in C, and significant indentation totally avoids it.


You could use indentation as a heuristic during error reporting. If there's an indentation change without a brace, that's probably where the error is.


> it enables you to programatically change/fix indentation, because the supposed levels can be recognized by the level of {}.

You only need to fix indentation if it doesn't match the block structure. Which modern languages solve by removing the unnecessary* {} tokens.

* If you can remove it, and it still works, it's unnecessary.


"Consider a syntax with no redundancy: Any random sequence of characters would then be a valid program. No error messages are even possible. A good syntax needs redundancy in order to diagnose errors and give good error messages." - Walter Bright, creator of D language (http://www.drdobbs.com/architecture-and-design/so-you-want-t...)


His argument doesn't really apply to programming languages, because when people talk about syntactic redundancy they are generally talking about redundancy in the context-free (or close to it) surface syntax of the language. But the actual language of acceptable programs depends on the name resolution rules and the type system, which generally can't even be expressed with a context-sensitive grammar.

In a language with a minimally redundant surface syntax you would still get an error if you use an unbound variable or call a function with arguments of the wrong type. The redundancy here helps tremendously for generating diagnostics. It's not even clear how you would eliminate it, because even determining redundancy (e.g. does a given type have a unique inhabitant modulo reduction) is undecidable in most practical settings.

Beyond that, a lot of the surface-level syntactic redundancy comes from the desire to match convention, e.g. using actual words as keywords and imitating mathematical notation.


> "Consider a syntax with no redundancy: Any random sequence of characters would then be a valid program.

Nobody was proposing sending raw instructions to the CPU. Instead, the higher level things, like how we indent blocks, should not be repeated. I believe you already know this.


> If you can remove it, and it still works, it's unnecessary.

There are elements in source code whose sole purpose isn't only to express instructions to the computer. Expressing the programmer's intent to future readers of the source is obviously also a frequent goal. Comments. Extra parentheses that are not strictly required due to order-of-operations rules. Various annotations and attributes. I mean, these are not exactly new, revolutionary ideas.


You're completely right: non essential things are fantastic for expressiveness to other developers. I was talking in the context of things which are unnecessary to the compiler, rather than to people.

All the things that you mention exist to help the user: that's what indentation's original purpose was, since parenthesis were obviously not good enough. Having the computer respect the same rules humans use is logical and helps remove the chance for inconsistencies.


With significant whitespace, you're not really removing them, you're just replacing them with non-printing equivalents. It's an illusion of elegance created in text editors which don't display tabs and spaces, but still basically the same. Visible syntax versus default-invisible syntax.


Indentation is visible. Conservatively estimated, tens to hundreds of thousands of programmers don't have any real problem with syntax based on indentation.


You could also measure non programmers (they lack bias) and get real numbers on whether adding parenthesis helps.


I don't see how these numbers would be more real than measuring programmers at work, unless you intend to help non-programmers write programs.


Can you please explain this argument a bit more? I don't understand how copy-pasting a piece of code with specified indents (which are known when you copy the code) is any different from copy-pasting a piece of code with specified {} nesting.


If you copy and paste this code into a different level of nesting the brackets can help give you automatic and proper indentation plus you know it's in that block now. With indentation only blocks you don't get that. At least I haven't used an editor that gives me that.

Just my 2 cents


When reading C++, features like colons and brackets are just sort of mentally removed. I don't really see them other than as clutter that at best makes the outline and structure of the program harder to see. I strongly suspect it's a matter of being used to the familiarity of brackets and colons. But hey, this is sort of pthe programmers version of the "blue and white dress."


To be fair, colons and brackets are really nice from a language designer standpoint, as they are completely unambiguous.

I think Haskell took an interesting method to the distinction, just use both. (Spaces are translated to the other form automatically)


Yeah, using whitespace / indentation as a scope delimting syntax is a horrible idea which is error prone. It's probably the most annoying thing in Python for me.


With the supposedly error prone whitespace syntax, the following code would generate an unreachable code warning instead of causing CVE-2014-1266.

    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
		goto fail;
		goto fail;
IMHO if the indentation of the code does not match the brace structure, that is highly suspicious and often very difficult to spot by manual code review, so it should not compile without any warning or error, but I'm not aware of any C-style syntax language implementation that does that.


I always follow the style of using braces for if statements in C++ and C (unless it's just a simple one liner). I.e. never write

    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
		goto fail;
Write

    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) {
		goto fail;
    }


Swift does not allow code blocks after an if statement without curly brackets, so this is not an issue.


> As much as I like Python the scoping based on spaces messes me up far too frequently

Not so much for me, but I like the rejection because consistency is more important. If I have a language where braces is used exclusively in one part and not the rest, I feel that's a bad design approach. At least in the case of Python, braces is a humor joke.

    "SyntaxError: not a chance"


> Rewrite the Swift compiler in Swift: This would be a lot of fun someday, but (unless you include rewriting all of LLVM) requires the ability to import C++ APIs into Swift.

Or write thin bindings exposing a C API to the bits of LLVM you need to invoke to drive the backend. I believe that's what Rust does[0], because you definitely can't import C++ in Rust, rustc is written in Rust, and yet it uses LLVM.

[0] might be in https://github.com/rust-lang/rust/tree/master/src/rustllvm though I'm not quite sure


Swift's compiler uses a lot more functionality from LLVM than Rust's compiler. For example, Clang's C++ API is used to parse and type-check C / Objective-C headers. Potential interoperability with C++ in the future would make this API surface even larger.


C++ interop would make the whole issue moot since you wouldn't need most of the shim anymore: you'd only have to shim enough to interop with C++, then from that could call the LLVM API directly.


That's a good point, although full C++ interoperability may be many years out, and it would probably have to include things like templates for that plan to work.


LLVM already has a C API:

http://llvm.org/docs/doxygen/html/group__LLVMC.html

It's less full-featured than the C++ API, though, and may not help Swift all that much. Swift interoperates seamlessly with Objective-C, but its C FFI requires a lot of awkward boilerplate to translate between types & calling conventions.

LLVM can also parse serialized bitcode, so one option (in any language) is always to dump to serialized LLVM bitcode and then pipe it to llc on stdin. Performance will suffer, though, since you have to serialize & deserialize the bitcode.


if/else and switch as expressions: These are conceptually interesting things to support, but many of the problems solved by making these into expressions are already solved in Swift in other ways. Making them expressions introduces significant tradeoffs, and on balance, we haven't found a design that is clearly better than what we have so far.

I wonder what these significant tradeoffs are? if/else and switch not being expressions makes certain code really awkward to write. Luckily Swift doesn't force you to use mutability here, but it's still weird IMO.


There's a few more details in the linked mailing list post[0]:

Exactly which statements should be included (certainly if and switch, any others)?

Further, it is important to consider whether the code written using this will actually be better than the code written with these things as statements. For example, the “switch” blocks tend to be very large, and turning them into expressions encourages additional indentation. Swift already allows ‘let’ values to be initialized on multiple paths, so is the win actually that great?

Given that statements-as-expressions would provide another way to do things (they are a purely syntax extension) the barrier should high to add them. They will add complexity and surface area to the language, so they need to pay that complexity.

[0] https://lists.swift.org/pipermail/swift-evolution/2015-Decem...


Well d'oh, should've clicked the link. Thanks :-)

I would argue that allowing 'let' values to be initialized on multiple paths is uglier than having them be always initialized by exactly one expression. But, I see their point.


It's a good point that "continue" is a wildly bad keyword for what it actually does. It only becomes appropriate when considered as augmenting a silent "break", i.e. "break, though continue looping".


Reasons to reject "if/else and switch as expressions" looks very naive. Can't believe it's coming from Chris Lattner. A lot of languages like Python, Haskell and Rust got this right.


I love and use Python every day, but I agree with Chris that in Swift's case, over using if and else as expression can hurt. In Swift's case, that line is extremely ugly.

If I were to catch an exception, I rather catch it at a line level in a block.

If you read through https://mail.python.org/pipermail/python-ideas/2015-Septembe... (a freakin long debate) you will see that sometimes simplifying things can hurt, although in this very debate if/else expression is favor over the proposed new syntax in that PEP, which I am against.


Python doesn't do or/else as an expression, does it?


`"yes" if foo else "no"`


That's a ternary, not an if expression.


The difference being?


You can not have full blocks, only expressions.


And in an if-expression, you similarly can have expressions. Some of those expressions might be blocks.

Some languages restrict where block expressions can be placed, but that's not a meaningful difference between if expressions and ternaries, that's a difference how blocks are treated. More concretely: I know of no language that allows "if expressions" that aren't just ternaries (i.e. either the language allows blocks as expressions or it doesn't, but given that choice, no language then further distinguishes between if expressions and ternaries).


The only thing I find bad is that not everything is a expression.


That's my only gripe with learning Swift so far. I'm also shocked at how often this document says "We do this to be like C" but yet I think the features/ideas of Swift that come from the ML family (Option/Maybe, Enum/ADT) are what makes Swift so great.


I saw this the other day and really appreciated it. It was a nice change from how some other languages (WHO SHALL NOT BE NAMED) just say "no, we're not adding this, and if you keep thinking we should then you're just not smart." This Swift document on the other hand explains thoroughly their reasoning behind it.


Just to clarify, you're not talking about Go here, right? Because they make posts like this with some regularity about language design and leave the door open on a number of suggestions/changes


The languages that you mean probably have this information somewhere, just buried in some mailing list archive instead of compiled like this. Not that people would stop complaining even with such readily available information.


Some open source projects prefer to avoid discouraging prospective contributors, even if they know that the task the contributor is currently working on has no chance of acceptance. The hope is usually that avoiding discouragement will build a larger community, and that contributors will eventually realize the futility of their efforts or otherwise organically move towards making productive contributions to the project.


What wacky logic. If I am going to spend valuable time helping a project only to let the work simply be wasted, I will organically move to some other project that values my contribution enough to not waste my time.


I used Swift for a class and really liked it. It reminded me of a mix of Python, C, and JavaScript which are my favorite languages. I hope to use it more outside of Apple's hardware if it makes sense.


This reads mostly as "people wanting swift to be something different than what it is"


Well in a sense that is swift-evolution.


I disagree, it's more like "my favourite X has this, so I want everybody else to have it"

If Swift's idea was to be a C-like language then it doesn't make any sense to suggest indenting as code-block markers, or to not use 'default' in switch statements


It was only c like in brackets. This language is an amalgam of the good features of many languages really and it's not done adapting to where it should be. I agree that indentation from Python is a bad feature though.


I think I kind of guess what would be the items on a similar list for Golang would be (for instance generics being a no-no).

And I must say I _must_ prefer the stance Swifts developers take compared to Go's situation. It is because of this that I think that Swift likely has a great future competing with Go in the space of web-software; be it a bit in the long run as it currently lacks some basic facilities/libraries.

I wish the both the best, for 2016 and beyond. But I keep a eye on Swift's web-tech libs as I expect it to blow up in the coming years :)


Is there any explanation for the lack of types in error handling anywhere? The compiler should be able to easily infer those and require that you handle them correctly.


There is a proposal to add support for them - it is currently blocked on infrastructure work necessary to "do it right".


Thanks!


I haven't had a chance to work with Swift much yet, but I'm actually very glad for their reasonings. The only issue I might gripe with is the single quotes, but I get the unicode perspective.


How often are you really making characters? Single quote for unescaped string literals is used way more often in my world and it's a feature of ruby, base et al. and other languages. Character("X") isn't that bad for something used minimally.


I argue that even in the case of char, why so cheap now to reserve a type for char instead of using unicode? I get it, sometimes you have requirements where char type is cheaper to use, but on iPhone a few extra bytes won't kill.


well it's supposed to be a systems language so it makes sense to have all types available. you could ask the same of Int8 being in the language when pretty much all processors nowadays are 64bit.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: