4 ms·
> Dinging it for its syntax is something that I didn't think I would ever hear. Not just syntax, but the amount of it, and the amount of special cases in it.
by dmitriid 6y ago
> Dinging it for its syntax is something that I didn't think I would ever hear.
Not just syntax, but the amount of it, and the amount of special cases in it.
> SwiftUI is not part of Swift, so 1 and 2 are not relevant
SwiftUI exposes deficiencies in the "one of the best designed languages" and shows how Swift fails to scale in complex scenarios.
(1) Shows that its design cannot cope with anything complex. You have to write clunky wrappers for `if` and `foreach` (but not for while and for, apparently), because the design of the language didn't have place for expressions. The type system cannot handle complex requirements of the library and can't provide better facilities than Java.
(2) Shows just how bad the design decisions are in the language that they all but force you to write code this way. There's syntax upon syntax with no internal consistency or actual design to figure out how they all operate with each other.
And Swift UI forces more half-baked escape hatches (like the `some` "type", like the lambda changes described in (1)) etc.
I'll just once again expose my favorite piece of code ever:
guard let self = self { return }
instead of
if self == nil { return }
This is not an "extremely well designed language". These are badly thrown together pieces of half-baked ideas.
(3) Once again shows just how badly it's designed. Or, rather, how badly the parser is designed that it can't reliably figure out what is going on. In a language that has no significant whitespace you have to care about significant whitespace. Great design.
(4) I'm faulting the design of the standard library that is only compounding the problems already present. Many languages managed to figure out standard libraries that don't make you read and write files from a string object, or need 15 lines (different every year) of code to figure out how to write/read a file. This only continues to show that very little thought is going into this project, as they are being pressured for time to deliver "something".
- saagarjha 6y agoI'm not interested in talking about SwiftUI, but you claiming that its type system is on the same level as Java's is just hilariously off-base. The "some Type" thing is fairly standard type erasure. Your "favorite piece of code" (which, FWIW, is missing an else on the guard) has different semantics than the other snipped you present because it rebinds self to a non-optional type, whereas the second one doesn't. The parser is largely whitespace agnostic, just like pretty much every other language. Oh, maybe you were going to bring up C++, the one where you have vexing parses and "most" vexing parses and until recently couldn't put >> down without it looking like an operator? Or maybe Rust, where you need turbofish or :: to help the parser out? In Swift at least the issue you mentioned doesn't actually show up if you care about your code style… Oh, and for the last point, I suggest you read the article :P
- dmitriid 6y ago> I'm not interested in talking about SwiftUI, but you claiming that its type system is on the same level as Java's is just hilariously off-base. The "some Type" thing is fairly standard type erasure. It amazes how people completely ignore everything against some one thing they can potentially defend. Once again, SwiftUI exposes deficiencies in the language, no matter if you care about it or not. Let's take it from the top, shall we? - Swift UI says: hey, I need to have a list of values inside my nice little functions, what can yo give me? Swift: I can give you Java: static func buildBlock<C0, C1>(C0, C1) -> TupleView<(C0, C1)> static func buildBlock<C0, C1, C2>(C0, C1, C2) -> TupleView<(C0, C1, C2)> static func buildBlock<C0, C1, C2, C3>(C0, C1, C2, C3) -> TupleView<(C0, C1, C2, C3)> static func buildBlock<C0, C1, C2, C3, C4>(C0, C1, C2, C3, C4) -> TupleView<(C0, C1, C2, C3, C4)> static func buildBlock<C0, C1, C2, C3, C4, C5>(C0, C1, C2, C3, C4, C5) -> TupleView<(C0, C1, C2, C3, C4, C5)> - SwiftUI: I obviously need need some conditional and list management logic in my nice little lambdas. Swift: well, our "best designed language" can only give you Java. Because our "best designed language" has skipped class on language development of the past 40 years and can't even imagine that conditional statements can be expressions, for example static func buildEither<TrueContent, FalseContent>(first: TrueContent) -> _ConditionalContent<TrueContent, FalseContent> static func buildEither<TrueContent, FalseContent>(second: FalseContent) -> _ConditionalContent<TrueContent, FalseContent> static func buildIf<Content>(Content?) -> Content? > The "some Type" thing is fairly standard type erasure. Once again, the only reason `some` exists is to aid the compiler. Because the compiler in "the best designed language" cannot figure out the difference between protocols and types on its own. In general, in Swift and you have to constantly manually aid the compiler in everything. Also see `guard` below. > Your "favorite piece of code" (which, FWIW, is missing an else on the guard) has different semantics than the other snipped you present because it rebinds self to a non-optional type, whereas the second one doesn't. Yeah, yeah. I've seen the "it's different semantics" argument everywhere. It's not "different semantics". The only reason this exists is because they rushed the language out, and the compiler and the type checker was very limited. The only reason guard exists is to force nullability checks by the compiler. It's an inelegant and clunky clutch to aid the compiler. That is it. "The best designed language" could instead have this: if x == nil { return } // the compiler knows that x is now not nil, // it's no longer an optional type beyond this point > The parser is largely whitespace agnostic, just like pretty much every other language. Oh, maybe you were going to bring up C++ No I'm not going to bring it up, but it's funny how you brought it up.
- skohan 6y agoGuard statements are great. First of all, this is still perfectly valid swift: if self == nil { return } But guard is really nice, because it signals to the reader of a code block that if the guard condition can't be met, execution cannot continue past the guard. It does a lot to signal intent which using an if statement for early return does not. It's something I sorely miss in Rust for example.
- dmitriid 6y ago> It does a lot to signal intent which using an if statement for early return does not. Since every single language has an if statement, we clearly know what intent an if block signals. If the if condition is not meant, execution cannot continue. See? Easy. The only reason guard exists is not to aid the reader, but to aid the compiler to recognise nullability checks. That's about it. It really is a very specific if statement that is given a special treatment. And all comparisons of how great it is compared to an if statement I've seen are hillariously funny in how they willingly lie about ifs. Starting with the actual Swift docs [1]: > Using a guard statement for requirements improves the readability of your code, compared to doing the same check with an if statement. It lets you write the code that’s typically executed without wrapping it in an else block Here's how people take it to heart [2]: > Without using guard, we’d end up with a big pile of code that resembles a pyramid of doom. This doesn’t scale well Nope, you don't end up with a pyramid of doom, and yes it does scale well, provided you language designers actually design the language. [1] https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.... [2] https://thatthinginswift.com/guard-statement-swift/ https://thatthinginswift.com/guard-statement-swift/
- skohan 6y ago> Since every single language has an if statement, we clearly know what intent an if block signals. Guard has different semantics than if. For instance, I can write: if self == nil { ... do some cleanup return } Or: if self nil { ... do something else without returning } If it's a simple early return, then yes it's pretty easy to tell the intent. But imagine that I have to do some complex cleanup work over many lines before the return. In the case of a guard, I can look at the guard statement and immediately know that this block of code must end the control flow within this function. With an if statement, I have to read and parse the content of the block before I can understand that execution should not progress past this block. This is especially relevant when you're maintaining code which was written by someone else. With an if statement, you might accidentally remove a return statement from an if block which is required for correctness, and you may not find out about it until you run your program (or in the worst case after you release your code, and it causes unexpected bugs in production). With the guard statement, the compiler will enforce this constraint. It's one of many tools which Swift gives you to help you write correct code. Also, with your example: if self == nil { return } I assume you are alluding to languages where self would be implicitly unwrapped in this case, so it can be treated as a concrete instance rather than an optional after this statement. IMO it is a strength of swift that you don't have this magical conversion of an optional to a concrete value which never explicitly written, but is inferred by the compiler. Guard offers clarity and consistency about exactly where the unwrap happens, and it's barely more verbose than a bare if statement. IMO this is a very elegant solution, and in practice it's something I miss in languages which don't have it.
- auggierose 6y agoYup, guard statements are indeed great. I am using them all the time. They say more than an if statement, they "guard" the rest of the code that comes afterwards. And especially "guard let" is super useful. It's ok for you not to like Swift, though. After all, taste is subjective.