Hacker News new | ask | show | jobs
by bphogan 3803 days ago
Yet the code behind the REPL knows exactly what I was attempting to do and tells me that.

This is what Ruby developers mean when they say they optimize for developer happiness over bowing to the will of the computer.

/uses Python regularly and enjoys it.

3 comments

Those assumptions that "optimize for developer happiness" 95% of the time make the developer's life hell the other 5% of the time. It happens often enough that "explicit is better than implicit", within reasonable constraints like dynamic typing, is one of Python's core values, and experienced developers usually come to appreciate it.

It's best to design an API that makes what's happening clear without being overly verbose or esoteric, and without making assumptions, especially not dangerous assumptions that may cause you to lose data (exit may close the REPL and cause you to lose your session when you forget that exit is a special word in REPL mode). My personal feelings are that Python has done a better job at this than any other major language. I have major projects in both Ruby and Python and I enjoy the Python ones 100x more because of this.

This document partially explains why; DHH is normalizing shortcuts because it helps him gain new users, even though working around those same shortcuts becomes a major PITA when you need to go a little bit off the beaten path, which happens in one way or another in most real software. There is a way to make these things explicit with only marginally more typing/"effort" (for example, requiring parens to call functions with no arguments, making it explicit and obvious when someone is referencing a variable vs. when they're calling a function), thus avoiding the complexity down the road.

> and experienced developers usually come to appreciate it.

I find statements like this a bit condescending. It's like when Java developers say 'Oh, that's nice, but I work on big applications." "Obviously you don't get it because you're not experienced. Experienced developers get it."

I'm sure that wasn't your intent. But it still irks me a bit.

I've been writing software for a very long time, in many languages and paradigms over the years. I believe that qualifies me as an experienced developer. My years of experience tell me that if I only experience pain 5% of the time, then the 95% of the time I don't experience the tools I use making me do extra work more than makes up for it. :)

>I'm sure that wasn't your intent. But it still irks me a bit.

Correct. I meant it inclusively, like most of the Python community is either experienced developers who've worked in a lot of languages and have sought refuge in the sanity of Python or the apprentices of such developers. Python doesn't have a figure like DHH to give it sex appeal, so not many new people use it.

There are definitely experienced developers who have not yet had occasion to seriously enjoy and appreciate Python.

>My years of experience tell me that if I only experience pain 5% of the time, then the 95% of the time I don't experience the tools I use making me do extra work more than makes up for it. :)

I meant this as a count of the number of issues, not the amount of time it takes to resolve them. That 5% of problems caused by non-obvious implicit magical behavior usually take an inordinate amount of time to debug and solve, and then the workarounds are usually disgustingly ugly because the framework had never conceived that someone might have a valid reason to circumvent their magic. Even worse, this locked-down, "looking inside will void your warranty" attitude (which Rails often calls "convention over configuration") frequently means that the workaround must be somewhat pervasive and ugly up your code not just in one place, but in several places to really resolve the problem.

Experienced developers may not encounter this often if they don't use a lot of magical APIs that promote the systemic ambiguity of "do what I mean".

> Even worse, this locked-down, "looking inside will void your warranty" attitude (which Rails often calls "convention over configuration") frequently means that the workaround must be somewhat pervasive and ugly up your code not just in one place, but in several places to really resolve the problem.

In 2005, when nobody used Rails, as a complete beginner to Ruby, I was able to write a patch to improve the Oracle database adapter. Somehow, despite all the magic, it took me very little time to find what to change and submit a patch. As a complete newbie to the language and platform.

Rails 2 and below revolved around a lot of hacks. Rails 3 removed many of those. Rails 4 even more so. Check out the book "Crafting Rails 4 Applications" to see how easy it is to hook into places in the framework to get what you need. (Disclosure: I'm the editor of that book.)

The argument you make about "voiding the warranty" is an argument I hear from people who have touched Rails for a project and hated it for one reason or another. It's not a sensible argument.

Remember, for centuries, people used "magic" to explain away something they didn't understand. :)

>In 2005, when nobody used Rails, as a complete beginner to Ruby, I was able to write a patch to improve the Oracle database adapter. Somehow, despite all the magic, it took me very little time to find what to change and submit a patch. As a complete newbie to the language and platform.

One part of the system not being obfuscated doesn't mean that many other important parts aren't.

>Rails 2 and below revolved around a lot of hacks. Rails 3 removed many of those. Rails 4 even more so. Check out the book "Crafting Rails 4 Applications" to see how easy it is to hook into places in the framework to get what you need. (Disclosure: I'm the editor of that book.)

I currently maintain both Rail 2.3 and Rails 4 applications. I totally agree that Rails 4 is a much smoother experience. There are still hacks around the magic that I've had to implement. The one most immediately on the top of my head is one of the form generators ignoring the method argument in some circumstances because it knows better and forcing me to jury rig them into obeying the command anyway (with a bit of JavaScript that alters the method on-page IIRC).

>The argument you make about "voiding the warranty" is an argument I hear from people who have touched Rails for a project and hated it for one reason or another. It's not a sensible argument.

Of course it's a sensible argument. Frameworks shouldn't be causing those feelings in people -- the magic isn't magical if it's getting in the way. If people are coming away with the impression that the system will blow up or otherwise misbehave when they try to peel back the covers, it's ignorance to just blame them for feeling wrong. One should try to at least understand the problem; then, you can decide if it's a problem that needs correction or if you're just OK with people who want some flexibility and cooperation from the framework not using your stuff and be honest about that so that they don't have to waste their time.

>Remember, for centuries, people used "magic" to explain away something they didn't understand. :)

And, also for centuries, people used "magic" to hoodwink gullible people.

Ruby + Rails has always been better at social engineering than any other language or environment.
> Yet the code behind the REPL knows exactly what I was attempting to do and tells me that.

Not really – all the code knows is to stringify objects, and it saw the object called `exit`, for which the stringified version is that error message. But nowhere in that flow does the code know how call anything that could exit the REPL.

/doesn't use Python regularly and thinks the smart move would be to make the REPL understand certain things as commands instead of normal Python code.

Well, the __repr__ method on the 'exit' object is getting called. So that method could actually call sys.exit() and cause repl to exit. But it would be very rude and strange behaviour for calling a __repr__ method to exit the interpreter, or, indeed, to do anything other than return a string representation of the object.
What someone more clever than me ought to do is write up a huge investigation of an obscure bug caused by exit.__repr__() calling sys.exit(), and then only at the end comment that it's not real, but could've been if Python went down this road.
Why? quit and exit are imported exclusively at the REPL: https://docs.python.org/3/library/constants.html?highlight=e.... Would it really be any worse than automatically assigning the result of the last expression to _?
Point well made.
And quit calling exit isn't weird?
If the REPL initiates an exit via throwing an exception (eg.g new QuitException ) and having the top level of the stack catch it then handle the termination, then you could have the stringification of exit throw that exception too.

It's not really magic at that point. It's not really 'magic' at that point to me.

Granted some people might say its surprising for stringifying an object to call sys.exit() or throw an error that'll cause exiting.... But within the context of the REPL its not surprising.

Whatever method you take, whether it's a special case after reading a line, or some other weird hack, you're adding magic.

With Ruby, this isn't a big deal because if `exit` is a function, then typing `exit` will call it, and you need to use the unary `&` to bypass this and have the callable treated the same way that Python does (which is roughly equivalent to a Ruby Proc).

Ruby doesn't require the hack, but Python would, for better or worse.