5 ms·
Is there a significant reason, other than preference, that Python is a "better fit for real-world team based development" than Clojure or any Lisp dialect? Pyt
by mattrepl 17y ago
Is there a significant reason, other than preference, that Python is a "better fit for real-world team based development" than Clojure or any Lisp dialect?
Python supports functions as objects that can be passed around, but that does not make it a FP language. Functional programming is about constraining mutability and declaring what you want, now how. Python does not lend itself to that style of programming.
Guido has spoken out against map/reduce/filter, lambda, and TCO in Python so many people interpret that as him disliking FP. I think it has more to do with Guido's aesthetic and Python's design principles than anything else.
- yummyfajitas 17y agoI'll give one reason why Python may be better for team development than clojure/lisp: powerful macros. They do make it harder to reason about code you didn't write. In Python, you can look at the inside of a function and have some idea what it is doing. "It's doing kwyjibo(i,v) to all the i in zqmfgb. Now, lets see what v and zqmfgb are." In clojure, that isn't always the case. An example: recently, I was trying to write an OpenGL app in Clojure. I found the following code on the net (pretend it was written by a team member): (doto obj (.glBegin ...) (.methods ...) (.glEnd)) I decided I wanted to factor out the (.glBegin ...) and (.glEnd). Aha, this is a job for macros! (gl-begin-end body) ; this should macro expand to: (do (.glBegin ...) body (.glEnd)) This would just fit inside the the doto, and be exactly what we need. The problem is that doto significantly modifies it's contents: (doto obj (.method x) (.method y)) (clojure.core/let [G__1206 obj] (.method G__1206 x) (.method G__1206 y) G__1206) So I got this: (doto obj (gl-begin-end body)) ;macroexpand once (clojure.core/let [G_1725 obj] (gl-begin-end obj body)) ;macroexpand twice (clojure.core/let [G_1725 obj] (do (.glBegin ...) G_1725 body (.glEnd))) Obviously this didn't work. In this case, the problem is me: `(doto obj body)` is idiomatic clojure, and I should have known about it. On the other hand, `(kwyjibo obj obj2 body)` could be very hard to figure out and modify. I should, however, raise the caveat that I'm not a good enough lisp programmer to know if this is really a problem in practice.
- jules 17y agoYou say that (doto obj (.glBegin ...) (.methods ...) (.glEnd)) > I decided I wanted to factor out the (.glBegin ...) and (.glEnd). Aha, this is a job for macros! (gl-begin-end body) ; this should macro expand to: (do (.glBegin ...) body (.glEnd)) But why did you change `doto` to `do`? Here's how you can do this: (defmacro gl-begin-end [obj & body] `(doto ~obj (.glBegin) ~@body (.glEnd)))
- yummyfajitas 17y agoAs I said, I know the programming mistake I made here (and that it reflects lack of knowledge of clojure on my part). But the problem I had with the doto macro could easily translate to a problem you have with my kwyjibo macro. In python, I know what this code does, regardless of what happens at higher levels of indentation (ignoring some rarely used class-level hacking): f(a,b,c) g.h(i) In lisp, I can't necessarily assume that (f a b c) (.h g i) will actually call f on a,b,c and then call the h method of g on i. The ability to modify syntax programmatically implies that syntax (i.e. the s-exp structure) may not mean what you think it means. I'm speculating that this may make collaboration more difficult.
- gruseom 17y ago[Macros] make it harder to reason about code you didn't write. No, actually, they don't. Given the usual high quality of your comments, I'm surprised you would repeat this canard. you can look at the inside of a function and have some idea what it is doing. This is just as true of a macro. In fact it's more true: you can expand a macro in place on your code and see what it is doing, a maneuver there is no exact analog to in functionland. The macroexpansions in your example make it immediately apparent what the problem was. Macros are different from functions. That's why they're useful. I'd encourage you to stick with the learning process. The key difference with what you were expecting is that macros control the evaluation of their arguments.
- yummyfajitas 17y ago
- abdulhaq 17y agoPython is better than the lisps for team based development, IMO, primarily because you can't write your own language in python. In a team you're normally working on long-lived code of medium - large projects (e.g. over 100k lines, over a period of 1 - 5 years). You need to be able to quickly grok how to maintain older code written by someone else. Python's mantra "there's only one way to do it" means that is more likely to be possible than it is in one of the lisps. However I have to admit that that is conjecture on my part, not having worked on a large team with a lisp project.
- gruseom 17y agoRight, because programs with millions of lines of code written by many different people are so easy to "quickly grok". As long as they stick to lower-level constructs. The problem with this fallacy is that it assumes that what is true of a single self-contained function is true of thousands of inter-depending functions heaped on top of each other.
- abdulhaq 17y agoWe, for instance, structure all our code very carefully with clearly defined and documented interfaces and modularised functional areas. I doubt that any function is really interdependent with more that 20 other functions, never mind thousands. If someone needs to understand thousands of functions to maintain any piece of code then that code has a serious problem and probably a low 'bus factor' (how many developers being hit by a bus it would take to derail your project). I suspect that the power of the lisps tempts developers into writing code that does effectively have many interdependent functions, though they may not fully realise until it's too late.
- pivo 17y agoI really don't see any difference there. You can write bad code in any language. If you have the organizational discipline to code the way you've described in Python, why wouldn't that restraint carry over into other languages? Why are macros different? I find typical Python programming to be not particularly disciplined, so if you've overcome the problem in that language you should be fine in a generally more disciplined language like Clojure.
- ubernostrum 17y agoWell. The whole "people don't write applications in Lisp, they use Lisp to write a new language and then write applications in that" point has been brought up already, so I won't try to argue its pros or cons (thankfully somebody else can get flamed from both sides over it). I will say that I think Python does something interesting, in that it removes some of the stupidest problems teams usually run into. Consider projects written in C or C-like languages: hugely disproportionate amounts of time are dedicated not to actual issues of how to design applications, but to things like where to put braces and how to use whitespace. Python sidesteps a lot of that petty bickering because the requirements of syntactically valid Python impose consistent solutions to those debates from the start. Also, culturally, Python programming style tends to go quite a bit beyond that. For example, most large projects simply use PEP 8 as their style guide, doing away with an even larger class of stupid infighting. As to FP and whether Python hates or supports it, unfortunately it is the case that if you put five FP proponents in a room you'll get at least twelve mutually-exclusive definitions of FP. So I think that tends to be a rather silly debate to have :)