4 ms·
Any claim of the form "this language is magical! every statement is self-evident" has been bunk since the dawn of programming. The people making such claims ar
by inopinatus 6y ago
Any claim of the form "this language is magical! every statement is self-evident" has been bunk since the dawn of programming. The people making such claims are always already too close to the language to realise their own confirmation bias.
So, feedback, from someone whose exposure to Swift consists basically of this article but has eaten a metric crapload of many other braced languages over the decades.
What I can tell is that the programmer wanted to print 2,4,6,8. So the intentional readability is there. However when it comes to understanding how it works (i.e. the language mechanics delivering the intuitive reading) I had lexical concerns. I couldn't immediately tell whether the where-clause acts like a guard predicate in the for-statement or an unbraced if-statement i.e. equivalent to
for i in 1..<10 {
next if !(i % 2 == 0)
print(i)
}
or
for i in 1..<10 {
if (i % 2 == 0) {
print(i)
}
}
or even (let's hope not)
if (i % 2 == 0) {
for i in 1..<10 {
print(i)
}
}
and in a similar vein the lexical scope and binding of i was not clear to me; some languages bind the iterated variable at the level of the statement, others inside the iterated body (which may even be a closure for all I know), and this has implications particularly for the the value of i after the loop, for the binding of i in any function generated inside the loop (example: print could actually talking to an IO object that defers output by prepending lambdas to a chain - I've seen web containers deferring view rendering this way), for name masking, and for the consequences of any flow-control/continuation/exception mechanism that may cause an early loop exit.
- saagarjha 6y agoI'm unsure what the difference is between the first two…are they not equivalent? The lexical scoping could be interpreted differently, sure (allowing your third example the benefit of the doubt) but this is where the "Swift is consistent" comes into play. You already know Swift's scoping rules, it's one of the first things you learn, so using that knowledge you can figure out this code as well.
- inopinatus 6y agoNo, they're not equivalent. See, that requires making an assumption that I didn't about lexical nesting. They merely do the same thing in this example. I do not know Swift's scoping rules and having read through the introductory guide and the flow control chapter I still can't tell you if the loop variable remains visible after the loop, and what it is bound to if so. No doubt that if I sat down with a REPL or an IDE it'd hopefully be evident by example within a few seconds, but the claim was about dry-reading, not interactive experience. I'll leave it there with an admonishment against making assumptions/declarations about the obvious-ness of something you're already familiar with.
- lstamour 6y agoLexical nesting? While I agree with the statement you’re making — that reading code requires you to understand more about what the code means, in that context/runtime, I also think the example you’re picking apart reminds me of the dangers of undefined behaviour in C++. If the language specification plus its test cases still has implementation-specific details, then while by all means measure or discover them, but I would both say this is not unique to Swift and is just part of the complexity that is not writing CPU instructions directly that target only one type of CPU design. Maybe I’m taking this too far, but my point I suppose is that I know what was intended by the swift code even if the exact details are optimized out from underneath me by a compiler or language library. Might as well argue that you should have full unit and integration tests for every target platform to ensure the code behaves the way you expect, and even then you’ll still hit platform-specific edge cases, particularly on the wide variety of platforms Linux supports... I do tend to trust Clang, but even it can vary greatly from (hopefully major) version to version.
- inopinatus 6y agoYes, I'm definitely trying to point out the distinction between reading code and understanding its intention vs understanding implementation mechanics and awareness of the possible alternative behaviours. It's easy to point out that C++ is amongst the worst offenders in that regard, but even a language with a reputation for "programmer happiness" like Ruby (which I absolutely adore) is full of magic, almost every nontrivial expression glossing over a huge pile of conceptual and mechanical object-functional devices that beginners trip over quite routinely (don't even get me started on the thick layer of sorcery that Rails slathers over the top of that). So I'm not actually calling Swift a major offender, but noting generally that I don't there's ever been a language in which the intuition gap between intention and mechanics was small enough to be irrelevant. (something at the back of my mind is now whispering "Scheme", but too quietly to be taken seriously)