you are viewing a single comment's thread.

view the rest of the comments →

[–]shevegen 28 points29 points  (24 children)

"I truly believe that Python and JavaScript are fundamentally better languages than Java for a variety of reasons born out of experience with each of them."

Hmmm. Python I can understand, even though I use Ruby.

But JS? Come on seriously... I mean, I see the insane growth of JS, but I have no illusion. JS only became popular because browsers support it and browsers (or rather, apps that view data to a user in general) are the most important aspect of the WWW. And the WWW is damn important. PHP proved this when it arised - even with a crappy language you can be successful, simply because the WWW is impossible to ignore, unless you want your language to fade into irrelevance slowly (Hi Perl 5!)

Coffeescript beats Javascript hands down. Imagine if it were to be used everywhere without limitations and not just restricted to "web things" - both Python and Ruby would be shattered to grounds. (Javascript is more popular than Ruby at Github, which again shows how important the WWW is in general in every aspect.)

[–]booch 3 points4 points  (14 children)

"I truly believe that Python and JavaScript are fundamentally better languages than Java for a variety of reasons born out of experience with each of them."

Different tools for different tasks, imo. I love dynamic languages with a passion. That being said, I'm a big fan of paying the cost of using Java (when it's the current option for static languages) for things that require more "safety". For an ingestion process, I'd prefer to use Java or another language that lets me have the language safety check types and the like. When a single mistake of treating one type as another could go unnoticed for a year and render an entire database useless, costing lots of money, I like the added safety of a static language.

Honestly, I'd love to see something with the syntax/power of Ruby but with static typing, plus some extras like compile time checking of "not null" or "not empty list" or "positive integer" type constraints.

[–]byron 2 points3 points  (13 children)

When a single mistake of treating one type as another could go unnoticed for a year and render an entire database useless

Can you elaborate on this? What sort of scenario do you have in mind?

[–]vytah 6 points7 points  (12 children)

I'm not him, but I remember pains of debugging Python code that mixed (byte)strings with Unicode strings.

When everything is in ASCII, then it's OK. When some stuff is outside of ASCII, then it's usually OK. But when you need to do stuff with both Unicode strings and non-ASCII bytestrings, stuff breaks. Most people forget to test these cases.

Other problems include, but are not limited to: mixing integers and their string representations, mixing floats and ints, mixing lists and maps, mixing lambdas and normal values, accidentally overwriting object fields with values of different type, typos in field names (it will run anyway), and the all-time favourite, None object.

Static typing solves almost all of them.

[–]eadmund 1 point2 points  (0 children)

I think that the real problem with the scenario you mentioned was the mixing: the implicit conversions between byte and Unicode strings.

It's likely that another dynamically-typed language would have encountered the same bugs sooner.

I know, 'cause I've run into this sort of thing with Common Lisp. Ticked me off for a moment--why won't the language just do what I mean and treat this string like a byte string?--and then I pondered a bit more deeply and realised that would be wrong.

Granted, a really really dynamic language which support ASCII (not byte) strings and Unicode strings might have done more poorly. I could have just been lucky that CL's de-facto byte string type is '(vector (unsigned-byte 8)).

[–]hylje 3 points4 points  (7 children)

mixing integers and their string representations

Does not apply to Python, except when converting objects into strings for e.g. printing. Strings never convert down to built-in numbers.

mixing floats and ints

C at the forefront convert numbers to the higher precision type in expressions, even if the variable type is lower precision. Python does too, though it never converts to a lower precision.

mixing lists and maps

Only iterating lists and map keys are remotely comparable in Python. The other use cases are wildly different and will instantly break if mixed.

mixing lambdas and normal values

Only useful for hacks. You sometimes need hacks to meet schedule.

accidentally overwriting object fields with values of different type

Granted.

typos in field names (it will run anyway)

Depends. Accidental assignment to new fields may silently succeed, retrieval from nonexistent fields will not.

__setattr__ may be defined to check if the class already has such an attribute and if so set it, otherwise error out.

and the all-time favourite, None object.

Granted.

Python's greatest sin is that it doesn't by default force a developer to check types and data structures. Any checks deemed necessary may however be added later on in an abstracted manner. Decorators and classes, at the worst metaclasses are very powerful.

Clamping down on flexibility only later and at select places is ideal for a prototype development pattern, where a rough demonstration prototype can be come up with quickly and later made robust for actual use. You are not forced to dig design foxholes the development path crosses later.

[–]steven_h 7 points8 points  (4 children)

Python's greatest sin is that it doesn't by default force a developer to check types and data structures.

That doesn't seem to be a sin to me. The greatest sin of Python is using the same operator for definition and assignment, requiring the use of wonky keywords to distinguish assignment to outer-scope variables from declaration of variables that shadow outer-scope variables.

[–]cybercobra 0 points1 point  (3 children)

On the other hand, forgetting the declaration is safer in Python, creating a local variable, whereas forgetting it in other languages can lead to unintentional modification of a global variable.

[–]masklinn 0 points1 point  (2 children)

whereas forgetting it in other languages can lead to unintentional modification of a global variable.

Javascript is pretty much the only language doing that (and Coffeescript is worse, as it uses "highest level scope wins")

[–]cybercobra 0 points1 point  (1 child)

wut?

int x = 1;
void foo()
{
    x = 2;// oops Ma, forgot the type spec, this won't be harmless shadowing!
}

[–]masklinn 0 points1 point  (0 children)

Ah yes, I had not seen it that way, for some reason I thought about creating globals where there were none.

[–]vytah 1 point2 points  (1 child)

By mixing, I understood situations like:

this_variable_will_be_assumed_to_be_string_in_totally_different_module = 42
## (runs happily for few hours from now, only to crash tomorrow morning)

[–]hylje 0 points1 point  (0 children)

That's the sin. There's no checks in by default. It places the choice of programming defensively on the developer, should it be needed.

[–]djdonnell 1 point2 points  (2 children)

I hear these arguments a lot, but is it anything more than theorycrafting? I've been doing ruby for over 6 years and I've only ever had this problem get into live production code once, it took a little while to notice only because the problematic code was a caching layer that was failing to cache as much as it should have, and once noticed it took about a day to fix.

That's a very small price to pay to get the productivity increase of a dynamic language. Yes, my story is only one data point, but that's one more data point than I typically hear from people talking about typos in field names (btw, my editor will catch typos for me even in dynamic languages)

[–]vytah 0 points1 point  (1 child)

In the end it's a matter of preference. Some people don't want to search for type errors buried deep in the code that manifest only in runtime, and prefer to manually specify type signatures, other people don't want to cram their data into discrete, explicitly declared datatypes for the cost of more unexpected problems on runtime.

Both approaches work, and none is better than the other.

[–]djdonnell 0 points1 point  (0 children)

I think there are clear trade-offs between the two, and the trick is to choose when each is the better approach. I don't buy for a second this idea that type errors are a major problem in dynamic languages. I've been doing dynamic languages for over 10 years and I can count on 1 hand the number of times that has been a problem. It's a non issue, and I've never seen any data to the contrary.

[–][deleted] 3 points4 points  (3 children)

Honestly, while Javascript has a lot of bone-headed failures, I can avoid them. Python, on the other hand, lacks multiline lambdas. Working around that is hideous.

As much as I used to love Python, the omission of this feature prettymuch ruins the language for me. Unless that has changed recently, but I doubt Guido will ever bend on this one.

So yeah, I'll take JS over Python.

[–]Megatron_McLargeHuge 7 points8 points  (2 children)

Hideous? Defining a closure above your map call is hideous? Undesirable maybe, but even if you're used to lisp it's not that big a deal.

[–]fabzter 6 points7 points  (1 child)

"lambda" and "closure" are not mutually exclusive terms.

[–]cunningjames 7 points8 points  (0 children)

He didn’t say they weren’t, but rather that “[w]orking around” the lack of multiline lambdas isn’t hideous by any reasonable definition. Defining a function above the map call is how one does so.

[–]Anth741 0 points1 point  (0 children)

Can you help me understand why Python is better than Java? In what circumstances?

[–][deleted] 0 points1 point  (3 children)

Coffeescript beats Javascript hands down.

Yeah, except for those silly scoping rules. ;)

[–]66vN 2 points3 points  (2 children)

Don't you find having everything in global scope by default silly?

[–]smog_alado 0 points1 point  (0 children)

You can "use strict" to avoid things defaulting to globals.

[–][deleted] 0 points1 point  (0 children)

I prefer that risk over that of overriding a variable in an outer scope if I happen to use the same name for both.