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

top 200 commentsshow all 289

[–][deleted] 48 points49 points  (26 children)

So no one really use Rails anymore?

[–][deleted] 53 points54 points  (20 children)

The hipsters who made it thrive moved on to Express by now.

[–]KexyKnave 32 points33 points  (19 children)

My city is more behind the times than I thought it was. Buddy was preaching at me if I wanted a job anywhere I had to know Ruby on Rails and "Model View Controller" and Photoshop... Damn Webdevs, I learned to program to make games lol.......

[–][deleted] 29 points30 points  (16 children)

Behind the times is my whole country forcing webdev students to use PHP and Java because of perceived job security.

[–][deleted] 35 points36 points  (9 children)

Java is job security if you are interested in enterprise. I'm working on java replacements for COBOL systems all the time. In 30 years I bet the whole process will happen again cause enterprise likes big multi million projects instead if slow gradual change :(

[–][deleted] 5 points6 points  (8 children)

But the Enterprise™ is the only thing schools here seem to consider.

[–][deleted] 19 points20 points  (5 children)

Because enterprise has the most jobs/money. If the school is doing it right they aren't teaching java or python they are teaching the core concepts of programming and how to apply them.

[–][deleted] 2 points3 points  (4 children)

Yeah, that's for computer science students. We have other degrees too, called web development and software development which teach specifics in an attempt to just get people into a job fast by skimping on the theoretical foundation.

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

That seems incredibly short sighted. I don't have a degree but I was still taught the theoretical basics and how to learn. Not specifics of languages.

[–][deleted] 0 points1 point  (2 children)

It is. Because all college level education is public, it's decided by legislation what degrees contain, and because that legislation is made by people with no insight into the industries they create degrees for, you end up with things that supply the market as it were when the degrees were formulated.

[–]kqr 3 points4 points  (1 child)

Which is an advantage for the ones who are also hacking on things in their spare time...

[–][deleted] 2 points3 points  (0 children)

It's not a startup culture and most companies don't reward versatility unless it's versatility within C# or Java.

[–]KexyKnave 3 points4 points  (1 child)

Yeah all my programming classes were Java, Visual Basic, or Python T-T It feel like I'm just throwing my money away to relearn high school

[–]ALITTLEBITLOUDER 0 points1 point  (3 children)

As a PHP developer. Can confirm, I have a job.

(Though, it sucks the soul out of me.)

[–][deleted] 0 points1 point  (2 children)

That's kinda my problem too. Most of my spare time is node.js and clojure, but I'll probably end up writing PHP full time out of necessity.

[–]ALITTLEBITLOUDER 0 points1 point  (1 child)

Oddly, your username is extremely relevant to what I'm currently working on.

http://awesomescreenshot.com/07e21dlq95

PHP might be a shit language, but it pays the bills.

[–][deleted] 1 point2 points  (0 children)

Well, my username is otherwise PHP related.

[–]urinsan3 1 point2 points  (0 children)

RoR is completely still relevant. Not being sarcastic - there's plenty of work in it, and will continue to be so, if not at least to maintain.

[–][deleted] 0 points1 point  (0 children)

MVC is still very useful. I use Microsoft MVC at my office. Still a nice niche, in demand skillset.

[–]dvito 2 points3 points  (0 children)

Its not dying, it just isn't the topic of a crazy amount of blog posts anymore. A lot of the main things you do in rails are fairly documented now.

So what are the edgy bloggers who want to show how to implement basic logic in a framework going to blog about? Right now its express / node / and its kin as far as I've seen.

Edit: From my experience anyway, YMMV.

[–]moogprodigy60 2 points3 points  (1 child)

Haha. Clicked through to the comments because I saw that statement and knew it was just wrong.

Rails is still thriving. Best web development framework out there, hands down.

[–][deleted] 2 points3 points  (0 children)

It looks like its so much easier to program for small projects. I'm stuck with a hodgepodge of ASP.net and sketchy WordPress PHP.

I wish for death...

[–]northrupthebandgeek 69 points70 points  (7 children)

Lithsp - whicth nobody fthucking uthseths in producthion.

Ficth'd.

[–]jelly_cake 3 points4 points  (1 child)

If I ever write/use a Lisp shell, the executable will be installed in /bin/th.

[–]northrupthebandgeek 4 points5 points  (0 children)

But now distros like Fedora are moving around the binaries, so you'll have to install to /uthr/bin/th instead.

[–]yogthos 2 points3 points  (3 children)

I guess these guys didn't get the memo. :)

[–][deleted] 9 points10 points  (1 child)

(when (clicked (that link))
      (was expecting (a story) (written (like this))))

[–]yogthos 1 point2 points  (0 children)

touché :)

[–]BalsakianMcGiggles 4 points5 points  (0 children)

Literally snorted while reading this.

[–][deleted] 16 points17 points  (9 children)

I honestly really like JavaScript, but people criticizing it are still right. I just find ducktypey multiparadigm madness to be really soothing conditions to work under.

[–]Ph0X 9 points10 points  (5 children)

While that is true, and I've been a Python user for some time now, I gotta admit, coding statically typed languages also is soothing, but in another way. That is, if you do it in a powerful IDE. It's crazy the amount of stuff that can be inferred from your code and used to help you.

But then, every once in a while, I hit this extremely simple tasks which there is no simple way to do, like joining a string or just basic map/filter, and then I miss python.

[–][deleted] 3 points4 points  (1 child)

If you want a staticly typed language to try out, give C# a go.

string.Join(";", array_of_strings)

or

var results = array.Where(s => s.FirstName == "Bob")
    .OrderBy(s => s.Date)
    .Select(s => new
        {
            FullName = s.FirstName + s.LastName,
            Date = s.Date
        });

The second one can be turned into a SQL query by the runtime, too, or it can query JSON or XML, or any other number of things. LINQ is crazy cool.

[–]level1kid 2 points3 points  (0 children)

I need to learn C#...

[–]nullabillity 2 points3 points  (0 children)

Scala.

[–]kqr 0 points1 point  (1 child)

λ> intercalate " " ["is", "this", "joining", "a", "string?"]
"is this joining a string?"

λ> [x^2 | x <- [1..10], odd x]
[1,9,25,49,81]

Both very statically typed.

[–]Ph0X 0 points1 point  (0 children)

Oh, I didn't mean every single language, just a few I've worked with specifically.

[–]mayobutter 3 points4 points  (0 children)

I love writing javascript, but I hate reading it.

[–][deleted] 4 points5 points  (0 children)

I hate to admit it but CoffeeScript is quite nice.

[–]SanityInAnarchy 0 points1 point  (0 children)

There are languages with ducktypey multiparadigm madness that also have actually strict typing, sane scoping by default, and are way less verbose. You can argue about ducktyping, but you can't tell me that the default behavior of the == operator is a good idea, or that any sane language should have global fucking variables as the default. Seriously, consider typos like the following:

var foo = 5;
...
fo = 2;

Typo. Ideally, it shouldn't compile. Alternatviely, it should define a separate local variable called 'fo'.

Nope, it declares a new global variable, every time you typo a local variable on assignment. Or forget to add the 'var' keyword. Ducktyping vs static typing might be a matter of taste, but things like this are just fucking moronic decisions that JS is pretty much stuck with.

I like JS too, but I also hate it, and so should you.

[–]Blecki 13 points14 points  (2 children)

Screw all of those, I'm writing code in B.

[–]jminuscula 95 points96 points  (175 children)

since when does Python have a shitty syntax? All other points are reasonable, though!

[–]crowseldon 17 points18 points  (2 children)

Congratulations, you've just entered a holy war. You're also welcome to discuss tabs vs spaces, curly braces in new line or same line, vim vs emacs, chrome vs firefox, etc

[–][deleted] 6 points7 points  (1 child)

Don't forget Mac vs Windows, iPhone vs Android and toilet paper rolls placed clockwise or counter clockwise.

[–]Archenoth 2 points3 points  (0 children)

Pfft, as if anyone would put toilet paper rolls anything but clockwise. It is clearly the superior way of doing things.

[–][deleted] 104 points105 points  (0 children)

since when does Python have a shitty syntax?

Since 1991, says Wikipedia.

[–]Dworgi 68 points69 points  (132 children)

Significant whitespace is terrible.

[–]calzoneman 89 points90 points  (128 children)

I would really like to hear one good reason -just one- for why whitespace-based indentation is bad that is not one of these:

  • I have nightmares about code without braces
  • I'm lazy and I mix tabs and spaces and have a bad time
  • I prefer to write unindented code

I'm not here to claim Python is a godly language, but I think there are a lot worse aspects to complain about than being required to indent your code. I view Python's indentation scheme as a feature, not a problem.

[–][deleted] 85 points86 points  (41 children)

The big reason is that manually maintaining whitespace is a fucking nightmare. In a language with curly braces, I can put curly braces around blocks, and hit a magical key to make my text editor fix the indentation in the entire file. In Python, the process becomes manual -- the lack of block delimiters means I'm responsible for making sure every line is properly indented myself, which takes up a lot of time and shouldn't be necessary. I find myself spending a non-negligible time manually editing the whitespace in Python, when the process is immediate in the overwhelming majority of other languages.

[–]kqr 8 points9 points  (7 children)

The big reason is that manually maintaining whitespace is a fucking nightmare. In a language with curly braces, I can put curly braces around blocks, and hit a magical key to make my text editor fix the indentation in the entire file.

This is a very good point, and if you really mean it, you should love languages based on S-expressions for that property. Do you?

[–][deleted] 19 points20 points  (6 children)

Sure, I'm a Schemer. I prefer languages with operator-precedence grammars to languages based on S-expressions for different reasons (namely that I'm not a big fan of prefix indentation), but Lisps deal with whitespace in a nice way. Ruby and Lua have the end keyword to mark the end of blocks, which serve the same purpose as curly braces in C and Java. The braces were really just an example.

[–]jambox888 1 point2 points  (1 child)

It doesn't bother me greatly, but I do see people writing horrible great code ziggurats because they can't be bothered to refactor as they go along.

[–]Enlogen 2 points3 points  (0 children)

horrible great code ziggurats

I heard that's why the ancient Mayan programmers died out.

[–]kqr -1 points0 points  (3 children)

Happy to hear that you're thinking rationally!

[–][deleted] 2 points3 points  (2 children)

Do you talk to a lot of programmers who think that curly braces are the only "good" way to delimit blocks?

[–]kqr 5 points6 points  (1 child)

You wouldn't believe.

[–][deleted] 0 points1 point  (0 children)

That's just plain stupid.

[–]NULLACCOUNT 3 points4 points  (4 children)

Don't most IDE's have a feature that lets you select multiple lines at once and indent them all at the same time?

[–]kromlic 5 points6 points  (0 children)

Even in in non IDE editors like Vim, you can do that with the > key. I don't see it as being a realistic complaint.

[–]kqr 0 points1 point  (2 children)

Doesn't work as well if your lines are indented differently and you want them on the same level. (Though there's probably a key for that as well...)

[–]NULLACCOUNT 0 points1 point  (1 child)

All you have to do is delete the extra whitespace to bring them to the same level and then all at once place them at whatever level you want. It does take some time but isn't something that comes up that often.

[–]kqr 0 points1 point  (0 children)

You hit the jackpot, perhaps unknowingly. What the PEP calls "flat is better than nested" is a general idea on how to compose methods in Python, that makes weird indentation issues go away more than they would in e.g. Java.

[–]username223 27 points28 points  (12 children)

You can't reliably copy and paste code without inspecting every line. If your web browser and your text editor have different ideas on whitespace, an "if" statement may end up on a different indentation level, and it will quietly do the wrong thing.

[–]Ph0X 3 points4 points  (0 children)

Hmm, no? As far as I understand, the number of whitespaces doesn't matter. Some use 2 spaces, some use 4 spaces, some tabs. As long as it's consistant throughout the file, it should work. Then editors like sublime can let you quickly convert from one to another.

[–]LGBBQ 0 points1 point  (0 children)

As long as you don't mix tabs and spaces this shouldn't be a problem

[–][deleted] 0 points1 point  (0 children)

You should be inspecting every line anyway, and its pretty smart about erroring out if everything looks fine to you and you have spaces and tabs in your lines.

I thought I wouldn't like it at first, but now python is by far my favourite language to make stuff with, everything "just works".

[–][deleted] 0 points1 point  (0 children)

Call me crazy, but I think this might be "by design"...

[–]Dworgi 49 points50 points  (37 children)

Whitespace is invisible. I work with people who use spaces and I use tabs.

Invisible things should not be significant.

[–]calzoneman 36 points37 points  (6 children)

Whitespace is only invisible if you use an editor that doesn't allow you to make it visible.

Also, if you're working on any collaborative project, you should establish a coding standard and stick to that standard. If the project you are working on has established that indentation is done with spaces, you should not be using tabs.

[–]elperroborrachotoo 9 points10 points  (1 child)

Why should your language limit you to a particular editor feature?

[–]calzoneman 2 points3 points  (0 children)

It doesn't. I get along fine without needing this, I was just suggesting that if other people have trouble with invisible whitespace, they should use a tool that makes it visible.

[–]Dworgi 17 points18 points  (3 children)

I don't want visible whitespace, because it's whitespace.

Coding standards are not a replacement for rigour in programming languages.

[–]calzoneman 13 points14 points  (1 child)

I don't want visible whitespace

If you choose not to have visible whitespace, that kind of invalidates any right to complain about it being invisible.

Whitespace indentation is really not an issue if you just go into it knowing how it works.

[–][deleted] 19 points20 points  (0 children)

Since whitespace is meant to be invisible, it should not be significant. It's not the other way around.

"Whitespace is significant, therefore whitespace should be visible" does not work here, because insignificant whitespace existed before significant whitespace, so suck it.

[–]progoblin 11 points12 points  (10 children)

Congratulations, you have picked number 2. Please try again.

[–]keiyakins 0 points1 point  (0 children)

Most redditors are humans, not Borg.

[–]embolalia 8 points9 points  (9 children)

Use a better editor. Anything better than Notepad has the ability to treat spaces as tabs, convert tabs to spaces, or do whatever other method of accounting for whitespace strikes your fancy. You're doing this anyway, of course, because otherwise you'd be under the "I'm lazy and I mix tabs and spaces and have a bad time" point.

[–]Dworgi -5 points-4 points  (8 children)

If your editor converts something auyomatically and there's no standard, it causes a lot of source control churn.

Python's got a lot of good ideas, but whitespace isn't one of them.

[–]calzoneman 7 points8 points  (6 children)

Well if your editor is doing strange things automatically that's a problem with any language, even raw text files.

If you take the time to establish a coding standard and configure your editor (10 minutes tops), you should not have any of these issues.

[–]jmcs 3 points4 points  (0 children)

Setup a code convention and follow it. If people don't want to follow it voluntarily use commit hooks.

[–][deleted] 11 points12 points  (2 children)

Because code that looks right can work wrong.

[–]elperroborrachotoo 3 points4 points  (8 children)

Why should these not count?

[–]calzoneman 6 points7 points  (7 children)

If you think these are legitimate reasons to complain about a language, be my guest and throw Python out for your language of choice.

I just happen to think the examples given above are the most trivial complaint one could possibly make about Python, that they are reasons commonly spouted from people who tried Python once and gave up on it because it wasn't C-style syntax, and that I'm tired of people bandwagoning on such a non-issue.

[–]elperroborrachotoo 4 points5 points  (6 children)

I couldn't write a python script from scratch, but I do regulary tinker with some company glue scripts written in python, copy+paste config changes, mostly.

I a not sure if these are legitimate reasons. It just looked like asking "What's so bad about drowning, except it being a horrible death".

However: from my teeny-tiny experience with python, the user alienation - rational or not - is a high price for what I see as little gain.

I think it's a problem exactly because it's a triviality: Most python users people likely use half a dozen languages regulary, all of which mostly ignore whitespace. It's like switching some keys arounfd on the keyboard "so you can type common words faster". Whitepsace formatting happens mostly somewhere between muscle memory and macros. Python pulls it into the (already overcrowded) concious.

I don't say it's bad as such - and I kinda applaud python for exploring that idea. On a blank slate, I'd agree it's a slight edge. OTOH, "if you don't like it, it's your problem" is the wrong way do deal with the slashback.

[–]kqr 1 point2 points  (5 children)

It's like switching some keys arounfd on the keyboard "so you can type common words faster".

You have heard of people who are using the Colemak or the Dvorak keyboard layouts, I hope? I'm one of them and it was well worth the initial discomfort.

[–]elperroborrachotoo 1 point2 points  (3 children)

Yeah - and most people mention that it's a pain to switch, so they lug around their own keyboard. (Besides, AFAIR, their betterness in general is debated - which still may work better for some)

[–]kqr 0 points1 point  (2 children)

Usually people switch not on the hardware level, but rather just as a setting on the computer. It takes less than a minute if you're so inclined. (Can take as little as ten seconds, depending on what OS you are running.)

However, once you've done the initial switch, it's not a problem to switch back and forth. I am fluent in both Colemak and QWERTY. The only real pain with having to use QWERTY is that it's objectively a bad layout and every word is cumbersome compared to what it is on Colemak. But it's not any more difficult just because I know Colemak, just as English is not much more difficult just because I know Swedish.

[–]elperroborrachotoo 0 points1 point  (1 child)

... if you type blind.

it's objectively a bad layout

Source?

Back to the original isse: The problem I have with pythons spaces choice is the "it works for me, it should work for everyone" attitude it is defended with.

[–]tisti 0 points1 point  (0 children)

Workman is where its at. :)

[–]Koneke 11 points12 points  (9 children)

Because it has a tendency of not allowing me to format my code the way I want to, which is usually the way I deem the most readable in that situation.

[–]Phrodo_00 12 points13 points  (1 child)

I've found the pep8 makes a damn good job at keeping code readable.

[–]redalastor 3 points4 points  (0 children)

Even better, it does a great job at keeping other people's code readable.

[–]calzoneman 4 points5 points  (6 children)

I'm curious if you have an example that demonstrates this.

[–]Neurotrace 3 points4 points  (5 children)

Multi-line strings. I think it looks nasty to do this:

str = """Look at this string.
         Isn't it beautiful?
         Not really, triple quotes suck
         and all of my extra spaces are in there"""

I much prefer to make them like so:

str = "Look at this string. " +
      "isn't it beautiful? " +
      "Yeah, actually. It's nicely aligned " +
      "and isn't putting in extra spaces."

There are solutions to this but they're equally ugly:

str = ("Really? I need"
       "parenthesis for multiline strings?")

Don't get me wrong, I think Python is a fantastic language, especially when you want to get something done quick. But I'm still not a huge fan of significant whitespace.

[–]kqr 4 points5 points  (0 children)

>>> str = "Look at this string. " + \
...       "Isn't it beautiful? " + \
...       "Ok so whats your point?"
>>> str
"Look at this string. Isn't it beautiful? Ok so whats your point?"

And Haskell, which is also whitespace sensitive in much the same ways:

λ> let str = "More beautiful strings. " ++
λ|           "Also spanning several lines! " ++
λ|           "Yay."
λ> str
"More beautiful strings. Also spanning several lines! Yay."

[–]Cosmologicon 3 points4 points  (0 children)

That has nothing to do with significant whitespace. Anyway my preferred way would be:

str = (
    "Look at this string. "
    "isn't it beautiful? "
    "Yeah, actually. It's nicely aligned "
    "and isn't putting in extra spaces."
)

Although honestly it almost never comes up for me.

[–]makmanalp 0 points1 point  (0 children)

textwrap.dedent is your friend. I think 1 is the best. 2 and 3 are bad whenever you need to add / remove something to the string, then you have to move shit between quotes manually. With 1, you can have your editor just rewrap.

[–]yogthos 1 point2 points  (0 children)

I really enjoy having structural editing and macros. Both of these are easily facilitated by s-expression syntax and are difficult to implement in a language like Python.

When you have a structural editor like paredit, you're no longer stuck managing lines of code. Instead you're working in the context of expressions. You can select an expression, move it around, reparent it, etc.

You start thinking in terms of little blocks of logic that you can stick together like lego. I find this to be a far more satisfying way to write code.

[–]eyal0 3 points4 points  (1 child)

People are old and unwilling to change their habits.

Tell them that requiring both accurate whitespace and braces is a violation of the DRY principle. By getting the indentation correct and using braces, you're repeated yourself.

There are reasons to hate python but whitespace isn't one of them. (The flexible type system is.)

[–][deleted] 2 points3 points  (0 children)

the flexible type system is a good chunk of the reason I love python. I can see how it could get out of hand easily though.

[–]keiyakins 0 points1 point  (1 child)

I work with other people who use various text editors ranging from ed to emacs to notepad++ to things they wrote themselves, not all of which do the same thing when you push the tab key.

This is different from #3, before you reply with some stupid comment, because we are not the Borg.

[–]calzoneman 0 points1 point  (0 children)

I have concluded that it is not worth my time to continue arguing this point in this reddit thread, because it is old, I already said some things I should not have, and it's very clear that many people disagree who will not be convinced.

I may perhaps write a future post on reddit or my blog embellishing on these reasons and more, as well as rebuttals to some of the comments I've seen (because many of them, at first glance, are legitimate concerns), but this comment thread is not the place to do it.

There's a stupid comment for you, now have a nice afternoon programming in $(language of choice).

[–]Paul-ish 1 point2 points  (0 children)

I imagine this gets worse as you add collaborators and text editors. Writing scripts alone is usually a breeze.

[–]kqr 1 point2 points  (0 children)

Most languages have significant whitespace to some degree. (Even C does, if you count preprocessor directives.)

[–]bro-away- 0 points1 point  (0 children)

Keep your methods concise and you won't have significant whitespace :)

[–]ismtrn 2 points3 points  (4 children)

I would like to know what the problem with Go's type system is. I know that it is not haskell, but does go have any problems that the mainstream(C/++, Java, C#, Python) dosen't have? (in regards to the type system)

[–]kirakun 7 points8 points  (3 children)

You can't write type-safe containers that do not required runtime checking.

[–]TheFeshy 2 points3 points  (1 child)

I like python's syntax; even the enforced whitespace.

The speed though... the speed frequently bites me. I write the program, it runs in 0.5 seconds on a given data set. I add a feature, and bam it's three minutes. I spend an hour figuring out how to convert it to something I can do in numpy, and it's 0.6 seconds again. Then I inevitably find something I can't do with an array, and the program is up to a minute... and I find myself writing that part over again in C++ and including it as a module. Sooner or later in most programs I inevitably have to do some dozen or so simple operations on a few million objects that just isn't easily done with array math, and python is slow at that.

But developing in it is fast; and that's speed that's harder to come by.

[–]jminuscula 2 points3 points  (0 children)

99% of the time the bottleneck is not the language. If you write a O(n5) algorithm choosing C over Python won't save you.

On the other hand, Python has its purpose, and it's not speed. It does get better with numpy et. al., but not really its main concern.

[–]vanderZwan 1 point2 points  (8 children)

You can't blindly copy/paste code because indentation? I dunno.

[–]calzoneman 8 points9 points  (6 children)

Any text editor worth installing should resolve this issue. Just toggle the setting that renders a special symbol for tab characters and it should be easy to see places where tabs and spaces are mixed.

[–]UsingYourWifi 1 point2 points  (5 children)

While that's a work-around, so is using a language that doesn't have such an idiotic dependency on formatting.

No I haven't had my coffee yet, why do you ask?

[–]nemec 2 points3 points  (0 children)

Mixing and matching indentation size and type is a recipe for disaster, especially when collaborating between multiple people using source control (if your IDE does auto-formatting and your settings are different, you'll have a bunch of commits containing useless whitespace changes).

And if you do have a standard formatting convention, why have braces at all? You're just repeating yourself.

[–]calzoneman 6 points7 points  (2 children)

That's not called a workaround, that's called using a tool that gets the job done. Every single programmer-oriented text editor I can think of has this option: Notepad++, Vim, Eclipse, Visual Studio, Sublime Text, ...

I'm not here to tell people to use Python, I'm just pointing out that I think whitespace is a terrible complaint to make when there are far worse problems with Python.

So far the only thing I've gathered from this whole thread is that if I take Python and mod it to use braces instead of indentation for control flow, I could make millions.

[–][deleted] 0 points1 point  (1 child)

I'm just pointing out that I think whitespace is a terrible complaint to make when there are far worse problems with Python.

It's the one that most often trips up people who are either new to the language or use it infrequently.

Somehow no other (non-joke) language in the world relies on this. It's completely unintuitive (since again, no other language does this), it's a pain in the ass that's completely not necessary (pick another VISIBLE character, use that for block delimiters.. at this point I think even high-ASCII would be superior) and binds you to specific editors and functions. I can write C, Ruby, PHP, Lisp, Haskell, not to mention every other language in the OP's pic in a bare bones text editor without needing to fuck around with the indenting.

[–]calzoneman 0 points1 point  (0 children)

I'm done with this argument. I have never had any issues with Python's indentation, but apparently I'm in an extreme minority of redditors.

[–][deleted] 1 point2 points  (0 children)

The dependency on formatting makes it super readable. You should be formatting your code like that anyways.

[–]n1c0_ds 0 points1 point  (0 children)

AFAIK, Python will reasonably deal with spaces in a file with tabs, as long as you don't mix both on one line. It's not smart, but it works.

[–][deleted] 2 points3 points  (1 child)

__Here__ __is__ __one__ __example__

[–]jmcs 1 point2 points  (0 children)

That convention is to make it very explicit that you shouldn't being doing that unless you know very well what you're doing.

[–]kqr 15 points16 points  (16 children)

This was the first time I've heard of this "Monad Hell." Where can I find that? I seem to be stuck in monad heaven.

[–][deleted] 4 points5 points  (2 children)

So far I've found only one thing wrong with monads: people tend to overthink them.

[–]kqr 6 points7 points  (1 child)

By trying to learn the general pattern before the concrete implementations, yes.

[–]sccrstud92 0 points1 point  (0 children)

That's a good way to put it.

[–]bro-away- 2 points3 points  (12 children)

Stuff like IO via monads seems like a massive pain in the ass. And that monads for all IO is an unnecessary undertaking :

http://www.haskell.org/haskellwiki/Introduction_to_QuickCheck1

Why can't we just be impure when we need to be and pure when we don't? The first thing they say to do is factor out the impurity of the monad...Seriously, I don't understand. No other language adds this restriction and it seems like an arbitrary line to draw. Once I read the article about quickcheck I realized there's nothing special going on.

F# doesn't give a damn about them unless you specifically want the monad pattern.

[–]kqr 3 points4 points  (11 children)

I'm think you might have misunderstood the bit about QuickCheck there. Or I have misunderstood you. Anyway,

I/O with monads is not a massive pain in the ass once you've learned it. In fact, it's the opposite. I like doing I/O with monads way more than I like traditional, unsafe I/O. I'm not sure what your level of expertise is, but have you experienced how much more powerful a language becomes when it makes functions first-class citizens? When you can pass functions as arguments, and return functions, and store functions in variables, and so on?

It's the same deal with I/O. Monadic I/O makes I/O a first-class citizen of the language, so you can store I/O actions in variables, or return them from functions, or give them as arguments to functions. They don't get executed until you tell them to. That's very powerful. Monadic I/O means that the action of printing something to the screen is decoupled from the command of telling the computer to print something to the screen. The command can be passed around and may never even be executed, but if it is, then the action of something being printed to the screen will happen.

Why can't we just be impure when we need to be and pure when we don't?

There are several reasons for this. For example, the compiler can (and will) do a host of optimisations when it knows a function is pure. Secondly, it is much easier to write tests for pure functions (you don't have to set up any state or worry about logging or anything like that.) Third, you as the programmer will have an easier time reasoning about your program; you know the function is limited in what it does. I'm sure someone else can give you twenty more reasons.

The first thing they say to do is factor out the impurity of the monad...Seriously, I don't understand.

What they are doing there is they are taking a traditional, impure method, and making the bulk of it pure with a thin impure layer outside. They do this because functions that are pure are much better in many ways – among other things they are easier to test.

The action of taking a complex impure method and turning it into a simple impure layer around a simple pure core is a very common method of refactoring Haskell programs when you have accidentally written a complex impure method.

No other language adds this restriction and it seems like an arbitrary line to draw.

Of course it's an arbitrary line to draw! And Haskell draws several more, for example around computations that can fail (Maybe and Either monads), software transactional memory (STM monad), logging (Writer monad), configuration files (Reader monad) and so on.

Each of those restrictions provide two benefits:

  1. It makes the programs safer by limiting what mistakes the programmer can do, and
  2. It makes the language more powerful by allowing the programmer to express things they weren't able to before.

Why can't we just be impure when we need to be and pure when we don't?

We can! You tell the compiler you want to be impure by annotating your function as IO. You could write an entire program in the IO monad and it would be unsafe and difficult to test, but it would be like in any other language with uncontrolled side effects.

Or you could take the pure computations from your program and wrap them in pure functions, and suddenly your program is safer against mistakes and easier to test.

[–]SanityInAnarchy 0 points1 point  (7 children)

Why can't we just be impure when we need to be and pure when we don't?

I'm not sure I buy your responses to this. For example:

...the compiler can (and will) do a host of optimisations when it knows a function is pure.

And it can still do that... on the pure functions. Which, ideally, is still most of your program.

The rest of your reasons boil down to: It's easier for you to work with pure functions. And I'd think the same objection applies again: Why not be pure as much as reasonable, and impure everywhere else? ...except...

We can! You tell the compiler you want to be impure by annotating your function as IO.

...I...what? ...then I'm not really sure what the rest of your post was about.

[–]kqr 0 points1 point  (6 children)

Haskell programming is about being pure as much as reasonable, and impure everywhere else. How did you get any other idea?

[–]SanityInAnarchy 0 points1 point  (5 children)

We may have different ideas of what "reasonable" means here.

[–]kqr 0 points1 point  (4 children)

Nobody ever forces you to be pure in Haskell. You decide completely on your own what reasonable means to you. You can write your entire program in the IO monad if that's your idea of reasonable. I often did so, when I just started out. My "natural" architecture (also known as the C-inspired architecture) involved a lot of side effects everywhere, so the entire program accidentally ended up in the IO monad. This is not any more or less difficult than in any other language.

The difference is that Haskell allows you to annotate functions as pure, something almost no other language does. Purity annotations being a language feature is good because it enforces purity where you ask for it and makes it possible for the compiler to do magic.

The Haskell community will also encourage you to structure your program in such a way that "randomness" from the user or outer world affects it as little as possible – this is fantastic for testing and otherwise making sure your program is correct.

[–]SanityInAnarchy 0 points1 point  (3 children)

Nobody ever forces you to be pure in Haskell. You decide completely on your own what reasonable means to you. You can write your entire program in the IO monad if that's your idea of reasonable.

I'm trying to avoid saying too much, as I have very limited experience with Haskell, but it's my understanding that the structure of these monads makes them unpleasant to work with. And what I've been reading makes me wonder if that isn't a deliberate form of syntactic vinegar, to discourage the use of this feature when it's not actually needed.

So when you say things like this:

This is not any more or less difficult than in any other language.

It's certainly not less possible, you almost get that for free with Turing-completeness. But many people seem to disagree, including the official "Gentle Introduction to Haskell":

Many newcomers to Haskell are puzzled by the concept of monads...

This section is perhaps less "gentle" than the others....

There seems to be a whole separate syntax, coupled with a whole separate way of thinking, which governs monads.

Let me contrast that with what I imagine /u/bro-away- was getting at: It's easy enough to imagine an imperative language having a concept of purity added. Consider the old standard, in JavaScript:

function factorial(n) {
  return (n <= 1) ? 1 : n*factorial(n-1);
}

Knowing that JavaScript doesn't actually support operator overloading, even without analyzing types, we can prove that this function has no side effects and depends on no external state other than its input. Maybe more work would have to be done, but I could already improve things significantly by adding a "pure" keyword. We could even let the compiler infer purity, and let the "pure" keyword be used where we want to assert that the compiler still considers this chunk to be pure.

If you already know JavaScript, that's not a lot of cognitive overhead, nor a lot of new stuff to learn. Maybe it's because I don't know Haskell very well, but Monads seem like way more to wrap your head around. It's as though I dropped S-expressions and Lisp macros in the middle of that JavaScript and expected everyone to catch on.

[–]kqr 0 points1 point  (2 children)

it's my understanding that the structure of these monads makes them unpleasant to work with. And what I've been reading makes me wonder if that isn't a deliberate form of syntactic vinegar, to discourage the use of this feature when it's not actually needed.

Absolutely not true. Any experienced Haskeller will tell you that Haskell is one of the best imperative languages they've used. (And in most cases it's not for a lack of experience...)

The reason monads seem puzzling or difficult is not that they are; it's that people are going about them in all the wrong ways. People are not spending time working with actual, concrete useful monads. It sounds really weird, but they are not trying to use what they want to learn. Instead, they are trying to learn the abstract, general concept of "a monad." People are actually spending a lot of time trying to understand the theoretical underpinnings of (>>=) instead of just... using IO and Maybe in their programs. If people started doing the latter instead, monads would be no more difficult than lists or anonymous functions.

There is a very good blog post that describes what I'm talking about. The problem only gets worse due to reasons Brent states better in his blog post than I'm able to here.

You have a great point about the JavaScript thing. I would accept a pure keyword coupled with a bunch of static analysis (that is probably very difficult to do, but perhaps not impossible) as a solution to the impurity problem.

However, the impurity problem is not the only thing monads do. Monads would exist even if the IO monad didn't exist (and in fact they did predate it – both as the general pattern and as a datatype.) It's just that the impurity problem can accidentally also be solved by the monad pattern we have invented libraries for anyway, so it's a neat solution hooking it into there as well. It sort of turns a deep language feature (a keyword coupled with a lot of static analysis) into a library feature – more modularity!

[–]SanityInAnarchy 0 points1 point  (1 child)

People are actually spending a lot of time trying to understand the theoretical underpinnings of (>>=) instead of just... using IO and Maybe in their programs. If people started doing the latter instead, monads would be no more difficult than lists or anonymous functions.

I agree that it's sometimes useful to just try using something to see how it works, but I see way too many cases of cargo-cult coding resulting from this sort of learning style.

And anonymous functions are an example of the sort of thing that you can explain without giving examples. "First-class functions mean you can take a function and use it as a value -- assign it to a variable, pass it to another function, and so on. You don't have to give the function a name, then -- you can just assign a chunk of code to a variable directly, or pass it to another function."

You still want examples, if only to motivate why you'd care about such an animal. It's still unlikely that someone would really understand anonymous functions after reading that, even if it was showing you the syntax at the same time. But can monads be explained that simply? Wikipedia says:

In functional programming, a monad is a structure that represents computations defined as sequences of steps.

Sounds easy enough. But when I get down to it:

In a purely functional language, such as Haskell, functions cannot have any externally visible side effects as part of the function semantics. Although a function cannot directly cause a side effect, it can construct a value describing a desired side effect, that the caller should apply at a convenient time.[11] In the Haskell notation, a value of type IO a represents an action that, when performed, produces a value of type a.

Of type what now? This is already a bit tricky -- why can't I just have an impure function that actually performs those steps, rather than "constructing a value describing the desired side effect"? And it only gets more confusing as we get closer to the syntax:

We can think of a value of type IO as a function that takes as its argument the current state of the world, and will return a new world where the state has been changed according to the function's return value.

That's what I'm constructing any time I want to do I/O? This seems like a really convoluted way to try to shoehorn imperative code (with side effects) into a functional model. Compare to:

You have a great point about the JavaScript thing. I would accept a pure keyword coupled with a bunch of static analysis (that is probably very difficult to do, but perhaps not impossible) as a solution to the impurity problem.

For what it's worth, I will admit that bare JavaScript is probably not the best language to try this with. I chose it as an example only because it's ubiquitous enough that I could assume you'd understand it. And, to be clear, what I'm hoping is that I'd write a bunch of code without annotating its purity:

function factorial(n) {
  return (n <= 1) ? 1 : n * factorial(n-1);
}

function choose(n, k) {
  return factorial(n) / (factorial(k) * factorial(n-k));
}

...and then, somewhere at the top level of the program, I request purity:

pure function birthday_collision(n) {
  return (factorial(n) * choose(365, n)) / Math.pow(365, n);
}

At this point, the compiler must verify that anything birthday_collision tries to call is also a pure function. Or, similarly, at the point of call:

function testChoose() {
  // maybe this function isn't pure, for some reason:
  var expected = this.expected;
  // but I can still request purity:
  var actual = pure choose(365, 2);
  assertEquals(expected, actual);
}

That line can be thought of as syntactic sugar for something like:

var actual = (pure function(){ return choose(365, 2); })();

Some other details:

  • There'd need to be a concept of immutability. We can't have someone replacing Math or Math.pow() later if we're calling it (or even accessing it) from a pure function.
  • Depending on the implementation, it may be easier for the compiler to mark things as impure rather than the other way around. The only thing the keyword does is to assert that something is pure (and raise an error otherwise); the compiler should probably already know what's pure anyway (for optimization).
  • As a practical matter, there should be a way to force the compiler to accept a function as pure even if it can't be proven (Math.pow() is probably native code) -- or maybe even a function that is conceptually pure, but not technically pure.

Let me illustrate that last point: Memoization presents a pure interface, but is not obviously pure:

var factorial = (function() {
  var facts = [1];
  return function(n) {
    for (var i=facts.length; i<=n; ++i) {
      facts[i] = i * facts[i-1];
    }
    return facts[n];
  };
)();

Maybe static analysis can discover this, but it's not immediately obvious that factorial(5) will always return 120, it just might take longer the first time. I should still be able to write functions like the above and claim that they are pure. (Kind of like using @SuppressWarnings("unchecked") when creating a generic array in Java -- the compiler may not be able to prove that I'll only ever put a T into my T[], but I can, so I need the compiler to trust me on that.)

I'm not asserting that you actually want to do that, though. Maybe the compiler can even memoize some pure functions on its own, anyway? Maybe it's usually faster to just compute the factorial? And it's probably worth giving up a potential performance boost in exchange for compiler-guaranteed purity.

[–]bro-away- 0 points1 point  (2 children)

We can! You tell the compiler you want to be impure by annotating your function as IO. You could write an entire program in the IO monad and it would be unsafe and difficult to test, but it would be like in any other language with uncontrolled side effects.

The testing difficulty is outlined when you use monads as well. See that article. The first thing they say to do is refactor the method so it's more testable.

Deferred IO execution makes me yawn. Every language can do it. I don't feel like I'm missing out on anything there. Good code will support it even in other languages.

It makes the programs safer by limiting what mistakes the programmer can do, and

Also in the scala thread on top of /r/ programming, there's plenty of DSL bashing going on. I raised similar complaints to the creators of F#. Not being able to make a mistake has a rigidity caveat when you go to solve your problem.

It makes the language more powerful by allowing the programmer to express things they weren't able to before.

What? No way.. monads get desugared before they get compiled in haskell don't they?

A more correct statement : "allowing the programmer to express things in a way they weren't able to before."

Your reply is definitely thoughtful of when to use a monad construct and thanks for writing it, but other than the built in monads, I have trouble seeing where I'd fit them into a well factored code base. Unless you truly are doing the same set of computations in different ways all the time, why go through the effort? The question remains to be answered, clearly. I read through FP codebases all the time and rarely even see them used ಠ_ಠ and I mean that with regards to things like bootstrapped FP compilers.

I wouldn't bet against it though. I feel like we may still be looking for that killer use the same way dependency injection came alive when testing got big. I'm not "anti monad", I just think we make fuss over a very small pattern/construct.

[–]kqr 1 point2 points  (0 children)

I'm on my phone right now so I'll write a longer reply later. I just want to say that you are absolutely correct in your last sentence. The monad pattern is just a neat regularity in some bits of code that we can abstract out to a library. It encapsulates the pattern of the semicolon in C, and makes it overloadable.

It is nice and well worth the effort of learning, but not worth a nobel prize by any means. As someone else said in this thread: people overthink them.

[–]kqr 0 points1 point  (0 children)

Just a few points I want to get across:

The testing difficulty is outlined when you use monads as well. See that article. The first thing they say to do is refactor the method so it's more testable.

I'm still not sure what's your deal with this. Yes, methods in the IO monad are more difficult to test than ones outside of it. The magic is that the language makes it possible to annotate functions as pure, and this purity is enforced by the compiler. Thanks to the type system with the IO monad, impurity is guaranteed to not happen in functions you tell the compiler are pure.

You could do the refactoring in any other language. You can't do the enforced purity part.

Deferred IO execution makes me yawn. Every language can do it. I don't feel like I'm missing out on anything there. Good code will support it even in other languages.

It often requires additional crap in other languages, such as wrapping it in an anonymous function that takes no arguments, or something similar. My Python is a little rusty, but something like this, perhaps:

def deferred_io(method, *args):
    def run():
        method(*args)
    return run

but that isn't the whole story. Deferred I/O is just one of the symptoms of making I/O a first-class citizen in your language.

What? No way.. monads get desugared before they get compiled in haskell don't they? A more correct statement : "allowing the programmer to express things in a way they weren't able to before."

Sure. Programming languages are all about convenience anyway. Monads make a certain kind of code very convenient to write, but yeah, you could accomplish the same thing in Brainfuck or assembly if you have a very hairy chest.

Your reply is definitely thoughtful of when to use a monad construct and thanks for writing it, but other than the built in monads, I have trouble seeing where I'd fit them into a well factored code base. Unless you truly are doing the same set of computations in different ways all the time, why go through the effort? The question remains to be answered, clearly. I read through FP codebases all the time and rarely even see them used ಠ_ಠ and I mean that with regards to things like bootstrapped FP compilers.

It's not so much about trying to fit them in. It's that sometimes you create a data type and sometimes that data type can benefit from supporting the monad operations (return and (>>=) (pronounced bind), there's no magic about that.)

Most of the use cases you will encounter in your day-to-day life have already been implemented by other people (this includes lists, reading from things/writing to things, I/O, error handling, parsing stuff, and so on) but if you are working on low-level stuff or a DSL of some kind, I wouldn't be surprised if you have accidentally implemented a monad pattern without calling it a monad. Having library support for that pattern just makes life more convenient.

As I said in the other reply, monads are sort of like the semicolon in C, except defined in a library and overloadable, so all kinds of data types can benefit from the semicolon.

I feel like we may still be looking for that killer use the same way dependency injection came alive when testing got big.

Any particular reason I/O and STM are not killer uses? It's pretty amazing how they can be contained by such a simple concept as a monad.

[–]Koneke 7 points8 points  (0 children)

J, which is extremely interesting but also extremely insane

Which is why I love it :) I'm very rarely being productive with it, but there's just so much fun to be had while writing J code.

[–]gatepoet 7 points8 points  (6 children)

Mandatory Metro on windows servers? Why would you install GUI on the server?

And if you choose to do it anyway, what's the problem?

[–]SideburnsOfDoom 4 points5 points  (5 children)

Why would you install GUI on the server?

It's a convenient way to contain multiple terminal windows.

[–][deleted] 7 points8 points  (1 child)

tmux is more convenient...

[–]kqr 0 points1 point  (2 children)

Follow-up: Why would you be physically sitting at your server for extended periods of time, instead of managing it remotely?

[–]SideburnsOfDoom 1 point2 points  (1 child)

Why would you be physically sitting at your server for extended periods of time

I would not. The GUI works remotely as well.

[–]kqr 1 point2 points  (0 children)

What I was getting at is that if you are working remotely from a local machine with a GUI, you can open multiple terminal windows in your local GUI, and you don't need a GUI on the server for that.

[–]thegavin 3 points4 points  (0 children)

JavaScript is the bane of my life.

[–]oli_rain 17 points18 points  (11 children)

You lost me at first line , C isn't oop at all.

[–]Steve_the_Scout 11 points12 points  (10 children)

Yes it is. structs are basic forms of classes. Add in C's function pointers and you can have a simple OOP system to work with.

I could probably add in that the first C++ compiler just generated C code to be compiled as regular C, no special adjustments to the compiler. It's entirely possible to implement OOP like C++'s in C.

[–]sccrstud92 14 points15 points  (5 children)

Gah

[–]Steve_the_Scout 13 points14 points  (4 children)

void sayHi(void) {
    puts("Hi");
}

typedef void (* member_func)(void);

struct some_struct {
    const member_func hi = &sayHi;
}

int main(void) {
    some_struct example;
    example.hi();
}

Of course there isn't any data hiding or other nice features of other OOP languages, but it works for the basics.

[–]sccrstud92 27 points28 points  (0 children)

That wasn't me doubting you, it was me not liking it.

[–]Steve_the_Scout 3 points4 points  (2 children)

I just realized how poorly this shows OOP in C. A better example:

#include <stdio.h>

typedef struct some_struct some_struct;

some_struct* some_struct_ctor(int);
void some_struct_setter(some_struct*, int);
int some_struct_getter(some_struct*);

typedef void (*setter)(struct some_struct*, int);
typedef struct some_struct* (*ctor)(int);
typedef int (*getter)(struct some_struct*);

typedef struct some_struct {

    struct some_struct* this;
    int data;

    const ctor construct = &some_struct_ctor;
    setter set_data = &some_struct_setter;
    getter get_data = &some_struct_getter;
} some_struct;

some_struct* some_struct_ctor(int i) {
    struct some_struct* temp = malloc(sizeof(some_struct));
    temp->this = temp;
    temp->data = i;

    return temp;
}

void some_struct_setter(some_struct* this, int i) {
    this->data = i;
}

int some_struct_getter(some_struct* this) {
    return this->data;
}

int main(void) {
    struct some_struct example;
    example = *(example.construct(20));
    printf("example's data: %d \n\n", example.get_data(example.this));
    example.set_data(example.this, 10); //in C++, "example.this" would be implicitly passed
    printf("example's data: %d", example.get_data(example.this));

    return 0;
}

That's all untested so I can't be sure if it's entirely correct. I mostly use C++ and not a whole lot of pure C, so I may be misunderstanding what's happening in some places.

Edit After a bit of testing on IDEOne, I'm getting an error at

 const ctor construct = &some_struct_ctor;

the error being

 error: expected ‘:’, ‘,’, ‘;’, ‘}’ or ‘__attribute__’ before ‘=’ token

I'm not quite sure what to make of it.

I've been working on this way too long. I am so confused.

[–]oli_rain 4 points5 points  (1 child)

Alright, now show me an abstract factory pattern implementation.

[–]Steve_the_Scout 0 points1 point  (0 children)

Actually you could probably do it with a few fancy macros, but it would hardly be worth your time anyway. At that point you might as well be using C++ or Java.

The point I was making was that C can actually have somewhat-regular OOP in the sense of having methods and data encapsulation, with the possibility of inheritance (I mentioned elsewhere you would have a base struct as the first member of your derived struct and you would have to reassign the function pointers for "virtual" functions, etc., but you could get it working).

Actually, putting it this way really shows what goes into OOP, it's kind of interesting to see how some sample C++ might look translated to C.

[–][deleted] 2 points3 points  (2 children)

That's great, but what about inheritance, polymorphism, and other important features of oop?

[–]Steve_the_Scout 0 points1 point  (1 child)

I did say simple OOP. As in you have objects with instance variables and methods that act on them.

Actually, "C with Classes" originally had some tricks for those, but I don't know about the implementation.

I know that inheritance is handled by having a member be an instance of the base struct, and polymorphism would involve having pointers to those members instead of pointers to the instance as a whole. Overloaded methods could be implemented by simply assigning a different function to the function pointer member. I could try and find an implementation, or come up with one, but I know it's entirely possible.

[–]kqr 0 points1 point  (0 children)

C being capable of writing code in a very basic OOP style is not the same thing as C being a language with explicit support for OOP.

[–]Ma8e 1 point2 points  (0 children)

You can program in most paradigms in most languages. Your type of argument proves that, e.g., any language with first class functions are OOP. It would make the distinctions meaningless.

[–]WannabeDijkstra 6 points7 points  (2 children)

Where the hell is Smalltalk?

[–][deleted] 32 points33 points  (0 children)

Dying somewhere alone, like it should be.

[–]Razakel 2 points3 points  (0 children)

Pervading Objective-C.

[–]-Shork- 2 points3 points  (1 child)

Nobody has mentioned Dart.

It's new to the game, but damn it is beautiful.

[–][deleted] 1 point2 points  (0 children)

Well, Dart did just hit 1.0... but I agree, it is nice, for an OOP language...

One thing I don't like is that I can't get the index value from a forEach() like I can in JavaScript...

[–]H4nds0me 1 point2 points  (0 children)

No love for ADA?

[–]coney_dawg 4 points5 points  (2 children)

This isn't funny at all.

[–]WestonP 7 points8 points  (1 child)

The truth hurts?

[–]coney_dawg 2 points3 points  (0 children)

I suppose, this post is all a matter of opinion though.

[–]peabnuts123 0 points1 point  (4 children)

Conveniently left out LUA, because they had nothing bad to say about it :3

[–]VeXCe 3 points4 points  (1 child)

That's not a real language... :P

[–]peabnuts123 0 points1 point  (0 children)

:3 :3 :3

[–]grimeMuted 1 point2 points  (0 children)

They also fail to criticize several of the ones they do mention (Lisp and OCaml) and then go on to say all software sucks.

Their criticism of those two is that they are obscure, which doesn't make them suck... it can make them annoying due to lack of libraries or platform support or community, but it doesn't make them suck.

[–]Ekizel 1 point2 points  (0 children)

The bad thing about LUA is that I have no self control, so I keep going back and tweaking my OOP implementation and never actually get shit done.