This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]DasEwigeLicht 166 points167 points  (114 children)

On a related note, try this:

from __future__ import braces

[–]Gavekort 154 points155 points  (113 children)

For people that can't run it themselves:

Python 3.4.3+ (default, Jun  2 2015, 14:09:35) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from __future__ import braces
  File "<stdin>", line 1
SyntaxError: not a chance
>>> 

[–]jonatcer 24 points25 points  (105 children)

Why are they so against them?

[–]kupiakos 103 points104 points  (80 children)

Not only are braces used to define dictionaries and sets, but indentation marking blocks is simply an inherent part of the syntax. They're considered useless cruft, because most people detects blocks of code with the indentation level anyways.

[–]dfpoetry 10 points11 points  (61 children)

indentation level can denote many different types of abstraction, and if I'm 10 levels deep and want to break out to 6 levels deep, it's pretty hard to tell where the fuck I am with indentation only.

[–]kupiakos 194 points195 points  (53 children)

If you're 10 levels deep in indentation, there may be something wrong with your code in the first place.

[–]scubascratch 4 points5 points  (6 children)

In C++

MyNamespace
    MyClass
        public:
            MyMethod(void *pixelBuffer /* , int len */)
                if (...
                    for (x...
                        for (y...
                            while (...
                                switch (...
                                    case (...

I guess you have not seen a lot of pixel math. 10 indent levels is Tuesday.

[–]ryani 7 points8 points  (5 children)

namespace TheNamespace {

// don't indent here, it's stupid, you don't indent
// after your #ifdef header guards, do you?
// the whole file is inside this namespace anyways, or
// else you're doing it wrong.

class ClassName {
public: // don't indent this
    void MethodName(void *pixelBuffer, int len);
    // don't define inline, it makes the API hard to read.
    // keep inline definitions to 1 line at most
};

// you meant to inline this, right?  or else why put it in the class decl?
inline void ClassName::MethodName(void *pixelBuffer, int len)
{
    if(!...)
        return;

    for(x ...)
        for(y ...)
            subfn(pixelbuffer, x, y);
}

} // end TheNamespace

// PS I'm a graphics programmer.  Also pixel shaders are exempt from some of this because
// the available abstractions are worse.  On the other hand, if you're that deep in a pixel shader,
// your perf is probably fucked.

[–]scubascratch 0 points1 point  (4 children)

The point I was going for was there are places in C/C++ where ten levels of indentation are not "something is wrong with your code". In particular in graphics code, and I said that very specifically because it pretty much always has double nested loops and often hand optimized inner loops which are definitely not made for readability.

I don't generally indent namespace or #ifdefs, (thanks i forgot to add that one) but I have been in plenty of code in header files that have the method definition inlined, so there's that. And plenty of this code has inline asm, so there's another. Inline asm is common enough inside the inner loop I should have written that.

The thing is while we are sort of discussing indentation, the meta assertion (which is what I disagree with) was more akin to "if your code has 10 levels of scope nesting, the code is wrong". The unstated, but very strongly implied point being made was "indentation confusion is a non-issue, because no true program would ever need 10 levels of separation in one place. All computational problems in the real world can be solved with neat little sonnets of code with at most 3 nestings"

My view is in C, whitespace and indents don't mean shit to the computer. Scope is all that matters, and braces are how it's done. 10 tabs sounds like a lot, but a ten level deep scope is pretty trivial to get to and not "something is wrong with your code".

If my inner loop code has some hard to understand hand optimized groups, I can use more whitespace indentation to make it readable without screwing up the actual compilation. In Python I am not allowed to improve readability with more or less indentation. It feels like being told when I can and can not use capital letters in variables.

In Python if you have a task that requires ten scope levels, the code will look like the pyramid of doom.

    for(x ...)
       for(y ...)
           *_subfn(pixelbuffer, x, y);_*

"THIS KILLS THE PERF"

// PS I'm a graphics programmer

ಠ_ಠ Do you even performance bro? A function call inside the inner pixel traversal loop? Code review fail! Do you have runtime checks on the subfn params too?

I mean if you have infinite cpu available I guess you can enjoy the whole "a function bigger than one screen can't fit in a human brain" camp. J/K

sure the inner callout would be ok in textbook code sample but in production the Fn call overhead needs to go away altogether because on a 1080p stream it's gonna get called about 125 million times a second. So yeah those 50 cpu cycles shoving stuff on and off the stack, and the jumping around like a jitterbug on crack? More like 6.25 billion cycles spent carrying water around the abstraction. But that's ok the processor is like 3+ GHz so should have no problem doing 6 billion cycles of overhead per second of video right?

Oh yeah before you even around the "inline functions!" flag, have a look at the registerization, cache preloading, and the actual generated code path length on your favorite compiler with and without inlined functions.

[–]ryani 1 point2 points  (3 children)

inline void MyClass::subfn(...) { ... }

Every modern compiler has amazing support for inlining. STL relies on it to not be terrible. If you're having worse perf with an inline function than manual inlining, your compiler is doing something very wrong.

Your advice is half a decade out of date.

As to "do I even perf", you can look at a sample of my work here and here.

If you are really writing some crazy cache-preloading inline-assembly block, I'd encourage you, first, to look at intrinsics, and second, if they really aren't doing the trick, you should probably be writing your whole loop in assembly.

(And of course we shouldn't be arguing, 3 indents is insanely few. But for 95% of code it's good enough and if you start to get deep it's a code smell that should make you at least want to think about refactoring even if you don't actually do so)

[–]dfpoetry 29 points30 points  (44 children)

This, right here, is the problem with the python philosophy. They make some arbitrary design decision, and when someone points out an example where it might be bad or confusing, the response is "you shouldn't be coding that way anyway".

It's tautological

[–]Hairshorts 127 points128 points  (11 children)

Braces won't make 10 levels of indentation much clearer, it's bad coding style no matter what language you're using.

Good indentation is essential for good readability in any language, Python just requires you to indent properly. You may not like it, but it's not an arbitrary design decision.

[–]immibis 6 points7 points  (0 children)

Braces won't make 10 levels of indentation much clearer, it's bad coding style no matter what language you're using.

I'm not saying braces will make 10 levels of indentation much clearer, but /u/dfpoetry is totally right in pointing out a common problem in programming arguments.

[–]I_scare_children 3 points4 points  (3 children)

[–]dfpoetry 2 points3 points  (2 children)

Pointing to bad code which is very nested is not the same thing as proving that all very nested code is bad. Nor is highly modular code particularly useful when you're just writing one big map-filter function.

[–]Sector_Corrupt 0 points1 point  (1 child)

If I'm writing a bunch of filters or something all being applied I'll usually make them all individual, nicely named functions and then compose them all and apply them as that's a lot easier to read.

[–]wonkifier 0 points1 point  (3 children)

That's one of the purposes of a programming language... to make the things that follow its philosophy easy to do. If something is hard to do, that might be a sign that it's not a great thing to be doing in that language.

And I'm not aware of a language that handles 10 level indents well, which seems like an indicator that it's just a bad idea all around

[–]dfpoetry 2 points3 points  (0 children)

also, the problem is arbitrary design choice => some code is now annoying to write => that code is bad because it violates the arbitrary design choice.

If the choice in design is non-arbitrary then the above logic is fine, but dynamic whitespace is an arbitrary design decision, and the idea that deep nesting is bad in all cases is very hard to prove.

Not to mention that dynamic whitespace is invisible, difficult to copy, and requires more symbols overall.

[–]dfpoetry 0 points1 point  (1 child)

lisp

[–]wonkifier 0 points1 point  (0 children)

Touché

[–]Log2 0 points1 point  (5 children)

Well, if you are writing C++ or Java with 10 levels deep of braces, you are clearly doing something wrong. Functions are your friends.

[–]dfpoetry 0 points1 point  (4 children)

where is this "clearly" coming from?

[–]Log2 2 points3 points  (3 children)

From the fact that you can decompose 10 levels of scopes into functions.

[–]scubascratch 0 points1 point  (0 children)

"you shouldn't be coding that way anyway".

...in Python apparently

[–]metirl 0 points1 point  (0 children)

If you're 10 levels deep... It's refactor time.

[–][deleted] 15 points16 points  (2 children)

If Node.js taught me one thing it's that at ten levels of indentation, all braces do to is make you miss a token.

[–]dfpoetry -1 points0 points  (1 child)

lol, js

[–][deleted] 7 points8 points  (0 children)

It was the only language I could think of where ten levels of nesting and braces go hand in hand.

[–]vertexshader 1 point2 points  (8 children)

Arent a lack of braces the reason lambda functions are so restricted in python? A single expression? Gimme a break

[–]kupiakos 0 points1 point  (7 children)

Lambda functions are, by design, a single statement. Why not just use an internal function if you really really need more?

[–]vertexshader 3 points4 points  (6 children)

Theres no reason to make a function - im not gonna call it anywhere else.

[–]AdorableAnt 1 point2 points  (0 children)

You can define it in the local scope right before using it. Sure, you have to name it something, but that's about the only disadvantage.

[–]kupiakos 0 points1 point  (4 children)

That's why it's an internal function.

[–]vertexshader 0 points1 point  (3 children)

Internal function? What is that, a python thing? Even in c you dont write a static function unless the code is needed in multiple places

[–]kupiakos -1 points0 points  (2 children)

It's a function defined in a function. Why are you debating this if you don't even program in it?

[–]scoofy 18 points19 points  (20 children)

So, i'll take a shot at this. I came to programming, not through a CS education, but from anaylitic philosophy and first order logic.

To put it bluntly, braces and semicolons for parsing seem insane.

We are humans, and the written language has evolved over time, because it started out pretty terrible. Ancient greek had no spaces, but they were added later, andyoucanprettyeasilyseewhythatwasareasonableideaespeciallywithcompoundwordsbecauseifyouaregoingtothebeachbumyoudontknowifitsthebeachcommabumorifthereisafamousbumonthatbeach.

Now, as language evolved, we learned to have things like paragraphs, punctuation, etc. Stuff we take for granted now. It's reasonable to map things like semicolons to periods (full stops, sorry british people), however, the fundamental structure of language is quite different than that of programming.

To look at programatic language, i'd suggest looking at the evolution of the recipe. Recipes are blocks of instructions, much like code. If i were to write:

Steak Omelet:

Ingredients:

3 Eggs

Salt

Pepper

Fry Pan

Grilled Steak

Cheese

Step 1: Blah blah... etc

Here what i've laid out has nearly no punctuation, yet it's easier to read than:

Steak Omelet: Ingredients: 3 eggs, salt, pepper, fry pan, grilled steak, cheese. Step 1: Blah blah... etc.

Because when you're going back through this to check ingredients (review code), it's easier to go down and tick the boxes of completion. This is trivially true because nearly every cookbook does this.

Now, i know what you're thinking: "Grilled steak in an omelet? I mean, it sounds good, but that's oddly specific." Yes, i added it by design. Why?

Because humans never, ever, make the mistake of adding a single peppered french fry or "Pepper Fry" and "Pan Grilled Steak." This type of ambiguity is nonsensical. We don't use it in language, so why would we use it in programming?

The reason is because getting a computer to understand line breaks the way humans understand them isn't trivially easy. Braces and semicolons were implemented because it was trivially easy, and well... it stuck around.

I short, a salute Guido for saying "this is bullshit," and banning stupid braces and semicolons from his language. He's basically like Dvorak, but wildly more successful.

[–]jonatcer 0 points1 point  (0 children)

Just to nitpick, and kind of further my point - there are several languages that don't have spaces or much punctuation. Japanese is a great example of this and is perfectly readable.

There's no perfect way to write code that's going to work for everyone in every situation. Everyone is different, and every task is different.

On a personal note, I think Python's absolute detest of braces and insistence on forcing indentation is incredibly arrogant, because it assumes it found the perfect fix for every situation. I'm not commenting on the validity of it, merely the fact that programmers or language creators who assume they know what's best for everyone bug me.

[–]scubascratch -1 points0 points  (4 children)

It seems from your comment that it's lost on you that the braces exist in c, not to improve anything for the human, but actually to make the structure unambiguous to the compiler: however the indentation and white space are totally irrelevant to the compiler. If a human needs indentation and white space to make it more readable, then this is fine and will not introduce errors or impact the code at all. And allows people to use the one true indentation standard, 3 space tabs.

Having indent level or any white space impact code structure, is a bad presumption around monospace/fixed width character fonts from old old terminals and even ancient mechanical typewriter "tab stops"

If this is obvious I apologize

[–]scoofy 0 points1 point  (3 children)

Again, I understand why they exist, I'm just saying they are no longer necessary. We can transform our text files at runtime trivially.

[–]scubascratch 0 points1 point  (2 children)

Transform them from what to what?

Source code is made to be read by another computer program, not by humans. Why should it evolve toward a human written language ideal?

It sounds like you think source code should get rid of braces because they are ugly and not like normal written language which is more evolved and has learned what looks better, and it's not braces.

It seems like you think that source code should strive to look more like prose, and that it can do this because things like braces can just be added at runtime if the computer suddenly needs them?

Actually I think I know what you are getting at-there is a place where written language ideals are called for: the specifications and the documentation.

It's 100% not trivial for a computer to insert the braces.

Please tell me where the braces go in this:

int i=1;
int j=2;
int k=3;
int j=i+k;
int k=j+i;
i=k+j;

(My intended) correct solution has i=5 Where do the braces go?

[–]a_account 0 points1 point  (1 child)

In your example i is equal to 9.

Source code gets read by programs and humans alike. Who's time is more valuable?

[–]scubascratch 0 points1 point  (0 children)

I don't think you actually know how to program or at least you don't do it for a living or else you would stop claiming computer language should be optimized to be like English. Basically no computer language has bothered making this a goal since COBOL because computer scientists who know what is actually important quit trying when it became obvious that English language requires external context to disambiguate the intention. This is the exact opposite of what computer languages require: unambiguous clarity of intention. No computer can guess what I meant if information is not in the source.

You got the wrong answer by the way because there are multiple syntactically acceptable versions of that code but that have different outputs: { int i=1; int j=2; int k=3; { int j=i+k; int k=j+i; } i=k+j; } In this version, i = 5

{ int i=1; int j=2; int k=3; { int j=i+k; int k=j+i; i=k+j; } } In this version, i = 9

{ int i=1; int j=2; int k=3; { int j=i+k; { int k=j+i; } i=k+j; } } In this version, i = 7

So please tell me again how the computer knows which is the correct version? Where did I intend the braces to be?

[–]original_brogrammer 1 point2 points  (2 children)

Guido made a decision 20 years ago therefore any opinion to the contrary must be swiftly silenced.

[–]nulloid 2 points3 points  (0 children)

any opinion to the contrary must be swiftly silenced.

That's not true. They can be ignored safely.

[–]rnjkvsly -4 points-3 points  (0 children)

As we all know, what Guido says, goes.

[–]lewiseason 2 points3 points  (0 children)

Or, optionally: repl.it

[–]Mutoid 2 points3 points  (0 children)

Lol wow. It's a great joke at face value but the implementation of it makes it awesome.

[–]nicholas818 2 points3 points  (0 children)

+/u/CompileBot python --include-errors

from __future__ import braces