I don't like Python. Does that make me a bad person?
I love C. I like C++ too. I used to write a lot of Java when I was a kid (as in high-school kid) but now that I've written quite a bit of C and C++, Java seems more like a toy language. I did enjoy Java back then, however. I yet to do any major work in C#, but it seems to be a powerful language, especially when handling certain kinds of complexity.
I've been learning LISP on weekends for two weekends now, and I find it interesting. I know little bits of Haskell (am planning to learn it later this year) and seem to like it too. Maybe I like the idea of liking Haskell, I'll know for sure once I actually start writing Haskell.
Coming back to the point - I don't like Python. I've never liked it. I've tried working on various Python projects but have always found some or the other excuse to prematurely back out. And mind you, I love coding - I spend most of my time writing code or learning new stuff about code.
My question to the hardcore python lovers is this (and mind you, by hardcore I mean the kind of people who wrote Exaile, not the kind who hack up a Python script every now and then to organize their iPod): No doubt many of you have come from C / C++ / LISP backgrounds. What is the paradigm shift you experienced? I look at a piece of C code in a certain way - how do I look at a piece of Python code? How do I think about Python? How do I think in Python (copied that one from Bruce Eckel)?
230 comments
[ 4.1 ms ] story [ 282 ms ] threadI'm not against the non-Perl philosophy of There Is Only One Way To Do It, but for God's sake, don't insist on indentation! I am under a personal vow that until Python lifts its indentation requirement (say, via a command-line switch), I'm no way using this language for my programming needs.
If there was a command line switch, would you use it? Why?
Technically, your editor should take care of that for you, but some of them don't do it properly (and sometimes can't do it properly), and it really sucks.
Well, everything has a downside :)
Do any exist for Python or Perl?
1. People don't indent consistently. There are a lot of (imo, pointless) arguments about where to place the braces, etc. One of the advantages of the language forcing a style is that arguments about it are no longer necessary.
2. Why should tools be taking care of this? People indent to understand the code better. Everyone agrees that you have to do it. So what's the problem with the language forcing you to do it? I'd rather it be part of the language than an external tool enforcing it.
But in Python, you don't even have to worry about other people not indenting their code!
I guess the only complaint I might have is why bother thinking about indentation, ever? Throw in a couple of {} and now the tools can provide additional help.
When you edit Python, the tools can already help as much. The start of a block is obvious (def, if, for, etc), so tools indent for you. To dedent, just hit the right key (e.g. a backspace on an empty line in emacs) -- no harder than hitting the brace key.
I don't like Python either and prefer Perl. (In Python I did not like indentations, dicts, tuples, lists, and the IDLE gui.)
To my knowledge, this is no worse than the expectation for a braced language, but much better than the worst case for a braced language.
If you mean something simpler than I've taken you to mean, e.g., the conversion of a whitespaceless C program into a whitespaced one, I concede you are mostly correct (';' still works in Python), but I must admit I would still not yet see your point.
In languages whose blocks are closed using nonwhitespace the problem doesn't exist. Your indenter just has to push everything as far to the right as it can, and problem solved.
It's nice that your editor gets copy and paste right, but it doesn't and indeed can't decide how to indent your code, something that works in every other language I've dealt with.
In brace language:
if (condition) {{ code_1 }} code_2
In Python:
if (condition):\n code_1 \n^H code_2
Unless your editor also knows when to place your close braces, and, haha, it doesn't and indeed can't, you have not even won a keystroke.
It's got nothing about saving keystrokes.
And now, back to working on pass-infested Python code.
This kind of "automatic indentation" (colon-enter to indent, a quick backspace to unindent) feels much more natural to me than a C-style indent, where the editor's cue to indent would be space-rightbracket-enter and leftbracket-enter to unindent.
True, one cannot come accross a completely unindented block of python code and ask the editor to format it correctly for them. But by definition, unindented code is not valid python and will not run. This is not unlike C / C++ / Java code that's missing all its braces, which would not run either.
The pain of keeping indentation correct is a forced ongoing investment in readability that is well worth it--at least to me.
I'm glad that haskell also has whitespace rules.
It's also fun to spend an hour looking for a bug caused by somebody inserting a tab instead of a space somewhere. We had a production crash that took us a long time to fix because somebody hotfixed a file with the wrong editor and did this.
I also don't understand how forcing people to indent code in the same way magically makes people write good code. The kind of programmer that can't or won't indent his code properly is introducing bugs far more serious than bad layout into your project.
Python's a nice language in many ways but I consider the syntax to be a bug.
Hotfixing is a naturally perilous process regardless of language. I've spent hours tracking down untested hotfixes in Java.
You're also probably less likely to come across a badly formatted block of python code because that would generally result in a bug. Much like misplaced brackets in Java/C/C++ would result in a bug.
It doesn't make the code magically better. It makes it less redundant. Indentation should already be there, why do you need curly brackets?
Copying and pasting is also known as refactoring. A syntax that makes that much harder than it needs to be is mis-optimized, IMO.
This. I'm convinced half the reason Ruby is displacing Python is that it's actually practical to talk about Ruby code in forums without ridiculous little-known workarounds like pastebins.
The Ruby community itself does strike me as more energetic though. All the activity on github etc seems a lot more impassioned to me than the coolheaded & practical world of Django et al.
And to the parent: I really hate to be "that guy", but can you give me an example where non-indented code looks better than indented code (since all your complaint really is about is style rather than what Python can help you do)? If it's just braces you're after, Python "supports" those by just commenting them out. When I first learned Python years back I was coming from a PHP and some Java background, and my code was sometimes single-space-indented, sometimes not indented at all, and it was hideous. After I realized I should be indenting anyway, Python made a lot of sense, all these languages with braces or 'end's everywhere didn't, and I can't think of any case I've ever thought "Man, I wish I didn't have to indent here." The one thing I can say I don't exactly like about Python now is the occasional self-hell.
Of course, most situations can be solved by a backslash-enter, and simple statements can be separated by ; but there are places where I wished for more flexibility.
This is only about readability, and overall Python code tends to be more readable than in other languages, although I've read beautifully written code in Java or Perl or C++, and the readability really depends a lot on the programmer writing it.
I think the major problem is the lack of focus in high-school / college on such things ... quite the contrary, many teachers are usually disconnected from real-world projects and don't have this skill themselves.
http://google-styleguide.googlecode.com/svn/trunk/pyguide.ht...
In fact at Google the maximum line length for python code is 80 characters because long lines make the code unreadable, and following the style guide basically anything can fit in a nice and readable way.
Of course I prefer Ruby, but that's a whole other can of worms :)
The only time I've had a problem with indentation is while copy-pasting things, occasionally that can get messed up and be annoying. Everything else is fine.
There are some interesting ideas regarding the use of whitespace in C here:
http://www.quinapalus.com/coding.html
I don't agree with everything he has to say- for example, I think his nested for loop example would be far nicer as something like this:
(Not to mention more in keeping with the principle of "alignment".) Still, if nonstandard indentation can make it easier to see the patterns in your code, it benefits both development and maintenance.for (i = 0; i < 1000; i++)
IMHO, such patterns (multiple nesting with empty outer loops), in most cases, are really an indication of just one real loop. Using multiple counters might also be an option.In case the loops are doing something different, they should be indented separately. For instance, the following makes little sense:
for (i = 0; i < 10; i++) {
foo (i);
for (j = 0; j < 10; j++) {
for (k = 0; k < 10; k++) {foo (i + j + k);
}
}
}
Let's say I'm making a simple tile-based game that uses a two-dimensional array called "grid" to store the map. To draw that map to the screen, I might do something like the following:
There are other ways to refashion this as a single loop, (storing everything in a 1d array and handling the dimensioning ourselves, using an iterator and giving tiles a position attribute containing their (x,y) coordinates, etc) but is any of that really more straightforward?Again, I am not arguing for indentation anarchy, merely that there are times when it can help to bend the rules.
edit: I imagine you'd prefer something like this?
BTW in haskell whitespace is optional but nobody write code that way.
I couldn't believe all the junk Java required of me when I took a stab at it. It's like being confronted with some unhelpful bureaucrat: I know what I mean, they know what I mean, but they're damn well going to make me trudge through all the nonsense so that what I mean is turned into something the bureaucracy understands. The linked NLP examples are great for illustrating this.
A language that needs you, the client programmer, to define getFoo () and setFoo () methods manually can't be right.
what do you think of ooc-lang syntax? http://ooc-lang.org/
Just an opinion, though.
another example: functions should be virtual by default.
No no no!
C++ got this one right, and then C# did better ('virtual' to declare a virtual/overridable function in the base class, and 'override' to replace it in the subclass).
http://www.artima.com/intv/nonvirtual.html
Every time you say virtual in an API, you are creating a call back hook. As an OS or API framework designer, you've got to be real careful about that. You don't want users overriding and hooking at any arbitrary point in an API, because you cannot necessarily make those promises. And people may not fully understand the promises they are making when they make something virtual.
It seems like Java wasn't defined in order to be an efficient for a three-person shop to hack in. It was meant to be efficient for a 40 person shop to build code as a team that they can maintain.
That said, I dread going back to my Java projects and updating them, even though I tried to maintain best practices in order that updating be as simple as possible. I've been immersed in php and javascript lately, so we'll see what it's like to go back.
I also tried to stay close to the OO paradigms (of course, I was just learning them), as I built this 50000 line beast called "Egorg." Now, I get to maintain and update it, so we'll see if it paid off.
On a side note, I have a real distaste for objects in Javascript. They seem clunky, almost like they were stuck on as an afterthought (I get a similar feel about Generics in Java). But the design of Javascript makes it quite easily to hammer out a script to do something cool. I'm worried about maintenance, though, because I feel like I'm evolving my own design patterns, so retracing my steps will likely be painful.
You are correct about the IDE thing. That does ease a large burden in Java.
I think that this is happening to many people who are doing a lot of 'non-trivial' JavaScript. The language is still very young and because the concepts that were chosen when creating the language are powerful and flexible (prototypal inheritance, objects can be accessed like hashes, first-class functions etc) there's always a million ways to code something.
OO-wise i think you can divide into those who use the `new` keyword and build objects that are more or less Java-like classes and those who create objects and prototypes on the fly, and probably use a lot more ideas from the functional and LISPy side of things.
My worst crime by far (that I am aware of) is that I have no hesitation to use a global variable if it saves me from bending over backwards to get around it. I'm doing animations, and sometimes the algorithm just comes to me a lot faster if I let a var keep a global value and be used by lots of functions between calls to my animate() function (using window.setInterval() ).
JavaScript is language that is very different from anything else. Depending on how you look at it it has either unconventional semantics (majority view) or unconventional syntax (my view). It's object model is strong and often useful (you can emulate class-based inheritance with it, not the other way around), but I agree that it is to some extent afterthought (although I have strong feeling that our reasons are very different). What is probably largest problem of whole JS is the "Java" part of it's name and weird syntax deliberately designed to "look-like-Java" or "look-normal", which simply does not match underlying semantics.
Coming from C/Unix background I actually consider the IDE thing burden in itself. I expect that there are some easily editable source that is transformed by series of some steps into final program, but all changes happen only in the original input. Which is simply not case in Java/ST world, where you essentially need pretty complex IDE (on the side note: few years ago some Java IDE I was using for quick experiment forbade me from saving source file with syntax error with it... WTF?).
What I find really cool about your comment is that you appear to have a deeper view of it all (meaning a deeper understanding of the underlying semantics), and I'm wondering how my view will change as I continue to work with it.
*I realise that pro Java coders use Eclipse to generate their getters and setters, but I have also drank deeply of the vim kool-aid and find myself going to ridiculous lengths sometimes to avoid other editors or IDEs. I keep trying to navigate with the wrong keys and trying to save with :w and using :sp to open other files when I use them.
Now what I do, which goes against stated policy, is keep the CustomerData variables (String name, int custId, and so on) public so I can set them easily. The only time I require getters and setters for primitive types (for example, name) is if I were to read in data from a user generated form that needed to be sanitized.
My apps are full of these customized data objects, and it's a technique which has saved my ass as I added features etc.
If you encapsulate all the data about a customer in a "CustomerData" object, do you really need a separate "Customer" object? Or do you mean, not the whole customer but larger bundles of information like addresses etc. that don't need any business logic or abstraction but are nice to have as one single bunch of data?
(I mean, there's a reason why C++ still has "struct"s even though OO zealots will tell you they come from the devil).
Edit: I didn't parse the "ouch" the first time I read this. Sorry, I'm not trying to be an ass about it. But when I first started trying to figure out the "right" way to do it, I came across something (probably by Allen Holub) that confirmed something I was suspicious about: There is no sense in having a private variable if you are just going to expose it with public getters and setters (except for sanitation purposes). The real point was to pass in the data through data objects, and keep the private members unexposed. This also means (typically, at least for me) a lot fewer getters and setters. It's completely against the Java Beans "way," I think, but it works well in real life. I use Java Beans only for persistence, because I like the automatic JB-xml conversion. That is, I make data objects out of the data that I want to store into a Java Bean, and do the automatic xml storage and read thing. It took me a while to figure that out. My first app, I hand-coded the xml. Ugh.
It's funny, too - though this type of thing goes against best practices, the primary argument for always using getters/setters (some day you might need to validate input or do other sorts of logic, and it's a pain in the ass to put that in after the fact) is pretty much 100% shattered these days, because any IDE worth a damn makes it possible to switch from public field access to getters/setters in a couple of keystrokes ("Encapsulate field" and "Inline method" are typically all you need).
Though it's worth keeping in mind, most of the Java best practices tend to assume that you're writing code that other people will have to use, people whose codebases you won't have access to after you release your code, and that's a much more difficult context to program in. It requires a lot more bureaucratic nonsense to leave your API flexible when you have to worry about breaking other people's code with each edit you make, and extreme paranoia is more than justified when that's what you're worrying about.
If you want Java without the unwieldiness, try Groovy. It's Java with a ton of syntactic goodness added; for instance, the default variable scope is "create a getter and setter which I can optionally override." Groovy interoperates well with Java libraries. The downside is that it's a dynamic language, so there is a significant performance penalty.
"Secondly I don't mean to criticize Java. By calling it a toy language, I was simply referring to the fact that Java tends to make writing bad code difficult, and in doing this takes away some of the flexibility and power that you tend to associate with other languages."
Judging from the general reaction it seems I should not have used the term "toy language". My apologies if I ended up implying that Java has little practical use.
I've known people who could write bad code in Java with the utmost ease!
It'd probably be more accurate to say that Java deliberately limits its expressiveness, in order to make it harder for people to shoot themselves in the foot, and to make it easier for one programmer to understand what another has written.
That is exactly what I meant.
Bad programmers exist. They will write bad code, no matter what language they're made to use.
If this were actually the case, it would be a bonus point for Java. It isn't, however. Nor is it the case for Python, Ruby or even BSDM languages like Ada.
How many times have you come (when searching for a used car or trying to reserve a table at a restaurant) to a slow, ugly, non-functional URL that creates an error message if you press the wrong button at the wrong time? Usually those URL ended in ".jsp", ".asp[x]" or ".cgi" or ".php".
I'd argue, that the largest amount of bad code that exists is in Cobol, followed by Java, C# and then C/C+, PHP and various BASIC dialects. That has nothing to do with how good those languages are but rather with the facts that most code out there:
a) is created by IT departments or outsourcing firms staffed by mediocre or completely disinterested programmers (I've never been in such an environment, but my hair stands up every time I read horror stories on dailywtf or on progit)
b) shouldn't have been created in the first place (there are commercial and open source packages that do this) if it weren't for the NIH symptoms. There are tons of restaurants with their own order/registration forms despite the fact that OpenTable is widely known and available. There are tons of non-technology companies writing their own accounting systems even though there's a multi-billion/year industry around that type of software (that employs programmers who understand not just J2EE but accounting itself as well).
c) is forced upon its users (due to the sunken costs fallacy) and thus isn't exposed to market forces
d) is written in those languages as they're most common and are either easy to learn (PHP, BASICs) or are widely taught in colleges or trade schools (Java, C#, C++)
Truth is, there is no magic language bullet. Some languages are more expressive, more pleasant to program in. Some produce faster code. Others are more scalable in the sense of making it possible to write whole systems in one language. Some are more "safe" in the sense of being less prone to garden variety security attacks, less likely to crash the entire machine when there's a bug (at the cost of imposing restrictive abstractions on the programmer).
No language, however, is a substitute for a team of competent and interested developers solving a relevant problem.
The following code is readable and I have required a variation of it in a program before:
Doing it in Java would be a chore now.(Set("letters in this sentence":_* ) & Set("and this one":_* )).toSeq.sorted.reverse
Or you, can take advantage of Scala's rich choice of collections.
import scala.collection.immutable.TreeSet
import scala.math.Ordering._
TreeSet("letters in this sentence":_* )(Char.reverse) & Set("and this one":_* ) toSeq
The machinery Scala has in place to make the second example work is quite impressive, and I was pleased to see that it worked. Even though the intersection method returns a brand new set, using implicit arguments it correctly creates a set of the correct type (TreeSet) with the correct ordering function (Char.reverse), without any duplication of code in the standard library (like overriding '&' in every sub-class).
("letters in this sentence" + "and this one").chars.sort.reverse
I can just as easily write ("letters in this sentence" + "and this one").toSeq.sorted.reverse in scala. You could tag the end of your ruby statement with .uniq and you would be fine. Alternatively, you could wrap the above scala statement in TreeSet(). These solutions process things in a significantly different way than was done by the OP, though.
I'm just learning, but I think this performs it correctly with sets.
1. I love python.
2. The OP was being a troll.
3. People need to be more honest about themselves and their favorite pet languages. I can write a sorted set in assembler too, if I wanted. However, there's been several times that I've wanted a sorted set data type while coding in Python but found that none was easily available. I hate the, "you can write your own!" counterpoint, because it is essentially meaningless unless you can prove that writing your own is as trivial as importing someone else's implementation.
By the way, in case anybody was wondering, here is a (relatively inefficient) way of making a sorted set in python:
http://code.activestate.com/recipes/576694/
Scala isn't as succinct, of course, but it gets much closer!
I've done some Django programming in the past. A view gets a request object (pardon me if I'm wrong or if this has changed recently) and is supposed to then render the response (or something similar, I don't remember exactly). Now what is a request? If Django were in C, I would know what a request object really was, grep for it, and look up the header file. If request has a GHashTable named post_data, I don't think I need two guesses about what it exactly is. Same goes for C++ and C#.
Then you've inconsistencies. The same method may return a string object or an integer on different calls. And this happens in practice - I remember when I was (trying to) model a relational database in Django, I found a ManyToMany field returning (when invoking values ()) a list of dictionaries instead of a list of Model objects (which I was expecting).
Of course, if I was not dumb enough to not read the documentation I might not have stumbled; but the point is that Python allows this to happen. And since I don't have the benefits of a compiler, anything other than basic syntax errors (the ones I can catch by calling py.compile) explode at runtime.
The thing I've begun to notice that scripting languages tend to require you to hold the entire structure of the program in your head as you code. In C++ you know that unless you've gone out of your way to do some casting magic, a string get_foo () will always return a string. And you can always do get_foo ().c_str (). In python you're never sure.
The idea that the OCaml community is dying is purely subjective. OCaml, having been around longer than F#, may just be going through a perceived lull.
Either way generalizing that F# will replace OCaml as the goto language in the ML family from a perceived decline in the OCaml community is probably not the right call.
http://norvig.com/21-days.html
From your comments, I kind of get that you want to be a real good programmer, and part of being a good programmer is to understand the different way you can wire bit and pieces together in the many different languages. I had a similar experience as you in that I went from C->C++->Java->Javascript->Scheme->SML->Python. I can definitely tell you that learning Scheme and SML first helped me tremendously in understanding dynamic languages in general. In more concrete terms, understand typing rules has helped me how to debug a program when I mess up in Python. For example, in SML, I can completely omit type annotations and the interpreter will infer the right type for me at parse-time, and that each function or statement must only return 1 type.
In dynamic languages such as Python, you can still do what you can do in SML or Haskell, but the runtime system makes no guarantee that your program as it is written is type-safe when the interpreter parses all your source files. Type checking is done at execution, when the code path in question is exercised. However, if you THINK about how the types are infered in SML when you write in Python, you generally will not run into TypeErrors.
The same goes for functions that return different types. To prevent tripping up with these functions, just apply what you've learned in Haskell or SML when you are debugging library functions that do this, and avoid writing functions that return different types.
def foo (self, stream): What is stream here?
void foo (std::ostream &out) { out << "bar" << endl; }
Hope you get the point.
The inconsistencies you mention are (in a well written code base) very rare. If you call a method get_name() odds are you are going to get back a string. If you seem to randomly get back an int or a dictionary or a datetime object it's a pretty good sign the code is foobar'd. Good Python programmers don't abuse the dynamic nature of the language. Methods should return predictable types (documentation is important), it might return different types depending on the input but this should be documented and obvious (say a parse date method that returns a datatime object if you pass it a string containing a date and time). The values() example you use is very clearly documented as returning a ValuesQuerySet that supplies dictionaries not models (http://docs.djangoproject.com/en/dev/ref/models/querysets/#v...).
In a number of years using python, the standard library and 3rd party libraries I've never been left wondering "If I pass X to this method what the hell type am I going to get back". Just like in C/C++ I need to remember it returns a list or a string or a dictionary but that's usually where the mental overhead stops.
Python is dynamic which means it's flexible. Flexibility is usually reached by sacrificing simplicity so Python encourages testing and good documentation. I would argue that these are both necessary features of any good code base, Python is just more upfront about this than a number of languages.
The purpose of this thread was merely to gauge what kind of paradigm shift people who were used to programming in C or C++ generally experience when they move to Python. Some people seem to find making the jump easier than others - I personally have found it difficult and have made little progress so far. Since I generally consider myself good with computers, I find this a little unnerving.
I really like using a dynamic language for some tasks. I almost never use C, C++, or Java for any task I hope to start and complete within a day. Those jobs are small enough it's easy to keep track of what you are passing around.
I spent 6 months writing all of my utilities in Python. I tried very hard to like it, but it just didn't tickle my fancy. I do like perl and ruby for a dynamic language. I think perhaps the issue is, if you are like me and you don't like using dynamic languages for large programs, the extra clarity of python isn't enough of a added bonus.
If Django were in python, you wouldn't even have to grep
>>> import django.http, inspect >>> print inspect.getsource(django.http.HttpRequest)
Django in particular has several additional advantages:
• it has an "interact" mode that pops you into a Python REPL so you can poke at all of this stuff interactively instead of having to save a source file and hop over to your browser;
• it has really first-class documentation;
• if you raise an exception in debug mode, the traceback includes dumps of all of the objects mentioned on all the levels of the traceback stack, along with a few lines of source code from the stack frame;
In short, Python offers much more power to undertake the kind of analysis you were wanting to do than C or C++, but you have to do it dynamically, instead of statically.
Doing it this way is not always feasible, since sometimes there's a prohibitive amount of setup code that needs running before you can get a real object. For short code paths though, like Django apps, it works really well.
I think it's fairly clear from context that he/she means, "not a lot of red tape", rather than a reference to specific language features.
Counter-edit: My response was in jest. I deliberately misinterpreted the term for humorous purposes.
Python for me is the imperative language (with some functional features) closest to pseudocode.
foreach line [read stdin] { foreach word [split $line] { if [string match *ing $word] { puts $word } } }
The one thing that gets me is the "it's already been done" mentality. If you love Tcl then you want to create things in Tcl for the world to use. I have thrown out a couple ideas like "mailman in Tcl" or "nagios in Tcl"...but I always get "it's already been done". Sure, I could have done it anyway, but it gets your spirit down when you hit that wall. I know they have been done with other languages. Let's do it in Tcl to see if it can be done better!
The whole scripting language issue is a complicated one imo.. People want to either use 100% scripting or 100% system (i.e., C), which is not alright. Combine scripting & system according to your needs. This is why I like Tcl the most: It prevents you from using it where there might be computational bottlenecks (e.g., in algorithms). It is meant to complement C, not replace it. Anyway this is a separate thread.
[read stdin] returns a string (not a list of strings), which is parsed as a list when you try to loop over it. The parsing breaks the string into a list of words, so the second loop is redundant. The parsing could fail if the input file isn't valid list syntax (unmatching {}'s). [split _] makes it safe.
I love Tcl too! Tcl is a scripting language for C, Python is less-powerful version of Lisp.ARGF.lines.each { |line| line.split.each { |word| word.match(/ing$/) and puts word } }
Unless, of course, Brainf*ck counts as a "scripting language". :D
So if you don't have to learn Python right now, maybe you should first learn Lisp, Haskell, or whatever else you want or need to learn that isn't much like C/C++/Java. I think you'll have more fun this way. :-)
Try the other two scripting languages - Ruby and Perl. I would prefer Ruby. See if you like the way things are done there.
If you find that you are more at home with this language than Python, try analyzing what makes you prefer it over Python.
I would suggest you to start with the basics of the Ruby language, and then try building a simple web app with Sinatra. I find the Ruby style much more comfortable than Python.
But if you don't like any of these languages, its still well and good. If you get can shit done with C#, thats all it counts.
I prefer Ruby, but appreciate Python and Perl. I come from C/C++ coding for 14 years.
I'm disqualified to answer - as I come in your so called second type (softcore python lover perhaps), people who uses python to fix things in day to day life.
So what kind of programmer are you? What do you develop? These questions are essential before making any advise.
Secondly I don't mean to criticize Java. By calling it a toy language, I was simply referring to the fact that Java tends to make writing bad code difficult, and in doing this takes away some of the flexibility and power that you tend to associate with other languages.
I mean
while (str++) str = (str) + 1;
becomes
for (int i = 0; i < sb.length (); i++) sb.setCharAt (i, sb.charAt (i) + 1); // and relevant casting
While the above piece of Java code can be improved and condensed (for instance, by calling getChars and iterating through them* and then creating a new String - would be slow however), I think you get the point.
I never met a hardcore C++ guy claim they like C++
> by hardcore I mean the kind of people who wrote Exaile
I think Python weren't meant to write desktop music players. Stuff like Zope are hardcore.
I'm more like a hardcore C guy.
I do know a fair bit of C++ though. Perhaps C++ would've been better if compatibility with C was not kept as a fundamental goal. Just a personal opinion.
Qt does an amazing job of taming C++. I used their framework for some GUI design and loved it.
http://docs.djangoproject.com/en/dev/intro/tutorial01/
Don't copy and paste the code in the tutorial and when they ask you to type something in the REPL, do it.
That's when it all started for me.
First off, Java isn't a toy language. You've characterized it improperly. Java is a bureaucratic language. You have to cross your t's dot your i's, fill out your requests in triplicate at the FactoryFactoryFactory to get the objectOfYourDesire. Why is this so?
This comes back to how C++ works on projects, especially large projects and midsize projects with a couple mediocre programmers thrown in (because, in commercial software development, you rarely get control of your team). C++ does not work well for large team development unless 1> You have very capable people 2> and you can fire everyone who steps outside the "defined okay subset" of C++ you use on the project. The language is too big, certain parts make it too uncertain, etc, for people to just willy nilly use all the language features. So Java, is basically Sun's "redoing" of C++ where they took its wild west nature, and made a BureauDisney version where you can't do a dozen things that happens in C++ all the time when good programmers go off the reservation or bad programmers enter the equation at all.
C++ has uses, but it's the sulfuric acid of programming languages: you have to have good personnel control and fire those who screw around outside the boundaries of the right style. A programming group with one guy programming like C with classes and another guy programming like it's Ocaml without garbage collection, and you're in for a mighty piece of hell.
So that's where Java came from. That's why it is what it is, and I hope I've highlighted a non-business issue with C++ that comes up from it's overabundance of "understanding breaking powers" which don't mess well with total programmer freedom.
Now lets look at what python was, and what it is now: Python was originally designed as a substitute for the pascal/BASIC line of programming languages (specifically a language called ABC). It was designed to be very very clear. It still is very very clear. It is still quite terse compared with C++/Java/C, but it's wordier than perl and ruby, but very much clearer for even non-python programmers to decipher much of the time.
Over time, it grew into an Application development and webserver development language. Why?
It has a very easy way to interface to C code. This is important, because C does great module level integration, but once you get at the system level, you start to get issues with namespaces, tracing bugs, etc. So python became an alternative for tying C code together.
It writes very quickly. While you may not understand how to write it quickly yet, usually python/ruby/perl will be quite a bit more productive on a feature basis than Java/C#, and tons more productive than an equivalent C/C++ project. This has to do with the fact it takes very few lines of these languages to "do a job".
For you currently, you're possibly less productive in python right now than you are in C++; I've honestly found this doesn't hold true more than 40-80 hours into learning python development while doing a real project for almost anyone who can handle commercial C++ software development. The C++ people do python faster than they do C++ and it has many fewer issues in the end than C++ they would have wrote. We use weave.inline or something else to speed up the inner loops with some native C, if even required for that application, and all is good, it works just as fast for the user or application, and was completed much faster with much less obtuse bugs.
If you spend those 40-80 hours on the language, you too will likely be a faster developer in python than C++ for many features.
Some tips: You are not doing C, you are not doing C++, you are not doing Java. Don't pretend you h...
"Thanks for responding, that's an interesting perspective" is not a class of comment that deserves downvotes. It's completely appropriate.
(Update: The comment was deleted as I wrote this.)
This is the best tip that could be given. In the SICP course in Berkeley CS class, the instructor puts it as
"Don't ask me what the language will do if you do something stupid, the answer will always be either you would get an error or the computer will do something stupid. Don't try to convert java code into LISP, try to think in the language."
This is such an absolutely fantastic way of succinctly describing why I dislike Java so much. Bureaucratic!
Absolutely fantastic post, get this on a blog somewhere. I seriously wish I could upvote you more.
It's like a security blanket for me.
Not to be a prick, but if you're having "typing" problems with Python, you're using it wrong.
Types are almost irrelevant in Python. What matters is whether, in a given situation, the method you're calling is supported and does what is intended. The actual type/class of the receiving object doesn't really matter, ditto for any arguments you pass to the method.
While this may seem highly unsafe and brittle, it has important benefits. You can just hack up some code that "just works" in a few minutes, without having to sacrifice a goat to the compiler first, making sure that all the correct types are specified, subclasses are defined, interfaces are implemented completely, etc. The rigid type systems in other languages often require this and more; making changes to your software becomes a chore. Rapid prototyping this is not.
In Python, when used correctly, you don't have this problem. Write a bit of code, write a test, run it, and decide what to do next. Ideal for testing out ideas. It doesn't work? Throw that shit out and write something else; two minutes later you'll be testing your new code again. Yes, you do need to have unit tests, but the same is (or should really be) true for most languages. Just because something compiles, doesn't mean that it does what you want. (Except maybe in Haskell. :-)
Interestingly, the quickly-written prototype might well be good enough to become the actual production code, with some additions. Just keep you tests up-to-date, for reasonable use cases, and there's no reason why your code shouldn't work in real life. Sure, that function foo(x) that wants to call x.bar() will fail if you call it with an x that doesn't support the bar() method. So don't do that, then! ;-)
Anyway, to summarize, I personally would much rather have Python's flexibility, paired with unit testing, than Java's lack of flexibility paired with compiler checks.
I'd say that strong compiler checks become more helpful as the size of a program increases. You can keep less of a big program in your head, and big programs have more code paths that could potentially need testing.
Either way, both flavors of static typing require development methods that are very different from Python's, though. My original point was that in Python, you shouldn't really have to worry about types, or checking them (in tests or otherwise). You can, but (IMHO) you'd be going against the grain of the language.
I understand the concept, but sometimes in a medium-size project, you just accidentally send the wrong object back. It happens. But Python won't tell you, and it'll blithely wait for the code to get exercised before dying. I don't remember exactly why I was having this problem, but the bug wasn't shallow, and required a certain confluence of exceptions to occur before it would fire. The sort of thing that would even escape most unit testing.
I would never force static typing on Python or Ruby or upon any language that didn't want it, and when I switched to Python I was very pleased with dynamic typing. However, I find myself much happier with the stronger compiler checks. Writing a medium project in Python now frays my nerves!
I agree that this does indeed happen... I think it's a matter of, the more flexible a language is, the more rope you get to hang yourself with, even unintentionally and unexpectedly.
(Anecdote:) For my work, I have been developing and maintaining a fairly large Python code base... (~70K lines... comparable to about 700K lines of Java <wink>). Another developer changed a module so it would access the database upon importing, which was a no-no (IMHO), so I changed it back, using a class that gets the desired info from the db upon instantiation, and some sort of singleton construct so the same instance would be reused. I also decided to write a test to check that when this module was first imported, there would be no instance of said class yet. To make sure it was a first import, I removed any references to the module from sys.modules, then did an import. This worked great... until I ran the whole test suite using nose [http://code.google.com/p/python-nose/], which has its own ideas about import order and such. This turned out to be surprisingly hard to fix... a non-shallow bug that wouldn't even be possible in less flexible languages.
Tests are effectively the answer, but they are a pain to write and having to document your type information via tests seems a lot more cumbersome from just doing "int my_var".
The party line with Python and dynamic typing is true in many cases, especially when starting a new project. As time goes on though, things get confusing and tests are rarely good enough to offer the same contract static typing offers. To say "you're doing it wrong" is somewhat correct, but no one does it right all the time.
import pdb;pdb.set_trace()
then run the program, and you'll get an interactive prompt and you can just look at everything in that state.
dir( myBuggyVariable)
Here is a link to doctests. There are godly, and unlike any testing library, in that they aren't a library, they're a comment scanner: http://docs.python.org/library/doctest.html
Smallest amount of rigmarole required to make testing happen I've seen in any language.
Java is almost untyped by comparison. Languages like Ocaml and F# occupy a middle ground.
Take the Java web framework, Play, as an example. http://www.playframework.org/
All of Java's features conspire to create a language that's pretty verbose and doesn't do a lot to make things easier for you (aside from simple object orientation). If you like spelling everything out in excruciating detail, that's good. If not, the language doesn't want to twist your arm, but it's certainly not going to do anything to help you.
It'll work from Hong Kong, and probably most places in the world, but if you cross the Chinese border into Shenzhen, you'll get "The connection has been reset". Same with other places in mainland China I've been.
But I've grown to like the simplicity of Python. One thing I don't like is its threads implementation, however. Because of the GIL, multithreading (GUI + background thread) just doesn't work right. Maybe I'm using it wrong?
The Python community seems to be warming to the importance of threads. There are several efforts breaking their swords against the GIL nowadays (Unladen Swallow being the most prominent), and Antoine Pitrou wrote a new GIL to help improve contention [1]. With any luck, by the end of the Python Feature Freeze, there will be some significant headway towards efficient handling of threads within Python, but I'm not holding my breath yet ;)
[1] http://www.dabeaz.com/python/NewGIL.pdf
I have exactly the opposite heuristic for syntax. The only thing worse than semicolons and curly braces, are `begin' and `end'.
Of course, I don't have any pretentions of being a "good person" either.
Perhaps I'm way off here but the languages seem to me to show some of their cultural heritage. Python has a blunt & minimalistic Dutchness about it while Ruby has a Japanese elegance and style.
Ruby is more fun,but python is more mature. In the end - whatever gets the job done right?
There are a number of things that made me think Ruby was made by a less astute designer. The 'end' everywhere feels bad in a world where I know both "}" and a newline can accomplish the same thing but with less typing and screen clutter. Also do not like Ruby's dropping of ()'s from fn call statements, because it blurs the boundary with non-calls and non-expressions and control flow keywords. I also feel Ruby encourages a certain kind of DSL creation which makes the code harder to read and maintain. I also don't think every app or library needs to export a DSL into client space. It's better if the interface it publishes still looks and feels like the prog language used.
That said, I acknowledge Ruby has good qualities. Python is not perfect, but to me it gives the better designed feeling. Actually the Lisps seem to be the most elegant and powerful. Love their regularity and power but not (yet) all the parentheth everywhereth.
People sometimes do go overboard with DSLs in Ruby too but the big problem I have with Python code is that it all looks the same. The shape of Ruby code is usually a good indicator of what it's doing, partly thanks to DSL. Python seems to have gone just far enough in making all code look the same to defeat quick visual intuition. Why not take it a step further and get a completely regular, homoiconic syntax and all the Lisp-y benefits it brings?
To me Ruby hit the sweet spot exactly between Lisp and Perl. If I had to code in Python I wouldn't hate it though. There are far worse languages.
I really enjoy the pretty simply object model, the message passing OO, and blocks.
An interesting point that I read somewhere the other day, from someone who codes in a lot of both: Ruby (to him) is kind of ugly, and Python is very pretty. Yet, the exact parts that make Ruby ugly allow it to have _awesome_ libraries. Python, with its rigidity, means that the core language is great, but the libraries end up being worse because of it. He uses RSpec as an example, specifically. So for him, Ruby ends up being better to use, even though he likes the Python language better.
Apropos: Does Ruby optimize tail calls?
In Ruby, the last expression in a function is the return value; in Python you must use the return keyword, even though there's no ambiguity.
For example, if there's a function composed entirely of print statements, the last expression evaluated will be the expression in the last print statement executed. But, that means you have to know that 'print' is a statement and not an expression, and that the right-hand side of the print statement is in fact an expression.
In ruby, actions like prints and assignments are side-effects and always evaluated as expressions. So if puts is the last expression in a function you'll get the return value of puts (which is usually nil I believe). That's pretty simple.
I find the Ruby version clearer because it proceeds from left to right like a shell pipeline.
This is easier to read and understand, only goes through the list twice, and loses nothing in terms of power:
(And for any given operation, there's very possibly a cleaner way to abstract out the inner list comprehension, which would again make it a lot nicer.)In general, I don't see much of a reason to use filter/map/etc in Python: weak lambdas mean they're not terribly powerful. List/sequence comprehensions can do everything they can do with cleaner syntax and/or fewer operations.
This, I think, is actually at the core of this whole discussion. The Ruby/bash approach makes sense if you're used to working with sequences like Ruby/bash do. The Python approach is more natural to me though, because I've written a lot of Python. (And having spent the last year writing a lot of Ruby, I still find the Python approach cleaner/easier to understand at a glance.)
In this example, yes, it's easy to solve the problem with only one iteration through the list. In a more complicated example (especially when the first map step is expensive and you really only want to do it once) this kind of solution may not work.
This is an excellent point. Ruby code can be some of the cleanest, most readable functional code there is. I have these kinds of chained pipelines in my Ruby code all over the place and they're much easier for me to follow than similar expressions in Lisp or Haskell and than Python's comprehensions.
If the preceding notations for anonymous functions have been too implicit for you, then you can use pointy blocks(or just plain anonymous function declarations).
Or, you could use hyper operators instead of the maps: The hyper-operators extend the scalar operators "+" and "*" to lists. Since the ">>" point to their operands on the right side, that operand will be extended to be as long as the other side, allowing you to use a single scalar as the right-side element.Examples.
In Java, accessor methods are considered good style. In Python, directly accessing a member is better. (more concise, makes client code clearer.) If you need to do magic, you can use properties.
In C++ and Java, you use inheritance to denote which classes have a given behavior. In Java, you also use interfaces. In Python, you simply give a class the needed method(s). (I.e., you use duck typing.) That flattens or removes lots of class hierarchies. If you need to do magic, you can use isinstance(), issubclass() or hasattr().
In Python, you use the built-in types a lot. Many problems decompose easily to lists, sets and dictionaries. That reduces code dramatically. Java and C++ STL's containers, in contrast, are so clumsy they make me look for ways to avoid them. If you need to do magic, you can subclass the built-in types or build new types with the same methods as the built-ins.