Live data from Hacker News

Replacing Python

roscidus.com

131–140 of 144 posts

Re: Replacing Python

#131
post #125

Earlier quoted context omitted.

Google uses Java because they were able to pick up a lot of really skilled Java developers during the 2001-2004 recession, and those devs built many of the products that were introduced in 2004-2007. Once a product's been built and adopted by the marketplace it's very difficult to change the implementation language. Most of the devs who were hired at Google from 1999 - 2002 still prefer C++, and products built in tha…

I'm not sure I get your point. Are you saying that Google's new programming languages adopt the Java philosophy because of developers they hired over ten years ago? Also, I'm not sure I understood what you were trying to say about C++ at Google.

I think his point is that the choice of language at google isn't exactly a managerial or strategic decision. They just happen to have a lot of java devs (probably at senior positions now, since they were hired a long time ago).Even if they have gone out, if most of your stuff is made in a language, it would be really difficult for new comers to shift that paradigm to some other language.

The part about C++ was to describe a similar scene. When they had mostly C++ devs, their language of choice was C++. and now they have mostly java devs, so java it is!

Re: Replacing Python

#132

Earlier quoted context omitted.

I've done a decent amount of work in both - I've written a compiler in OCaml and a few applications in Haskell. I do find Go to have the "best of both worlds" when it comes to the type system (ignoring all other features of the languages). As you know, one of the advantages of writing in dynamic languages like Ruby and Python is that you don't have to think much before writing down the first few lines of (working, ru…

Thanks! Another data point... I personally tend to see it as the worst of both worlds. I have to deal with types _and_ I don't really get strong guarantees. I don't run into problems in Ruby that Go's type checker could help with. But that's also my personality: I like extremes.

I'm curious what guarantees you're looking for that you don't get with Go that you'd get in other languages. I haven't worked with the more esoteric languages like OCaml and Haskell, so I might be missing something simple.

Re: Replacing Python

#133
post #46
post #6

Perhaps the title should be "Why Python is good enough." Between this post and the preceding one ( http://roscidus.com/blog/blog/2013/06/09/choosing-a-python-r... ), the takeaway for me is that the author didn't find sufficient benefit in any of the candidate languages to justify switching an existing product--perhaps not even a new product. It's true that Python can leave you with hidden crash bugs in unusual code p…

The other thing is his only complaint (slowness) isn't really a problem. If you have a critical hot spot in your server code, extract it, implement it in C / C++, and use ctypes to call it.

"slowness" is not the problem here - it's "slow program startup". If your process only lasts for tens of milliseconds, you're not going to make it any faster by embedding C code because 99% of time is still going to be spent initializing the python VM.

Re: Replacing Python

#134

I do not understand at all author's statement that OCaml datastructures are big win over Python's let {cache; config} = b in print_endline (String.concat "," cache); print_endline (String.concat "," config) ;; vs, actually I'm not even sure what the ocaml is attempting, some variation of print '%s,' % b.cache print '%s,' % b.config Which, in Python, if your printing more than a few should be print ',\n'.join((b.confi…

How is it a misuse of the term "pattern matching" ?

Generically http://en.wikipedia.org/wiki/Pattern_matching

And as for a language / call semantic look at Erlang for what actual pattern matching looks like.

Re: Replacing Python

#135
post #46

Earlier quoted context omitted.

The other thing is his only complaint (slowness) isn't really a problem. If you have a critical hot spot in your server code, extract it, implement it in C / C++, and use ctypes to call it.

Having recently started doing python full-time, I would say that by far the biggest problem with python is its propensity to explode in your face. Code written in python seems so fragile; except for the most blatant bugs like syntax errors or too few arguments, nothing gets caught. You end up having to write tons of unit tests, which often expose bugs that would be trivially caught with any kind of typing. Performanc…

This was exactly my sentiment when I started doing Ruby full-time.

I appreciate all the niceties that dynamic-typing language like Ruby provides. But I am not sure the trade-offs are enough (all you already described).

Re: Replacing Python

#136
post #125

Earlier quoted context omitted.

I'm not sure I get your point. Are you saying that Google's new programming languages adopt the Java philosophy because of developers they hired over ten years ago? Also, I'm not sure I understood what you were trying to say about C++ at Google.

I think his point is that the choice of language at google isn't exactly a managerial or strategic decision. They just happen to have a lot of java devs (probably at senior positions now, since they were hired a long time ago).Even if they have gone out, if most of your stuff is made in a language, it would be really difficult for new comers to shift that paradigm to some other language. The part about C++ was to des…

pron's point was [~ mainly] about the new languages from Google. nostrademons wrote mostly regarding what I wrote (and why it was wrong/simplified).

Re: Replacing Python

#137
post #76

Earlier quoted context omitted.

In the tests, his OCaML implementation takes 7ms, and his Python one takes 64 or 109 ms. So even on your SSD, that's 50% to an order of magnitude too slow, just for startup.

Do you really notice that though?

For stuff like tab completion and for launching small command-line apps (think "grep", "sed", etc), absolutely. A penalty of hundreds of milliseconds for the _launcher_ alone can double (or more) the total execution time.

I use zeroinstall a lot (I'm a contributor), and I turned off tab completion because the lag (of the python implementation) made me wonder if my terminal had locked up, which was far more distracting than trying to remember the available arguments. I have re-enabled it in the ocaml port, because now it's effectively instant.

Re: Replacing Python

#138

Earlier quoted context omitted.

How is it a misuse of the term "pattern matching" ?

Generically http://en.wikipedia.org/wiki/Pattern_matching And as for a language / call semantic look at Erlang for what actual pattern matching looks like.

That doesn't contradict the use of pattern matching in OCaml.

Re: Replacing Python

#139

Earlier quoted context omitted.

Thanks! Another data point... I personally tend to see it as the worst of both worlds. I have to deal with types _and_ I don't really get strong guarantees. I don't run into problems in Ruby that Go's type checker could help with. But that's also my personality: I like extremes.

I'm curious what guarantees you're looking for that you don't get with Go that you'd get in other languages. I haven't worked with the more esoteric languages like OCaml and Haskell, so I might be missing something simple.

First of all, I just want to say that I don't think that Haskell or Rust are competing with Go, we're just talking type systems here. I'll use those two because they're my favorite. Three examples, one from each and one they share:

In Haskell, the type system ensures that side effects only happen in one place: things inside a monad of some kind. For example, if I'm given a function:

    foo :: Int -> Int
I _know_ for a fact that this function doesn't do any IO. It doesn't maintain any state. It won't launch the missiles. And I also know that everything needed to understand what goes on in `foo` will happen via the one parameter. Because it's annoying to pass around code that interacts with the outside world, you end up with a small shell of imperative, stateful code, and a large amount of stateless, pure functional code. Since Go (to my knowledge) doesn't enforce referential transparency, it won't do this.

Haskell and Rust both don't have the concept of null. This is fantastic, as even the inventor of null thinks it's a bad idea. It's borderline irresponsible to write a new programming language with nulls today. So how do they handle a computation that may fail? Higher order types:

    use std::option::Option;

    fn call_me_maybe(x: int) -> Option {
        if(x > 5) {
            Some(x)
        } else {
            None
        }
    }

    fn main() {
        let i = 6;
        match call_me_maybe(i) {
            Some(x) => println!("Yes! {:i}", x),
            None    => println!("nope"),
        }
    }
This will print "Yes! 6". If you change it to 5, it will print "nope". The higher type wraps the output and tell us if we've succeeded or failed. Here's the kicker: what happens if we leave off the error case?

    rust.rs:13:8: 15:9 error: non-exhaustive patterns: None not covered
    rust.rs:13         match call_me_maybe(i) {
    rust.rs:14             Some(x) => println!("Yes! {:i}", x),
    rust.rs:15         }
It'll make us handle it. And since it has a different type, we can't pass it to something that takes an `int` either, because it's an `Option`. Both Rust and Haskell can do this, and have tools to make this easier, too. For example, maybe you want an error message, so Rust's Result type has a message on the fail case. Or you need three or more states, you can build your own.

Finally, in Rust, data is immutable by default:

    let i = 6;
    i = i + 5;

    rust.rs:3:8: 3:9 error: re-assignment of immutable variable `i`
    rust.rs:3         i = i + 5;
                  ^
    rust.rs:2:12: 2:13 note: prior assignment occurs here
    rust.rs:2         let i = 6;
And pointers have explicitly one owner or many owners:

    fn main() {
        let i: ~int = ~6; // read: i is an owned pointer to an int.
        let j: @int = @6; // read: j is an managed pointer to an int.
        let k = i;
        let l = j;
        println(i.to_str()); // error: use of moved value: `i`
        println(j.to_str()); // this is fine
    }
So in Rust, you cannot share data that has multiple owners across threads:

    fn main() {
        let i: ~int = ~6; // read: i is an owned pointer to an int.
        let j: @int = @6; // read: j is an managed pointer to an int.

        do spawn {
            println(i.to_str()); // fine, prints
        }
        println(i.to_str()); // you can't use it after you've given it away, either!
        // error: use of moved value: `i`
        // println(i.to_str()); // 
        //        ^
        //note: `i` moved into closure environment here because it has type `~fn:Send()`, which is non-copyable (perhaps you meant to use clone()?)
        //do spawn {
        //    println(i.to_str()); // fine, prints
        //} 

        do spawn {
            println(j.to_str()); // error: cannot capture variable of
                                 // type `@int`, which does not fulfill
                                 // `Send`, in a bounded closure
        }
    }
Therefore, race conditions are a compile-time error. Go has a race detector, which can help, but it can't always help.

Anyway, hopefully that explains some of my beef with Go's types. I think Go gets a lot of things right, I think the type system is one place where it gets things really wrong.

Re: Replacing Python

#140
post #9

The first Python example throws up a big red flag: manually parsing command line arguments instead of using argparse. Why reinvent the wheel when there is a standard library to handle it? Likewise, asserting that "For storing general records, Python provides a choice of classes and tuples" completely ignores one of Python's fastest and most powerful data types: dictionaries. Lastly, in get_value, the nest of ifs is u…

I was under the impression that using a class (with `__slots__` set) or a tuple is generally more performant than using dictionaries. At least, I assume that's why he didn't mention dictionaries.

The attributes of an object (and its class) are generally stored in a literal dictionary, so it's unlikely that a class will be more performant.

What a class buys you is behavior and a semi-defined interface.

Post reply on HN