Hacker Newsnew | comments | show | ask | jobs | submit | showell's commentslogin

I don't think the fights should be vicious, but I think the stakes are fairly high, and even though Ruby and Python are close cousins in the grand scheme of things, they really do represent profoundly different philosophies when you look more closely at the languages. It would be nice if these differences could always be discussed with civility, of course.

I use both Ruby and Python enough to appreciate that both languages generally make important tradeoffs with good intentions, but I don't always agree with the results (in either language). I also find Javascript often has an interesting relationship to both languages.

-----


That's just another reason for vicious fights besides small stakes, small differences.

Just ask the protestants and the catholics.

-----


It is true that small differences can mean large conflicts, but I think Catholicism and Eastern Orthodoxy is a better illustration of this. The only doctrine that the two denominations disagreed on was the exact way in which the Pope is higher-ranked than the other metropolitan bishops; this plus language barriers and differences in cultural atmosphere produced something like 1500 years of mutual hostility which were only ended by John Paul II.

However, we can sometimes mistake _subtle_ differences for _small_ ones; but just as there's a substantial difference between the Mac OS and Windows, there's a substantial difference between Catholicism and Calvinism (which was the most successful form of Protestantism) -- the difference between God seeing that you went to Hell, and God sending you there. I could go into much greater detail (I count nine paragraphs in how I'd previously structured this comment), but that's the nutshell of the nutshell.

-----


When looking at this from an atheists perspective it looks like very minor differences to me.

There's a joke about that, I looked it up:

I was walking across a bridge one day, and I saw a man standing on the edge, about to jump off. So I ran over and said “Stop! don’t do it!” “Why shouldn’t I?” he said. I said, “Well, there’s so much to live for!” He said, “Like what?”

I said, “Well, are you religious or atheist?” He said, “Religious.”

I said, “Me too! …Are you Christian or Buddhist?” He said, “Christian.”

I said, “Me too! …Are you Catholic or Protestant?” He said, “Protestant.”

I said, “Me too! …Are you Episcopalian or Baptist?” He said, “Baptist!”

I said, “Wow! Me too!…Are you Baptist church of God or Baptist church of the Lord?” He said, “Baptist church of God!”

I said, “Me too! Are you original Baptist church of God, or are you reformed Baptist church of God?” He said, “Reformed Baptist church of God!”

I said, “Me too! Are you reformed Baptist church of God, reformation of 1879, or reformed Baptist church of God, reformation of 1915?”

He said, “Reformed Baptist church of God, reformation of 1915!”

I said, “Die, heretic scum” and pushed him off.. — Emo Phillips

-----


@jacquesm: At least from my perspective, "God wants everyone to go to Heaven" and "God wants some people to go to Hell" are further apart than "God wants everyone to go to Heaven" and "there is no God, and the universe developed through chance and emergent patterns."

Calvinism had _huge_ practical consequences -- in social policy, it's the difference between ensuring that the poor are fed and sheltered, and kicking them into the street; and you can only imagine what it meant for the laws of war...

Edit: And the joke you mention is only too recognizable, but it's more like the Catholicism-and-Orthodoxy situation, where it's a matter of tribal loyalties more than views of the world...

-----


You might be taking the statement out of context, and you are certainly quoting it out of context (although brevity is appreciated.)

The statement in the talk was made to illustrate the differences between Ruby and Python, and it was not made to suggest that Ruby was replicating all the benefits of Lisp.

-----


I understand the intent, but I do not feel that it loses its incorrectness by taking it out of context.

That people even feel this comparison is appropriate is what has me depressed. It represents a fairly fundamental set of misunderstandings.

-----


> That people even feel this comparison is appropriate is what has me depressed.

I agree; you can replace the term "DSL" with "API" in almost every case without losing any essential meaning. (You have to give the hipper-than-thou language pseudo-advocacy, but that's no loss.)

-----


I think in those contexts, DSL is more a description of how an API feels to use, than a precise technical categorisation.`

Ergonomic distinctions are useful though, as is the distinction between declarative-style APIs and more imperative ones, which 'DSL' is often used to make.

-----


I have yet to see a Ruby "DSL" that didn't feel like Ruby. That is,

  unless you.talk :like => "this"

-----


Those are just the "english-y" DSLs. Not all are attempting to read like english. And even for those that are, the point isn't to be writing in english, the point is to be at least halfway readable to a non-programmer reading over your shoulder.

-----


Okay, but it's not really all that clear that "sum.should == 3" is actually any more readable than "assert(sum == 3)". (Do you really have non-programmers reading code over your shoulder? I can't think of any case in a 10+ year career where that's happened.)

-----


I don't personally use the stuff. :) But I have seen environments where that does happen, and it works pretty well for them.

If you're not doing that, I think they're kind of silly.

-----


> ... the point is to be at least halfway readable to a non-programmer reading over your shoulder.

That's the same argument for filing the serial number off of TDD and calling it BDD: sometime, somewhere, somehow eventually some non-programmer is going to have to maintain source code without a trained professional programmer around to help.

I don't get it; FIT's been around much, much longer. What kind of non-developer business rule expert can read the punctuation-sprinkled pseudo-English pidgin Ruby spreads around but doesn't know how to manipulate tabular data in a spreadsheet?

-----


The BDD reference is not just an analogy, it's what these are for. And it's not about non-programmers maintaining the code. Not at all. It's about a business owner and a programmer sitting together and making executable specs together.

I don't really get it, but I'm curious. People I respect swear by it.

-----


I have yet to see a Ruby "DSL" that didn't feel like Ruby

There are some out there though, for eg. FancyRoutes: http://www.railsinside.com/plugins/252-fancyroutes-a-nicer-d...

-----


Really? That's the example you want to use. First thing I see on that page:

  get / 'orders' >> :orders > :index

  with route / :slug / 'order' >> :orders do
    get > :show
    put > :update
  end

  get {'item_images' => :controller} / :image > :show
That looks like Ruby all over the place. Yeah, it overloads operator methods more than most Ruby code, but it's very clear that it's Ruby.

-----


I and i think most people would disagree with you because above does not "feel like" Ruby.

-----


haml, sass, cucumber...

-----


Decorators and annotations are very useful in Python, but I still like the terseness of Ruby--no need to define "hello()". Of course, Python wins on a different kind of terseness--no do/end--but that is mostly orthogonal.

-----


And you could use {} instead of do/end, but a Pythonista wouldn't consider that any more terse.

-----


Yep, my mention of do/end or squigglies was just a caveat on the Ruby-is-more-terse-in-this-example statement in the context of anonymous functions or blocks. I wish there was a language that won on both terseness metrics--i.e. a Ruby with indentation or a Python with anonymous functions.

-----


I wholeheartedly agree that all languages should be judged on the quality of their libraries and implementation, as well as the success of the projects implemented on top of them. Ruby and Python have a pretty good track record there.

One of the themes of Gary's talk was that Ruby is more expressive/flexible than Python, and lisp was thrown into the discussion as sort of a "gold standard" of expressiveness/flexibility, without necessarily passing any judgment on overall merits of the three languages.

To the extent that Ruby strives for more flexibility, it is probably way more influenced by Perl than lisp.

As somebody who has used both Ruby and Python fairly extensively, I think Ruby is undeniably more expressive than Python at times, but also more arcane at others. Some of the differences probably come from irreconcilable tradeoffs, where you cannot have your cake and eat it too, but other tradeoffs are probably less necessary, which is why people continue to discuss it. In the case of Ruby, it's a pretty young language, so there are probably opportunities to make it more appealing to a Python mindset without losing its great flexibility, although I do not have specific proposals.

The conference Gary spoke at was a Python conference, so most people were more interested in ways that Python could learn from Ruby, without sacrificing Pythonicness. Gary seemed to reach the conclusion that the number one feature he envied in Ruby was blocks. Speaking for myself, I wish Python just had some kind of anonymous function syntax that was more rich than lambdas, even if it were not exactly semantically similar to Ruby blocks.

-----


> I wish Python just had some kind of anonymous function syntax that was more rich than lambdas

A lot of people keep saying this, including the article author, and I'm having trouble understanding why. Lambdas are for "one-liners", functions are for more-liners.

Any time you want to write multiple lines in a lambda it's trivial to make it a named function.

    def listSomeTable(name):
        print name.center(40, "=")
        def getWeirdNumberPair(cap):
            while True:
                a = random.randint(1, cap)
                b = random.randint(1, cap)
                if (a==1) and (b==1):
                    continue
                return (a, b)
        for i in xrange(20):
            print getWeirdNumberPair(i)
        print "="*40
What do you want to use multiline-lambdas for that you can't do (equally simply and elegantly) with named functions?

-----


First of all, your objection to anonymous functions with an example that names the function in two different places kind of takes us off topic from the discussion of "anonymous" functions, but I will still respond.

Second of all, multiline-lambdas are already possible in Python, but they are not anonymous functions.

Anonymous functions, as I said, allow for rich syntax; they do not affect the Turing completeness of the language. The context I am speaking of is "expressibility" in the sense of natural language, not whether or not something is expressible at all.

Ruby allows you to do stuff like this fairly naturally:

def process_event_until_timer_expires # check time, then call block only if # timer not expired end

process_events_until_timer_expires { |t, event| puts t fire_event_downstream(event) }

Having an anonymous function here allows you to read from outside in, which is more natural. From the outside, you know you are in some event loop, then you can look inside the block to see the details of how the event are handled. It's really that simple. Not earth-shattering different than Python, just subtly different and more expressive.

I've been using Python for a decade, and Ruby's still overly exotic to me, so I am sympathetic to people that defend the more Pythonic approach. But Ruby does allow for a different kind of expressiveness here.

Javascript also makes heavy use of anonymous functions, and if you use anonymous functions in other languages, you realize that they have value, even if they are occasionally abused and technically unnecessary.

-----


The real problem with lambdas in Python isn't that they're restricted to one expression, but that Python's implementation of closures is clumsy (due to a scoping ambiguity). The argument about whether lambdas should be named or not is a canard. In languages that make heavy use of lexically scoped functions defined on the fly (Scheme, ML, etc.), they're often given local names. The problem is that Python's locally defined functions are less expressive. Apparently making heavy use of closures is not "pythonic".

-----


You are correct. There is no reason not to just use an inline function that happens to have a name. I think the "lambdas can only be one line" is a newbie python mistake.

-----


Personally, I dislike naming things that I won't use again. It feels like a waste. And then, since I have to name things, I have to come up with a _good_ name.

Just a matter of taste, mind you, but it's my reasoning for preferring anonymous functions.

-----


They do make code more readable sometimes... but I think they are often used in Ruby as an alternative to @obj.method(:foo) -- in other words the Rubyist would use lambda{@obj.foo} and the pythonista would use obj.foo

-----


> Lambdas are for "one-liners", functions are for more-liners.

The problem, though, is that this is entirely a Python conceit. It is in no way, shape, or form any kind of programming truism. In fact, taking a more principles-oriented approach, a named function is really just a special case of a lambda. I think this may be one of those things that using a LISP (such as Scheme or Common Lisp) helps people realize.

This:

    (define (foo n)
      ( . . . ))
. . . is just syntax sugar for this:

    (define foo
      (lambda (n)
        ( . . . )))
The fact that the syntax sugar is all many languages expose to the programmer doesn't change that fact, and the one-line restriction on "lambdas" in Python seems quite arbitrary.

-----


Giving people concise syntax for passing anonymous functions allows one to implement a lot of control-flow operations, and combinators from functional programming, as libraries, rather than language constructs.

In python, although they could technically be done as libraries, from a syntactic point of view, having to declare named functions and pass them explicitly as arguments rather defeats the elegance of the approach.

So instead we have special features and syntax added to the language, like with statements and list comprehensions, which are limited special cases of what can be expressed more generally with a nice syntax for passing closures as arguments.

Not that it necessarily matters, there's always a pythonic way to do the equivalent thing. Although a lot of the time it's more imperative, and my taste is for functional programming idioms where possible.

-----


Yes, Python's functions are meant to be named.

-----


The Laurnence Olivier analogy is stupid, inaccurate, and irrelevant.

-----


This seems like a wild exaggeration:

"The behaviour of every function in a mutable, imperative environment is dependent upon the state of all of the other (variables|attributes|bindings|whatever) in your program at the time the function is invoked."

You can write a function in an otherwise mutable and imperative environment like Python:

pi = 3.15 # damn, typo for the value of pi! pi = pi * 15 # mutate it, wrongly again

def sum(a, b): return a + b print sum(7, 8)

Please tell me how sum() depends on pi. The program correctly prints 15.

-----


It doesn't. It is a wild exaggeration. It usually isn't the 300+ variables, just a few obscured by multiple levels of indirection that can cause unexpected inconsistencies. (It gets even worse when you drag in inheritance...)

Each function only depends on the arguments passed in, and variables outside of its scope which are referenced. However, the same is true of every function called inside the function, and the dependency is transitive, so the impact of changes to variables that aren't explicitly threaded through leaks outside to functions that never mention them. That's the problem. Hidden state.

It's also the kind of issue that usually looks incredibly contrived in small (say blog-post-sized) code samples, but isn't funny anymore when you have to deal with big lumps of spaghetti code. Global variables make reasoning about dataflow hard. Real problem, poor description.

-----


Clearly you can see in the implementation of the function that it doesn't rely on any globals. However if you look at the function as a black box, you cant really be sure what global state it relies on. This could be an issue if you use larger libraries you didn't write yourself (or in my case, if I use code I wrote more than two weeks ago!).

In a language like Haskell the type signatures clearly indicates which global state the function (and other functions called by it) has access to, which makes it a lot easier to reason about side effects, even for code where you haven't read the source.

Of course, this approach also have its downsides. If you decide for debugging purposes to add a logging function to an otherwise pure function deep inside a pure part of your program, you may have to change a whole lot of code.

-----


"Sum" is written functionally, thus it is not dependent on the outside world. You used a functional stateless method to show that imperative stateful programming is safe.

-----


How do you know that "+" doesn't depend on pi? Oh. Now you see the problem.

-----


If you need 100% guarantees, then yes, do things in a purely functional way. However, I think the point is that in any sane program you can easily and safely make the assumption that + does not depend on pi in this situation.

Yes, anything _can_ depend on any and all globals, but with proper practices, documentation, code reviews and what have you, one can make simplifying assumptions on what _will_ happen.

-----


"...but with proper practices, documentation, code reviews and what have you, one can make simplifying assumptions on what _will_ happen."

Or you can leave out the practices, documentation, and code reviews and use a functional language and get the same result. Yes, those things are useful for other reasons, but the current argument is about avoiding the inherent dangers of global variables.

-----


Of course, the point is that a caller of any function in an imperative environment doesn't know what state its implementation depends upon.

-----


It is an exaggeration; but only a wild one if you are doing very simple examples.

Imagine you have a 'mutable' program and I have a line that says something like this.

(defun frob (a b) (+ (foo a) (bar b)))

Not only is frob dependent on the definitions of foo and bar, it is also dependent on the the definitions of any mutable globals that are within foo and bar.

If you imagine your program as a directed cyclic graph of functions, and pretend that mutable globals are really functions that set or get a position in memory, you can see that adding more globals to your program (and using them) increases the complexity of your graph mostly by adding cycles to it. (As well horizontal jumps across the entire graph).

It is true that sometimes you need these cycles to write a program (vs. a program that causes your computer to heat up and do nothing), but it is not wildly inaccurate to say that using them all the time makes your program more complex.

I'm not even sure that I'm on board with the supposition that global variables shouldn't be in the language; (saying 'shouldn't' exist at all to a language feature is entirely non-pragmatic).

I think it is more accurate to say that they should be in the language, but they should have a cost greater than locals, and it should be best practice to use them as little as is reasonably possible.

-----


Also frob is dependent on the (mutable) definitions of foo and bar. Functions can be redefined in e.g. Python and Scheme. (And functions are variables, too.)

-----


Same for +.

-----


I see the main point, and I try not to use globals when I can, but I can't help but recall a quote I read from somewhere: "People who are afraid of globals are usually afraid of girls, spiders, etc."

-----


I wouldn't trust the person who told you that, anymore.

Pretty much the last decade of software engineering has been a slow realization how how untenable the use of large amounts of global state is.

-----


You're right, of course, but sometimes globals can be the magic sauce you need to hack out something quickly. (I find global hate to be similar to 'goto' hate.)

-----


Ah, the "I'm a big man, I code by writing bits to the platters with a magnet" argument. (Quick, prize to the first xkcd link here!)

-----


I found it an amusing quote, and I'm a strong believer in using the right tool for the right task. :)

-----


http://xkcd.com/378/

You asked :)

-----


It is not a promise, or even a goal, of SHPAML that it will relieve you the burden of understand the final output syntax, whether that is HTML or HTML combined with some template language.

SHPAML users are expected to be literate in both HTML semantics and syntax. The semantics of HTML are not abstracted away at all. The syntax is only abstracted away where it is redundant.

As a couple folks have pointed out, HTML is a pretty simple language. The problem with HTML is not its lack of simplicity; it is its verbosity.

So, if you use SHPAML, you undeniably get the terseness of SHPAML and the powerful semantics of HTML. So the question then comes down to simplicity. Does SHPAML eliminate too much of the simplicity of HTML syntax in trying to achieve terseness?

-----


First of all, sorry about the name.

SHPAML is not a pseudo-programming syntax. It is purely a markup language, so there are no programming constructs.

SHPAML very deliberately tries to be a lightweight abstraction on top of HTML, unlike wikis and Markdown, which operate at a higher level abstraction. I am a huge fan of wikis, so I value the higher level abstraction at times, but I also see the need for an in-between solution.

I have not used Markdown much, but I see its merits as well.

-----


That came off more harsh than intended. It sucks to post something you're excited about and have lots of people digging into it.

I'm not being critical of your tool in particular so much as wary of the flock of thin syntax transformers that have come out lately. They're fun projects, but adding yet another mutually incompatible data format is probably only a net gain under relatively specific circumstances (small teams, for starters). I like Markdown in this regard because it's downwardly compatible with how people would write anyway. You're right that it's at a different level of abstraction, though.

And about the name - I'm really tired of hearing the same Monty Python jokes all the time, but that's my problem.

-----


I understand the objection to having too many mutually incompatible data formats, but I don't understand how Markdown is exempt from that concern. It achieves the goal of looking like what "people would write anyway," but at a higher cost in terms of departing from HTML semantics. For example, how do you indicate semantic structure via Markdown to allow for CSS styling or Javascript manipulation of the DOM?

-----


Modern IDEs inject close tags and angle brackets into the source document. The SHPAML preprocessor injects that syntax into the target document. The use case applies to the person who wants clean syntax in the source document and executable syntax in the target document.

-----


The reason I made SHPAML a one-way preprocessor is that my use cases haven't yet given me a compelling reason to write a round tripper, and preprocessing is simple to automate.

I do not know what your criteria are for judging a "first-class" DSL in Python, so I cannot comment on the feasibility. My goal was to create a simple markup language that maps well to HTML and plays nice with templates. SHPAML does that.

-----


Sorry, I misread the title "Beautiful mini language for outputing HTML in Python" as a DSL to be embedded in Python code rather than a separate text file (which is actually language agnostic after the preprocessor is done).

-----


No worries. I am actually curious to your thoughts about DSLs. I love Python, but it is not really optimized for DSLs. You can obviously implement a DSL in Python, but embedding it is another story.

-----

More

Applications are open for YC Summer 2015

Guidelines | FAQ | Support | Lists | Bookmarklet | DMCA | Y Combinator | Apply | Contact

Search: