Hacker News new | past | comments | ask | show | jobs | submit login
For modern development Javascript indeed is a shit language (julik.nl)
160 points by CmonDev on Oct 29, 2013 | hide | past | favorite | 238 comments



Despite most of the points in this post being debatable — there's one bit that caught my eye:

    "Being nice will not help it, and CoffeeScript is not radical enough."
As the guy who started CoffeeScript, I agree. It's an intentionally very conservative approach. But there's more than one good way to skin the JavaScript cat. I think it would be fun to take another run at the same problem — attempt to find a minimal, readable, and easier-to-learn language that fits in the same role as JavaScript — but to do so with a much more radical design. Whereas previously such a thing would have been unusable in practice, having good sourcemap support in most browsers these days makes it viable, perhaps. I've been playing around with it a bit...


I have no idea why, but CoffeeScript gives me a "kid on Christmas" feeling when I code in it. I never realized how much mental load went into counting braces and curly brackets, how many times I've tried randomly copy-pasting a variable assignment into different parts of a script until I stopped getting an error, etc. This weekend, I decided to pick up Node, and, to kill 2 birds with one stone, I've been rewriting every tutorial I've used as CoffeeScript just to test myself.

I've tried to think about potential improvements to CoffeeScript, but I have to say that I'm completely satisfied with the language now. Many of the things that I think would sweeten the language even more are easily achieved by simply including 3rd party JavaScript libraries.

Thank you so much for contributing 3 great pieces of work to the community!


This is how I learned Angular and CS, by writing the todo apps in CS...after a bit, it was much easier to think and reprocess the concepts in my head as coffee script, especially when it came to test writing. I think the must-have for me is te bevy of ways to do auto compilation these days


I very much agree. Now, I only touch raw JavaScript when I absolutely have to.


> I think it would be fun to take another run at the same problem — attempt to find a minimal, readable, and easier-to-learn language that fits in the same role as JavaScript — but to do so with a much more radical design.

Do you think ClojureScript could fit this category? We have teams that use it in production without any significant problems at all.


It certainly could, and particularly so if you come from a Lisp background.

But it also connects to a larger universe of Clojure libraries and practices, and a vast history of Lisp tradition — most probably for the best. In that sense, it might be more of a maximalist approach than what I'm looking for. (And (of course) readability is in the eye of the beholder ;)


Have you seen Wisp? [1] It's a minimalist approach with Clojure syntax. For me it may be the next step after CoffeeScript, which I believe has subtly brainwashed me into loving the lambda.

[1] https://github.com/Gozala/wisp


Keep up the good work!

I still think the main point around javascript is the type system or the lack thereof. I don't mind dynamic typing, but the javascript data types are central to all HTML5 APIs and most existing libraries. CoffeeScript gets this right, many others don't.


TypeScript & Dart are offering optional typing. ASM.js is seeing big performance gains through utilizing the numeric types, and avoiding the GC monster.


    > CoffeeScript gets this right, many others don't.
I'm not sure what you mean by that — as CoffeeScript's "type system" has no difference from JavaScript's.


Exactly.


CoffeeScript was obviously inspired by Ruby. While CS is great, I've never gotten over the usage of "->" or "=>" to signify a function. To me, Ruby's "def" or "do" reads so much better. Especially with "end", to signify a barrier, as opposed to whitespace. Have you considered porting Ruby directly to JavaScript?

By the way, thanks for your work on _ & Backbone!


    > Have you considered porting Ruby directly to JavaScript?
No. It's been attempted before, and it doesn't turn out to be terribly useful in the end, because of the vast semantic mismatch between the two languages. See: https://github.com/jashkenas/coffee-script/wiki/List-of-lang...

    > I've never gotten over the usage of "->" or "=>" to signify a function.
Give it a try, perhaps. It's critical not to use "def" and "do" when your functions are first-class values that can be passed as arguments, or assigned to variables. It's for this reason that Ruby 1.9 has a new lambda syntax that looks a great deal similar to CoffeeScript's. For example:

    request(url, def callback(response) do
      ...
    end)
... that kinda thing is no good.

The reason it's an arrow is because in any decent function, the input determines the output, eg. input points to output. And therefore, the CoffeeScript syntax: (input) -> output


>> it doesn't turn out to be terribly useful in the end

True, I'd chose CoffeeScript over Opal.

>> Give it a try, perhaps.

Oh, I dig it, especially the fat arrow.

>> It's critical not to use "def" and "do" when your functions are first-class values that can be passed as arguments, or assigned to variables.

Still, I find "def" to be more `readable` than arrow symbols. I'm not sure how JavaScript's first class status for functions would deter a keyword containing letters. Considering JavaScript itself uses function as its.

>> The reason it's an arrow is because in any decent function, the input determines the output, eg. input points to output. And therefore, the CoffeeScript syntax: (input) -> output

That definitely makes logical sense. Still, I feel the readability might be increased by using words, which the mind is more attuned to quickly applying meaning to.

Edit: Great job, on CoffeeScript, regardless!


Also worth pointing out that the fat arrow lambda expression is coming in ES6 [1] so you will see it in vanilla JS soon!

[1] http://www.nczonline.net/blog/2013/09/10/understanding-ecmas...


> Especially with "end", to signify a barrier, as opposed to whitespace.

But in any programming language you're already indenting blocks for humans. Why repeat the same work? Especially when it allows for inconsistency between how a human and how a machine would read the code.


To increase the clarity, for future collaborators.


People HAVE written Ruby -> Javascript compilers. Check out Opalrb, Redscript, Coldruby, Hotruby, Webruby...

The -> comes from Haskell's lambda syntax (\x -> x+1). It's a nice solution. 'Def' doesn't really work for lambdas, do does, but curly-brace blocks are nicer in Ruby if you put them everwhere {|x| x+1}... Keep in mind that Javascript is alot like Scheme in that there isn't really a difference between named and anonymous functions. You can write Scheme and Javascript pretty much the same way...


Great points! I really want to check out Scheme now.


The arrow is standard mathematical notation for function definition


That's a good point, it has historical significance.


> Have you considered porting Ruby directly to JavaScript?

It's been done. Check out Opal. I can't say I miss Ruby's ends in CS.


Opal is cool. I prefer CoffeeScripts approach to adding functionality though, without including an entire new standard library.


> I've been playing around with it a bit...

Tell us more!


I'm afraid that there's not much to show yet, apart from some little prototype scribblings, and the basic idea:

The web that we build for today is a rich, almost entirely backwards-compatible stew of nearly two decades of browser development and standards work, resulting in a triumvirate of very different languages that need to come together in order to make a web application happen: HTML + CSS + JS. Two of them are weak, data-description languages, one is strong and general-purpose. You have to learn all three, and learn about the quirks and sunspots accumulated over the years.

So, as a thought experiment, imagine what it would be like to work with a single language that was general-purpose, but also excellent at describing data, especially the trees (HTML) and property lists (CSS) that make up web documents. Perhaps it knows about the intended lifecycle of your HTML in a more structured way. Perhaps other flatly descriptive parts of your application can be merged with the "flat" styling of your CSS descriptions. Perhaps the idea of "binding" is built-in.

After that, there's technical hoopla. If it's interpreted in the browser, you need to be light and parse quickly, you need to be able to "JIT" chunks of code into optimized JavaScript when necessary, and you need to be able to dynamically generate the appropriate source maps, so that it feels closer to a seamless experience.

Is such a unifying language possible? I don't know. But imagine how much more fun it might be to work with — and more importantly, how much more accessible it could be for folks just getting started.

But when there is something to show, y'all will be the first to know...


"So, as a thought experiment, imagine what it would be like to work with a single language that was general-purpose, but also excellent at describing data, especially the trees (HTML) and property lists (CSS) that make up web documents."

You can accomplish this pretty effectively with a clojure/clojurescript stack, though it takes some work to get going and isn't perfectly seamless. Code-as-data seems really well suited to unifying the declarative and procedural.

Personally, I love the ideas behind clojure, but I prefer the experience of writing coffeescript to clojurescript. I think it would be very cool to see you combine your penchant for pragmatism and nimble syntax with the solid engineering principles of functional languages.


I've been prototyping a HTML CSS javasxript all in one language to do exactly this, in particular great support for in-code representation of the data structures common in HTML. Hopefully you'll beat me to it so I can stop spending time on it and use yours instead =D


ActionScript!


Yeah, the hilarious part of that being that Adobe, even prior to Steve Jobs's "flash sux" response, had begun to wander away from a purely ActionScript model into declarative markup via Flex.

I'm not 100% certain that declarative is wrong for presentational information. It just sucks that HTML + CSS are so messy. I'd even go for something that had a more parsimonious (note: not coupled tho) relationship between presentation/structure.


How do you feel about CoffeeCup + (CCSS or AbsurdJS)? Not unified enough?


so basically YAML and/or Jade + SASS + CoffeeScript. I dig it.


Very intriguing. I hope you pursue this, if anyone I think you're the right man for the job.


"but to do so with a much more radical design."

Now this is interesting. Working on anything!


Sadly I agree, you can just start with this:

    > [1,10,5,-15,-2,4].sort();
      [-15,-2,1,10,4,5]

And yes saying "oh but it is because it has weak types" doesn't excuse it, it is broken and that's that. Naming the brokeness with a label or showing why historically it is there, doesn't fix it.

On the other hand they do have nice closure support, I do like some of that. But in large, the language makes me angry every time I have to use it.

Someone mentioned Dart, I am hopeful for that. But who knows how long till dartvm is embedded in Chrome. For now dart.js and source maps might help.

There is a bit more palatable Coffeescript. But it only puts some band-aids over JS's brokenness.

Also agree with callback hell. It is funny people extol is at the next big thing -- whoo, asynchronous calls! You can callback in your callback while you callback. No, no, no. That is a horrible way to handle large concurrency problems! (Good for quick one page examples though!). Async and friends help. But why the heck do I need to stick a callback in the middle of my logic if all I need to do is make a request to the database or another GET request?

The only sane way I know how to best handle concurrency is using a language with support of goroutines/isolates/tasks or even threads and queues. Even deferreds are just sugar on top of callbacks. We all know how Python's Twisted has taken over the world, right? Oh wait, it hasn't. Calling them Futures or Tulips or whatever doesn't fix the underlying problem.

> I can understand that some people wanted to escape the MRI infrastructure by going Node, because - you know - learning Japanese is hard.

Granted node is fast. (And according to its author scales linearly across CPU cores, sorry couldn't resist the mandatory jab at that). Ok it doesn't really scale across cores and it will block everything if you do a for loop in the middle of your logic. But it is really fast, amazingly so. And that is like crack. It gets people hooked.

EDIT: JS has weak types not just dynamic, one can have dynamic and strong types for example, like Python ( https://en.wikipedia.org/wiki/Weak_typing ). Thanks makslinn.


> And yes saying "oh but it is because it has dynamic types" doesn't excuse it

It has nothing to do with dynamic types[0]. It has to do with

> If compareFunction is not supplied, elements are sorted by converting them to strings and comparing strings in lexicographic[0]

period end of the story. You might argue it's a shitty default, but please argue against reality, not what you (wrongly) believe it is.

[0] this is the MDN translation, the exact specification is steps 14 to 18 of the SortCompare abstract operation, defined in ECMA-262 5.1 15.4.4.11 "Array.prototype.sort (comparefn)":

    13. If the argument comparefn is not undefined, then
        a. If IsCallable(comparefn) is false, throw a TypeError exception.
        b. Return the result of calling the [[Call]] internal method of comparefn passing undefined as the this value and with arguments x and y.
    14. Let xString be ToString(x).
    15. Let yString be ToString(y).
    16. If xString < yString, return -1.
    17. If xString > yString, return 1.
    18. Return +0.
[0] your edition to "weak types" is just as wrong as the previous version I quoted was.


The correct answer is it has to do with weak types.

> `If compareFunction is not supplied, elements are sorted by converting them to strings and comparing strings in lexicographic` period end of the story.

As I said explaining the historical context or labeling the brokennes with something like "weak typing" doesn't excuse. It still stays broken.

> You might argue it's a shitty default, but please argue against reality, not what you (wrongly) believe it is.

Surprise, I know it is possible to eventually sort things in JS. I too have seen sorted tables in JS done entirely in JS. That's not the point. The point is, it is has fundamentally broken type system.


> The correct answer is it has to do with weak types.

No, it does not. You could define the exact same default function in Java, Haskell (requiring that the sorted type be a Show instance) or Python (hell, getting the exact same behavior in Python could hardly be simpler: `ar.sort(key=str)`. There, I broke it. That is near literally how the ECMAScript spec very explicitly defines the default comparison function. The behavior of the sort function is not a consequence of weak typing).

> As I said explaining the historical context or labeling the brokennes with something like "weak typing" doesn't excuse.

Which you'd know is not what I'm doing, if you could be arsed to read instead of trying to substitute your imagination for objective reality.

> The point is, it is has fundamentally broken type system.

That might well be, but the default sort comparison function is not a demonstration of it. As opposed to the comparison table of 0 and null for instance:

    > 0 < null
    false
    > 0 <= null
    true
    > 0 == null
    false
    > 0 >= null
    true
    > 0 > null
    false


> That might well be, but the default sort comparison function is not a demonstration of it.

Yes it is. It demonstrates weak typing which I also think is broken. If I wanted to sort a string, I would have done this:

      > ["1","2","3"].sort()
> (hell, getting the exact same behavior in Python could hardly be simpler: `ar.sort(key=str)`. There, I broke it.

You broke it by writing more code. That's good. Javascript is broken __unless__ you write additional code. That's the crux of the matter.


> Yes it is. It demonstrates weak typing which I also think is broken.

For the third time, no. There is no implicit conversion process during the comparison, the default comparison is explicitly specified to convert both of its arguments to strings before doing the comparison.

Javascript does not trigger conversions to compare two numbers, so relying on the type system would actually do exactly what you want.

> You broke it by writing more code.

Meanwhile you completely missed the point of posting the snippet.

> Javascript is broken __unless__ you write additional code.

And as I replied the first time around, I have no objection with the assertion that the default sort comparison function is garbage, I have an issue with your assertion that it is a consequence of weak typing because it is not.


> No, it does not. You could define the exact same default function in Java, Haskell (requiring that the sorted type be a Show instance) or Python (hell, getting the exact same behavior in Python could hardly be simpler: `ar.sort(key=str)`

I don't use JavaScript but to me this looks like a really broken implementation over weak typing. Of course, this isn't a trait of the typing system per se as it is a trait of the "interface", if you will, that it offers to the programmer.

What OP was probably annoyed by was the typical excuse the JS community offers for this behaviour: "it's weakly-typed so you can treat the arguments as anything you want". This misses the point of having a weak typing system: instead of using it to infer the type of the arguments and get a sane default comparison function, avoiding the verbosity typical of strongly-typed languages (where you have to specify the comparison function with the correct type signature), you have to specify the comparison function for anything that isn't a string. Bummer :-(.

I hope I haven't missed anything here; as I said, I'm not quite fluent in JavaScript.


Well as masklinn says this is a standard library function; the bad design is a property of that API and not inherent to the type system. It does perhaps reflect the 'philosophy' of Javascript, as evidenced by all the people in this thread defending this awful behaviour. Take the example of Io, which has a lot of similarities to JS but has stronger typing and syntax that I hope is fairly self explanatory:

  list(-3, 4, 10, 6, 1, 2) sort
  ==> list(-3, 1, 2, 4, 6, 10)
And to show that you can implement the Javascript behaviour in a language without implicit type conversions:

  list(-3, 4, 10, 6, 1, 2) map(asString) sort
  ==> list(-3, 1, 10, 2, 4, 6)
Javascript merely defines the standard sort function to be the latter.

One difference between Io and Javascript is that

  "10" > 2
throws an exception in Io (argument 0 to method '>' must be a Sequence, not a 'Number') so you can't sort a list that is a mixture of strings and numbers without explicitly converting them first (or using a custom comparator), since the standard sort function won't convert things for you (how would it know what you wanted to convert them to?). However that code is valid in Javascript, and actually returns 'true'. So the amusing thing here is that the > operator in Javascript actually does what you want (converts to numbers rather than strings) and if you sort with a custom comparator using the greater than operator then I presume it would give the correct result for an array of numbers. Something like this (disclaimer I'm not a Javascript developer, following code may be wrong):

  [7, -3, 6, 10, 1].sort(function(a, b){return a > b ? 1 : -1;});
  [-3, 1, 6, 7, 10]
For whatever bizarre reason the standard sort function is defined to convert to strings first.


> this looks like a really broken implementation over weak typing

No dammit, javascript does not coerce numbers to strings when comparing them, a "weak typing" implementation would behave exactly as he wants.

> What OP was probably annoyed by was the typical excuse the JS community offers for this behaviour: "it's weakly-typed so you can treat the arguments as anything you want".

That makes OP fractally wrong instead of merely broadly wrong.

> avoiding the verbosity typical of strongly-typed languages (where you have to specify the comparison function with the correct type signature)

Which you don't, not every language is Java and some actually have defaults. Which work. In fact, even in Java bloody java you don't have to provide a comparator to sort a list, as long as the list's items implement Comparable (that is, they can be compared to one another)


> No dammit, javascript does not coerce numbers to strings when comparing them, a "weak typing" implementation would behave exactly as he wants.

Please note that I wrote it's a broken implementation over weak typing, not of weak typing. The typing system is fine, at least as far as this matter is concerned, but the standard library is badly applied over it.


> Please note that I wrote it's a broken implementation over weak typing, not of weak typing.

But weak typing is a complete red herring, as I noted previously the behaviour of the default sort function is independent from the typing system, you could have a default sort function doing more or less the same thing in a very strict statically typed system.

Haskell's `sort` is defined (more or less) as

    sort :: Ord a => [a] -> [a]
    sort = sortBy compare
it could be (uselessly) defined as

    sort :: Show a => [a] -> [a]
    sort = sortBy (comparing show)
resulting in the same behaviour you see in javascript.


Yes, of course it is a red herring! OP's rage was against the JS community taking it as an excuse for shity implementation, that's all I was trying to clarify...


    > [1,10,5,-15,-2,4].sort(function(a,b) {return a > b})
    [ -15,
      -2,
      1,
      4,
      5,
      10 ]
    
    > [1,10,5,-15,-2,4].sort(function(a,b) {return ""+a > ""+b})
    [ -15,
      -2,
      1,
      10,
      4,
      5 ]
Perhaps .sort was initially designed to do something else, like sorting strings, rather than integers.


I'm pretty sure that the parent comment's author is aware of this. It does not change the fact that it's broken.


I don't know - it's just a default general API, obviously it's not going to match everyone's use case. I would say that even relying on sort made by someone else is already not fit for many use cases.

If such a petty and trivial "problem" is what you have against Javascript, then you are basically saying it's a good language :--)


Or you're saying that you know so little about it you don't know of its real problems.


Yet somehow it works just fine out of the box in plenty of other languages, including Python, Erlang, Clojure, Ruby, etc.


Yeah, plus it's not just thing one thing, but there is a good amount of seemingly little things like this that add up.


Why? Sorting strings is a far more common thing to do than just sorting numbers, so it makes sense to use simple string comparisons as the default algorithm. Rather than come up with something that first evaluates the types in the list and then tries to figure out what to do.


No, it makes sense to sort strings when you get handed strings, and sort numbers when handed numbers. Period. Default behavior is now exactly as expected by 100% of developers.

Your creativity as a language designer should only come in to play when dealing with sets of mixed type.


So how should [1, "a", 2, 3] be sorted by default?


Both Python and Erlang would return [1,2,3,"a"], Ruby and Clojure won't allow the comparison. Either of these approaches makes more sense than JavaScript's.


Javascript returns [1,2,3,a]. What's the problem.


    > [1,2,"10",3].sort()
    [ 1, '10', 2, 3 ]
That's the problem.


Not when I posted this, he's edited his comment.


It's not broken.


The sort function is fine when used as intended (for alphabetic sorting). If you want numeric sorting you use sort(function(a,b){return a-b}).

[1,10,5,-15,-2,4].sort(function(a,b){return a-b}); [-15, -2, 1, 4, 5, 10]


Ok but if I wanted to use alphabetic sorting I would have used ["1","10","5","-15"] no? Wouldn't that make more sense.


    > [1,10,5,-15,-2,4].sort();
    > [-15,-2,1,10,4,5]

    [1,10,5,-15,-2,4].sort(function(a,b){return a-b})
    [-15, -2, 1, 4, 5, 10]


So it is broken. I already gave it a list of numbers. Why do I have to subtract them to tell it how to compare them. If I wanted to compare string I would have used ["1","10",....].


     [1,10,5,-15,-2,4].sort (a, b) -> a-b
You're right; that was totally difficult.


  Safari/Chrome:  SyntaxError: Unexpected token '>'
  Firefox: SyntaxError: syntax error
In a discussion about Javascript maybe it would be a good idea to give examples of Javascipt that actually run in a Javascript console?


Firefox Nightly

    [1,10,5,-15,-2,4].sort ((a, b) => a-b).toString();
    "-15,-2,1,4,5,10"


You have responded to my pointing out that '->' syntax doesn't work in current browsers with an example of a different bit of syntax, '=>', that works in a single development browser. I don't follow your point.


Sorry you asked for an example which works in a Javascript console, I gave one, if you were trying to make a snarky reply about the state of es6 support in modern browsers then I misread it.


Actually when I posted it I was honestly unaware if that was ES6 Javascript or just Coffescript or something. People seem to throw them all about interchangeably which is very confusing to people like me who don't follow Javascript development.


People dont write JS just for Firefox Nightly.


I didnt say they should (some people do), it is code which works with a JavaScript console though


Personally, I disagree. I find JavaScript to be the most "write-able" language, and switching to Node + frontend JS as my main language (I've done Python, Ruby, PHP, Java and C++ as jobs) has been the best thing I've done in a long time. Express and Angular are amazing.

Sure, it has a bunch of quirks. Sure, it's not good for everything (I do mostly relatively simple CRUD apps). Sure, in the browser, it gets slow when the DOM is involved. Sure, this is hardly a rebuttal of the points in the original article.

But, still, I love JavaScript.

I think the problem is that the author is writing JavaScript as though it's Ruby. A JS developer switching to Ruby would have similar problems.


I see this all the time. JS is slow because of the dom. No. JS is slow because JS is slow. Yes, I know V8 makes it faster than it used to be. Yes I know it is neck and neck for computation, but because of the way memory is handled it is slow for loading large dictionaries.

But I could forgive all of that.

JavaScript is not well designed for work in a team environment, nor is it well designed for Large Code Bases.

But I could forgive all of that.

All the best languages have a group of scientists that have chosen that language to be their defacto language. That is why we see Python, LISP, Fortran (yes still), MatLab, all living on long beyond the "trendy" languages.

JS only picked up steam because Flash died. Not because it was a great language. If it were a great language people would have started optimizing it 5 years ago. It isn't. So they didn't. The new optimizations are out of necessity. And because it lets front end pretend to be backend. That may sound snobby, and it is, but JS for backend is like writing in Visual Basic. These days you can do anything in it, it will be fast, but that doesn't make it the right choice.


>> JS only picked up steam because Flash died. Not because it was a great language. If it were a great language people would have started optimizing it 5 years ago. It isn't. So they didn't. The new optimizations are out of necessity. And because it lets front end pretend to be backend. That may sound snobby, and it is, but JS for backend is like writing in Visual Basic. These days you can do anything in it, it will be fast, but that doesn't make it the right choice.

Very much ^this.

I never cease to be amazed by the defensive attitude and excuses coming from JavaScript developers. Usually the premise is "I can get shit done in it, so it must be good", which isn't a particularly strong argument.

If you would make up 20 completely different metrics to rank programming languages on, and score every popular language using each of them, JavaScript would be near the bottom of almost all of them, and near the top of none. It's not terrible in every way imaginable (it would score reasonably well on 'productivity' for example), but it's not great in any of them either, which frankly makes it a shit language that only exists as a historical accident.


The problem is that JS is a monopoly. Monopoly is never good.


I wanted to switch to other languages rather often, but most of them are getting strange quite early in the learning process.


> JS is slow because JS is slow.

JS is the fastest dynamic language next to SBCL's Common Lisp implementation.

> JavaScript is not well designed for work in a team environment, nor is it well designed for Large Code Bases.

Why is this a problem? Most web problems don't need a large code base. A small, dynamic language is suited to web problems. And judging by the amount of things being built with Javascript, enough people have figured out its quirks.

> All the best languages have a group of scientists that have chosen that language to be their defacto language. That is why we see Python, LISP, Fortran (yes still), MatLab, all living on long beyond the "trendy" languages.

To a certain degree I agree, at least about LISP and Fortran. You should add Haskell to the list. One language has also lived long beyond most of the trendy languages: COBOL. Take that for what it's worth.

> but JS for backend is like writing in Visual Basic. These days you can do anything in it, it will be fast, but that doesn't make it the right choice.

Why this is even an issue is beyond me. Nodejs is good for people writing a small backend to interact with a single page app on the client side. If you're writing giant Nodejs apps you're doing it wrong.

Besides, with pretty much every language having web frameworks and every language compiling to JS, you have plenty of choices.

Despite all of JS' quirks, people still write amazing things in it. That should tell you something.


> Why is this a problem? Most web problems don't need a large code base. A small, dynamic language is suited to web problems.

This is demonstrably false the second you start to use JS on the backend. Just because most of the problems you've seen require only tiny codebases does not mean that they all do.


Then use something else on the back end. Problem solved.

I'm saying the places you need JS and only JS are small. Have a larger problem? Use a statically typed language on the back end, and compile to JS on the front...


>"JS is slow."

In comparison to what? JS is one of the faster script languages out there. V8 is way faster that Ruby and outperform python a lot of time as well. It's regex is blast fast as well.


It outperforms Python at everything except where Python just calls a C function. Ruby (especially the recent releases) is on par with Python speed, if not faster. But neither is close to JS.


"My pet is fast because it can beat a turtle and a slug in a race"


Lol. Seriously though, show me a dynamic language (other than Lisp) that's even half as fast as Javascript...


Without Python, Ruby, Javascript and Lisp, we are sort of running out of dinamic languages options..

But the funny thing is the one that got left out, is the one that is faster than Javascript: Lua


Is it really faster than Javascript though?

http://benchmarksgame.alioth.debian.org/u32/benchmark.php?te...


This is for the lua interpreter. aka the PUC-Lua You should compare it to Luajit, wich is a proper JIT compiler as V8..

The benchmark game used to have Luajit, but they take it out for no reason..

You can download the scripts and run in you local machine against V8, using Luajit for real comparison..

http://luajit.org/

Also this link compare a lot of language implementations in different benchmarks than the ones in shootout

http://attractivechaos.github.io/plb/

edit: also see this blog post about benchmarks; if i am not mistaken, this guy is behind V8 and Dart VM's implementations

http://mrale.ph/blog/2011/05/12/dangers-of-cross-language-be...


Who says "JS is slow"? It might even be the single most heavily optimized scripting language ever. Given that Apple, Google, Microsoft and Mozilla work on high performance JS VMs (half of them open source) and in a public competition with benchmarks and claims for fastest browsing experience.

Performance was one of the selling points of Node.JS for me.


Some would argue that Flash's death was hastened by JavaScript, not the other way around. (And Steve, and..)


They did start 5 years ago. You obviously weren't around for IE6. Man that js engine was sloooowwwwwwwwwwwww. Like several orders of magnitude compared to modern ones.


I like JavaScript, and I don't really know what was wrong with Visual Basic either.


How do you handle Javascript ignoring wrong numbers of function arguments? Do you use a linter to catch this sort of thing?

This part of Javascript sounds the most absolutely insane to me: Silencing an error like that is catastrophic.


Generally speaking, in the JS world at least, if you're passing more than a few parameters into a function you might have code complexity problems. If you need to pass in a bunch of data to a function you tend to do it in a single options object with some runtime checking to work out what to do with it. Any remaining problems should be caught with good test coverage. Being able to flexibly and clearly handle variable numbers of function arguments without getting entangled in an involved function overloading syntax and methodology is actually sometimes pretty nice. It's a feature not a problem. Haha :P


>>How do you handle Javascript ignoring wrong numbers of function arguments?

>if you're passing more than a few parameters into a function

I didn't know you had to have "more than a few parameters" before you could make a coding error related to the number of parameters you pass something.


It's just never been a problem for me, I guess? I know how it works in JS, so I either ignore it or use it to my advantage (the JS equivalent of overloading). You seem to come from a more strongly-typed background, but I've never once found the way JS handles it to be "catastrophic".


How do you ignore it? Ignoring it means accepting cryptic bugs that result from signature changes.

You say "use to your advantage", but what's the advantage? You could have a "*args" like Python, and get the benefits without the (huge) drawback.

The typing debate is mostly about how much effort we should exert to catch errors at compile time rather than run time. In JS, it is much worse: It defers error catching forever, and never even catches them at all! It converts them to silent bugs, instead :(


Is this so much of a problem that we need to re-design JS to handle it? Why not just avoid making this mistake in the first place by reading the code? Not to sound dismissive - but if you're making these kinds of mistakes regularly enough to irritate you, it's not the language that's at fault.

Javascript's squishiness is the thing I like the most about it. It's far from perfect, just like any other language out there - but it's fun.


> Why not just avoid making this mistake in the first place by reading the code?

We're talking about programming errors. Are you suggesting the solution to human error is to just not make errors??

Note, of course, that wrong arguments will frequently not arise from a function call you just wrote -- but from changes in the code.

Say you merge in a trivial merge of some code, which changed a function's signature/parameters. The merge succeeds trivially. Now every single function call is a bug that is not only uncaught by a compiler. It won't even necessarily be caught at runtime. Instead, it may escalate to catastrophic, undefined/unexpected behavior.


> We're talking about programming errors. Are you suggesting the solution to human error is to just not make errors??

Not at all, I'm simply suggesting that people take care to acknowledge and operate within the rules of the language. If you're making changes to a function signature in JS without assessing the impact for code elsewhere, then you're doing a bad job - and that's all there is to it. JS allows you to do something which when ignored or fucked up, results in problems. This is not a JSism - this is just the way things work. Every language has 'features' like this. If you don't know what you're doing, then stop doing it. "A bad workman blames his tools" and all that jazz.

> Note, of course, that wrong arguments will frequently not arise from a function call you just wrote -- but from changes in the code.

So JS has a (potentially) higher maintenance cost. This doesn't mean that JS is badly designed - it's just a trade-off. Some people don't care, others do. Clearly to some people, it's an unacceptable cost - but all that means is that those people have a lower tolerance for that kind of thing than others.

> Say you merge in a trivial merge of some code, which changed a function's signature/parameters. The merge succeeds trivially. Now every single function call is a bug that is not only uncaught by a compiler. It won't even necessarily be caught at runtime. Instead, it may escalate to catastrophic, undefined/unexpected behavior.

This is just a case for good documentation and release notes. Don't merge in changes that you don't understand.


> If you're making changes to a function signature in JS without assessing the impact for code elsewhere, then you're doing a bad job - and that's all there is to it.

Given that other people are working on the same code base and may have added calls to this function, this is not even possible.

Also, dynamic languages all require you to fix calls to changed functions. But at least, when you test that code, it won't accidentally seem to work when it is broken.

Also, humans cannot do a perfect job every time. We will all make mistakes, and our tools shouldn't give us hell over those mistakes for miniscule to no benefit at all as in this case.

Out of thousands of changes to function signatures, do you think none would ever forget to fix a caller?

> So JS has a (potentially) higher maintenance cost

This doesn't sound potential at all. It sounds like you either lose a huge amount of reliability, or add a huge burden to development.

> it's just a trade-off

What do you gain here? You save an asterisk in the syntax when you want to overload?

> This is just a case for good documentation and release notes. Don't merge in changes that you don't understand.

In a collaborative environment, we merge work with each other every single day. Do you have documentation and release notes for every commit you publish? Do you go and check the commit's release notes every time you pull?


> Given that other people are working on the same code base and may have added calls to this function, this is not even possible.

Except it clearly is possible since I and millions of other developers seem to manage it daily.

> Also, dynamic languages all require you to fix calls to changed functions. But at least, when you test that code, it won't accidentally seem to work when it is broken.

This is a problem of your code-base, not the language. If your code is so brittle that it can't stand a few function changes without collapsing into a miasma of shit, then whose fault is that? Of course you need to fix calls to changed functions - but if doing so is causing you and your team pain, then perhaps you have other problems.

> This doesn't sound potential at all. It sounds like you either lose a huge amount of reliability, or add a huge burden to development.

Of course it's potential. Nobody's forcing you to write tightly coupled, shitty code which breaks after every merge. Seriously? Figure it out.

> What do you gain here? You save an asterisk in the syntax when you want to overload?

Like I said before, squishiness.

> In a collaborative environment, we merge work with each other every single day.

As do I, and clearly millions of other developers who don't seem to run into your problems.

> Do you have documentation and release notes for every commit you publish?

We have proper commit messages and tracking codes for every task / bug, yes. There's no such thing as perfect information - and sometimes merges get messy - but this is not unique to JS. Sure, not every single commit is perfectly documented, but small commits and concise messages go a long way to ensuring that the history is traceable and the code is clean. The more often you commit and merge with your collaborators, the more in lock-step you are and the less likely you are to run into these kinds of issues. Messy merges will happen from time to time regardless of your preferred language.

> Do you go and check the commit's release notes every time you pull?

Not always, but often. Maintaining visibility of the trajectory of the code and the project as a whole will help massively in heading off risks and development issues.


> Except it clearly is possible since I and millions of other developers seem to manage it daily.

Clearly possible to fix code that's in branches/working trees that you don't even have access to??

> This is a problem of your code-base, not the language. If your code is so brittle that it can't stand a few function changes without collapsing into a miasma of shit

When you change function signatures, code that calls those functions is broken. In static languages the breakage is a compile-time error. In dynamic languages the breakage is a run-time error. In JS the breakage is a cryptic bug.

> Of course it's potential. Nobody's forcing you to write tightly coupled, shitty code which breaks after every merge. Seriously? Figure it out.

The code is tightly-coupled and shitty because it has functions that get called?

> Like I said before, squishiness.

By squishiness, do you mean "trade errors for cryptic bugs"? You seem to be exactly who Dijkstra referred to when he said [1]:

> It was a significant improvement that now many a silly mistake did result in an error message instead of in an erroneous answer. (And even this improvement wasn't universally appreciated: some people found error messages they couldn't ignore more annoying than wrong results, and, when judging the relative merits of programming languages, some still seem to equate "the ease of programming" with the ease of making undetected mistakes.)

> As do I, and clearly millions of other developers who don't seem to run into your problems.

I'm wise enough to avoid JS, so I don't encounter such silly problems. I don't trust you to even know you are having these troubles, because the whole point is that these problems translate to cryptic bugs, rather than visible errors.

> We have proper commit messages and tracking codes for every task / bug, yes. There's no such thing as perfect information - and sometimes merges get messy - but this is not unique to JS

Note that the word "merges" may be misleading here. As every little pull you do (even a FF pull in git which updates files that don't overlap with your modified files) is a merge for this purpose.

Your approach here means that I must review all the function signature changes in every commit I pull, synchronously, before I carry on work. This doesn't help lock-step development as it incurs a serious overhead on such development.

> Not always, but often

That means when you pull, all the function calls to functions that may have had their signatures changed in your pulls may now become cryptic bugs. Awesome!

[1] https://www.cs.utexas.edu/users/EWD/transcriptions/EWD06xx/E...


> Clearly possible to fix code that's in branches/working trees that you don't even have access to??

This is a non-issue - if you're using unstable libraries then that's your own problem and breakages are to be expected. This is not the fault of JS.

> When you change function signatures, code that calls those functions is broken. In static languages the breakage is a compile-time error. In dynamic languages the breakage is a run-time error. In JS the breakage is a cryptic bug.

When you change function signatures, you document the change and you increment the version. If you're randomly updating dependencies without first checking that the new version is compatible with your existing code, then that's your problem. Again, this is not JS.

> The code is tightly-coupled and shitty because it has functions that get called?

If a change in a dependency causes you to have a ripple effect of completely broken code - then yes, your code is tightly coupled.

> By squishiness, do you mean "trade errors for cryptic bugs"? You seem to be exactly who Dijkstra referred to when he said [1]:

Squishiness is difficult to explain without describing the general ins and outs of dynamic languages, which I'm sure you're not completely alien to. Essentially, what I'm saying is that the problems you're experiencing with JS are largely your own fault - and no amount of complaining is going to solve the problem of the user lacking due diligence when they rely on unstable code or aren't maintaining their own dependent code properly. Again, these problems are not specific to JS.

> I'm wise enough to avoid JS, so I don't encounter such silly problems.

So you're weighing in on the problems of a language you don't even use. Doesn't that strike you as somewhat...silly?

> I don't trust you to even know you are having these troubles, because the whole point is that these problems translate to cryptic bugs, rather than visible errors.

They translate to cryptic bugs if you develop shitty software, sure. However, if you do your homework, correctly check your dependencies and retain some semblance of stability in your code-base, then no, these problems aren't nearly as dramatic as you're suggesting.

> Note that the word "merges" may be misleading here. As every little pull you do (even a FF pull in git which updates files that don't overlap with your modified files) is a merge for this purpose.

A merge is a merge is a merge. If you're merging unstable code, then you have to expect that you're going to need to do some maintenance. In what world is it sensible to develop software where you're not even attempting to ensure that potentially breaking changes aren't flagged up, discussed, and dealt with? Have you never heard of the phrase 'don't break the build'? In my job, if somebody commits and pushes something which is going to completely fuck the rest of the development team, then they're told to piss off and fix it. If you absolutely must change a function signature which is part of an API that others may be depending on, then you fucking document it and alert your users. Again, not JS. Sort your process out.

> Your approach here means that I must review all the function signature changes in every commit I pull, synchronously, before I carry on work. This doesn't help lock-step development as it incurs a serious overhead on such development.

No, my approach is that if I'm developing a library which others depend on, I don't fuck about with the API without a very, very good reason - and if I do, then I document it. Don't randomly update your dependencies if this is such a problem for you. If your code is so tightly coupled to whatever dependencies you have that updating that dependency means you need to change a thousand different lines of code scattered throughout your software, then you're already doing it wrong.

> That means when you pull, all the function calls to functions that may have had their signatures changed in your pulls may now become cryptic bugs. Awesome!

Except it doesn't, because who updates a dependency without checking that they can actually depend on it? The clue's in the name.


It seems you are misunderstanding me. I am not talking about library APIs here. I am talking about internal function signatures inside a single product developed by multiple codevelopers.

All your replies about external APIs changing are irrelevant. A codeveloper touching functions that call your functions or defining functions called by you will integrate with your work with an innocuous "git pull" and force you to review everything just to rule out what JS could have easily detected.

> If a change in a dependency causes you to have a ripple effect of completely broken code - then yes, your code is tightly coupled.

Again, I'm not talking about "dependencies" or libraries here at all.

> In my job, if somebody commits and pushes something which is going to completely fuck the rest of the development team, then they're told to piss off and fix it.

The push was completely benign. The integration of that push with your current work will be broken in cryptic ways. Not necessarily ones that show up in the testing suites.

> If you absolutely must change a function signature which is part of an API that others may be depending on, then you fucking document it and alert your users. Again, not JS. Sort your process out.

Every single function signature can break things, not just exposed APIs. Two developers might work on the same piece of code. There's not necessarily any obvious point to notify here and still breakage may arise.

> Except it doesn't, because who updates a dependency without checking that they can actually depend on it? The clue's in the name.

You clearly haven't understood the scenario involved, I'll try to describe it again:

1) Developer A adds a new function FOO that calls internal function BAR in his unpushed working tree.

2) Developer B changes the signature of internal function BAR, and pushes this change to "master".

3) Developer A pulls from master, his code is now broken, but JS doesn't even warn him when he executes it. Instead, wrong results (or accidentally correct results for any given test case) arise.

4) The test suites don't catch the error. Developer A unwittingly pushes the broken code to master.


> All your replies about external APIs changing are irrelevant. A codeveloper touching functions that call your functions or defining functions called by you will integrate with your work with an innocuous "git pull" and force you to review everything just to rule out what JS could have easily detected.

Everything that you didn't write yourself is an external API for all intents and purposes - you're using somebody else's code, regardless of whether that person 'owns' the code or not. The fact remains that if you're relying on a function and somebody changes it without considering the consequences, then that's a process issue, not a JS one. In the same way, if you're writing code which others may depend on, then you need to consider the potential consequences of your changes.

> Again, I'm not talking about "dependencies" or libraries here at all.

The point is that you should be talking about dependencies and libraries. The situation you're describing is one in which code is not properly modularised and organised - where any developer can change any function and thereby fuck up the rest of the project. If your code was organised properly, these problems would disappear.

> The push was completely benign. The integration of that push with your current work will be broken in cryptic ways. Not necessarily ones that show up in the testing suites.

You keep using the word 'will'. I'm telling you with hand on heart that this problem does not happen if you sort out your development team and project structure.

> Every single function signature can break things, not just exposed APIs.

Yes, it can break things, but it shouldn't.

> Two developers might work on the same piece of code. There's not necessarily any obvious point to notify here and still breakage may arise.

If two developers can't work on the same area of code without stepping all over each other, then you need to look at how you're structuring your code.

> 1) Developer A adds a new function FOO that calls internal function BAR in his unpushed working tree. > 2) Developer B changes the signature of internal function BAR, and pushes this change to "master". > 3) Developer A pulls from master, his code is now broken, but JS doesn't even warn him when he executes it. Instead, wrong results (or accidentally correct results for any given test case) arise. > 4) The test suites don't catch the error. Developer A unwittingly pushes the broken code to master.

Why is developer B changing the signature of function BAR willy nilly? Code isn't written in isolation and your changes have an effect on other developers. If you have a function which is being used by other people - then you have a public API. You don't break an API randomly.


So basically you need to use strict ownership at API boundaries as that is the only way to avoid this. This isn't always optimal. It sounds like you're sacrificing quite a few goats at the js altar for no real benefit.

Your question about why a developer would need to change an internal function's signature is ridiculous. Maintaining code involves changing function signatures all the time. If another developer is working within the same API boundary, he's screwed.

This isn't a necessary fact of life. Even most sane dynamic language will error out when such incompatibility arises, instead of blaming the developer for using a process incompatible with the js way.

Not to mention the other argument, that with all the discipline in the world, humans will still make mistakes. Instead of translating to errors, they translate to bugs.

The gain? not having to use an asterisk when you want varargs. That's just stupid.


> So basically you need to use strict ownership at API boundaries as that is the only way to avoid this. This isn't always optimal. It sounds like you're sacrificing quite a few goats at the js altar for no real benefit.

No, but when somebody I'm working with makes a potentially breaking change to a shared codebase, they either ensure that they also fix the now broken code, or they flag it up to the people whose responsibility that is. Aside from that - most people simply avoid making a breaking change - or if it absolutely must be made, then a process is followed.

> Your question about why a developer would need to change an internal function's signature is ridiculous

I wasn't asking why the developer was changing a function signature - rather why they're so eager to change a function signature without following up and either fixing the things they break, or flagging those things up to the people who require it.

> This isn't a necessary fact of life. Even most sane dynamic language will error out when such incompatibility arises, instead of blaming the developer for using a process incompatible with the js way.

There's no such thing as a random error. If there's an error, somebody made a mistake. Some mistakes are stupid, others are subtle. Changing a method signature and then not doing something about the callers is a stupid mistake.

> Not to mention the other argument, that with all the discipline in the world, humans will still make mistakes. Instead of translating to errors, they translate to bugs.

Of course humans will make errors - but your job is to minimise the frequency and severity of those errors. There's no excuse for sloppiness - you either keep on top of shit, or you don't. Call it whatever you like, but a shitty broken codebase is only the fault of the developers, not the language.


> Aside from that - most people simply avoid making a breaking change - or if it absolutely must be made, then a process is followed.

Changing internal functions is not considered a "breaking change" by anyone I know. You're allowed to refactor code internally, which definitely includes changing the structure of the internal functions.

Other coders who are also working inside the same module/API boundary will have their edits broken by this change. The original developer cannot fix their code because it's not checked in yet.

> rather why they're so eager to change a function signature without following up and either fixing the things they break, or flagging those things up to the people who require it.

I already explained why they can't follow up - because the code that needs the follow up is in their codevelopers' working trees. Flagging here would be silly. Almost every single commit would be "flagged for fixing breakage", since every single commit can refactor/change internal function signatures.

> If there's an error, somebody made a mistake. Some mistakes are stupid, others are subtle. Changing a method signature and then not doing something about the callers is a stupid mistake.

Yes, and we are all human so sometimes, despite heroic efforts, we will all make stupid mistakes as well as subtle mistakes.

Now, once we made the mistake, do we want our tool to insidiously hide this mistake from us, making it as expensive as possible to punish us for our mistake? Or do we want a tool that tells me ASAP "Hey dude, you made a stupid mistake over there"?

> but your job is to minimise the frequency and severity of those errors.

And to do this job, I have tools like languages that help me find those mistakes quickly.

> There's no excuse for sloppiness

Making mistakes isn't "sloppiness", it's human.

> Call it whatever you like, but a shitty broken codebase is only the fault of the developers, not the language

If one language makes writing a non-shitty codebase harder than a different language, it is also the fault of that language.


> Changing internal functions is not considered a "breaking change" by anyone I know.

If changing internal functions results in breakages, then I don't know what else you'd call it except a breaking change.

> You're allowed to refactor code internally, which definitely includes changing the structure of the internal functions.

If the person changing the function doesn't then go and update all of the callers, then that person isn't doing their job properly. It's not refactoring if you just randomly decide to modify a single function's signature and then don't follow up and fix the rest of the code.

> Other coders who are also working inside the same module/API boundary will have their edits broken by this change. The original developer cannot fix their code because it's not checked in yet.

Not if you're making small commits, often. Changing a function signature necessitates the modification of all callers to that function. This would be a large commit which includes all of necessary changes to ensure that the software remains in a stable state.

> I already explained why they can't follow up - because the code that needs the follow up is in their codevelopers' working trees. Flagging here would be silly. Almost every single commit would be "flagged for fixing breakage", since every single commit can refactor/change internal function signatures.

This is still just a process problem - if you committed and merged more often, these issues wouldn't arise. The reason you're having these issues is because you're allowing your working trees to become too out of sync. If everybody is working on the same module, then those developers should be trying to retain lock-step. Even if developer A (the breaker) doesn't have access to the code of developer B and therefore can't update his function calls - committing smaller changesets and merging more often, where the overhead in assessing changes is tiny, will wipe out 99% of these issues. If you can't see the forest for the trees, then issues are going to slip through.

> Yes, and we are all human so sometimes, despite heroic efforts, we will all make stupid mistakes as well as subtle mistakes. Now, once we made the mistake, do we want our tool to insidiously hide this mistake from us, making it as expensive as possible to punish us for our mistake? Or do we want a tool that tells me ASAP "Hey dude, you made a stupid mistake over there"?

Except in JS, the code itself isn't a mistake. It's your problem - JS has nothing to do with ensuring that you keep your codebase bug-free.

> And to do this job, I have tools like languages that help me find those mistakes quickly.

Then use them, and stop complaining about something that you don't even use.

> Making mistakes isn't "sloppiness", it's human.

Making the same mistake repeatedly and then blaming your tools is sloppiness however you dress it up.

> If one language makes writing a non-shitty codebase harder than a different language, it is also the fault of that language.

It's not harder, it's just different. If you learn the language and its subtleties, then you won't have these problems.


> If changing internal functions results in breakages, then I don't know what else you'd call it except a breaking change.

It's not the change itself that broke things. It's the combination of two changes that you got when you used "git pull".

> Not if you're making small commits, often. Changing a function signature necessitates the modification of all callers to that function. This would be a large commit which includes all of necessary changes to ensure that the software remains in a stable state.

Small commits make this less likely -- but it can still happen.

> This is still just a process problem - if you committed and merged more often, these issues wouldn't arise. The reason you're having these issues

I'm not having these issues because I am wise enough to avoid JS.

> because you're allowing your working trees to become too out of sync

CI is great, but for some major changes, incremental changes are not always a possibility. Sometimes you have to break things temporarily in order to change the way things work in a significant way. This is typically done in a side-branch. Integrating that side branch with all the changes will require going over all functions that changed manually, to see if the signatures now mismatch their callers (solving the halting problem, in the general case), because even UT can easily miss it.

> committing smaller changesets and merging more often, where the overhead in assessing changes is tiny, will wipe out 99% of these issues

What do you propose to do about the 1% of issues that still plague the codebase?

> Except in JS, the code itself isn't a mistake. It's your problem - JS has nothing to do with ensuring that you keep your codebase bug-free.

The code itself is a mistake. You meant to call something with (x,y,z), instead you called it with (x,y/z). Now the language will do its best to hide this problem from you, so you can discover it as late as possible, when it is most expensive.

> Then use them, and stop complaining about something that you don't even use.

The thing is, I was hoping to get the perspective of someone who does use this language, to see that point of view, but the point of view seems to be "languages should not help you write good programs or find your errors", "just don't make bugs", and "change your process to accomodate JS to reduce this risk that should not exist in the first place".

> Making the same mistake repeatedly and then blaming your tools is sloppiness however you dress it up.

Who says it's the "same mistake repeatedly"? There are many different mistakes that could be made non-repeatedly by many different developers that would get caught if function signatures were verified sanely but instead hidden by JS.

> It's not harder, it's just different. If you learn the language and its subtleties, then you won't have these problems.

So you just "learn" to never make mistakes. I get it.


This. People complaining about what JavaScript lets you do just need to learn how to exploit its strengths while being aware of its dangers.

It's like someone complaining that git let them make a mess after they merged master into their feature branch and then merge it back into master.


No, it's much more like git ignoring wrong command syntax and just using undefined instead.

  git commit - m"Hi" && git push
Let's push a commit with an undefined message, and ignore the m"Hi" argument. Error messages are annoying.


Silencing an error like that is catastrophic.

Silencing an error would be a problem, but in JS, it's not an error, because there's no concept of "wrong numbers of function arguments" built into the language. That's not to say you can't inspect the number of arguments yourself and throw an error, if some situation warrants it. But you don't have to do this. It's a very flexible, dynamic language. In some ways this flexibility makes things easier and more expressive, in other ways it necessitates more manual checking (or slower debugging). There's no catastrophe, just design differences.


> ... in other ways it necessitates more manual checking (or slower debugging). There's no catastrophe, just design differences.

See, there's the problem. Glossing over issues by explaining them away as "design differences". Nothing about an expressive language necessitates making life hard for the programmer. If your function call doesn't match the signature then it is very likely to be in error, and instead of failing silently the language should make such mistakes easy to spot. I like how most other dynamic languages require you to be more explicit about function parameters (with the exception of PHP).


> If your function call doesn't match the signature

Depending on what constitutes function signature. I agree with “design difference” argument. Someone has to make design decisions, even if someone else doesn't agree with them.


The problem is the design here is to trade errors that could be detected with cryptic bugs that can slip through. Or alternatively, adding insane per-function overhead/testing to manually cover signature checking.


It's still a programmer error when they accidentally call a function with 2 arguments when they meant to call it with 3. The fact that the language can't inform them of the error doesn't change that.


So do some error checks. The first unit test I write for any function is that it handles arguments correctly.


That's great if it's your function that's the problem. Less so if it's someone else's.

And it's not only these kinds of errors that can cause silent failure. I've had it on missing brackets, on missing commas, on failure to include/require the right source file etc, etc. No error message, no warning, no log entry, no nothing. Just silence. And a blank output. Not overly helpful.


So in every single function, I have to either:

A) Silently ignore errors in param counts, get cryptic bugs later when a trivial merge changes a function signature, or when changing a function signature.

B) Add explicit code to check the parameter counts at a huge cost (a per-function overhead!) along with extra tests for this silly thing for each and every function. This overhead is insane!

I have to choose between cryptic bugs and insane overhead, all for what? So you can use "args" and not "*args"?

This is a catastrophic choice for the language.


But you do see why people are complaining, right? You are having to manually write thousands of tests to check something that is trivial for a compiler to check.


This is just an absurd complaint, it's a dynamic language, if you want compiler forced type checking, use a static language. Dynamic languages are not broken because they don't behave like static languages.


You're missing the point.

A static language catches the error at compile-time.

A dynamic language catches the error at run-time.

Javascript hides the error and gives a cryptic bug, instead.


I'm not missing the point, and I don't agree that it hides an error and gives a cryptic bug. Messing with a function signature and not updating callers of that function is not a bug in the language, it's a bug in the programmer and will result in runtime bugs in any dynamic language. If you require X number of args, then assert that they aren't undefined. If you presume callers pass in X number of args in a variable args language, and then change the required args, you're the bug, not the language.


> I'm not missing the point, and I don't agree that it hides an error and gives a cryptic bug.

It hides the error by carrying on, despite having the wrong number of arguments, and executing code with thus necessarily wrong inputs.

> Messing with a function signature and not updating callers of that function is not a bug in the language, it's a bug in the programmer

When editing code, you routinely change the function signatures of hundreds of functions. Of course you're going to miss some, some of the time. Human errors happen, and good languages help us deal with them.

Also, every time you pull code from another repository, function signatures all over the place change. Some of those may be functions your currently edited code is calling. This means every little divergence requires reviewing every single signature change or cryptic bugs will result.

> and will result in runtime bugs in any dynamic language.

It will result in runtime errors in dynamic languages. Errors that are visible, and difficult to ignore. That means the code gets fixed. UT triggers it trivially.

Whereas with Javascript, even code under UT can easily pass accidentally when wrong numbers of arguments are used.

This Dijkstra quote is relevant:

> It was a significant improvement that now many a silly mistake did result in an error message instead of in an erroneous answer. (And even this improvement wasn't universally appreciated: some people found error messages they couldn't ignore more annoying than wrong results, and, when judging the relative merits of programming languages, some still seem to equate "the ease of programming" with the ease of making undetected mistakes.)

> If you require X number of args, then assert that they aren't undefined

That captures half of the bugs (too few arguments), for a large overhead (an extra line for almost every argument in every function).

> If you presume callers pass in X number of args in a variable args language, and then change the required args, you're the bug, not the language

Every time you change code, there is potential to insert bugs. Of course all bugs originate from programmer errors. The tools can work with us to find these errors and mitigate them, or they can give us hell.


> That captures half of the bugs (too few arguments), for a large overhead (an extra line for almost every argument in every function).

You don't have to check every every arg to check the count is correct if that's something you're concerned about. Nor does checking args are undefined require a line per since you could check them all with a single assert.

If you're the type who has constant bugs from wrong arg counts, use another language that better suits your programming style, but it's not a problem everyone has.

And Dijkstra despised OO, and came from a much different time, I don't much care for many of his opinions. Alan Kay is more my style.


> You don't have to check every every arg to check the count is correct if that's something you're concerned about. Nor does checking args are undefined require a line per since you could check them all with a single assert.

That's true, but the overhead is still relatively huge.

> If you're the type who has constant bugs from wrong arg counts, use another language that better suits your programming style, but it's not a problem everyone has

I'm the type of programmer who tries to avoid errors as much as I can, but still make them as I am human, as we all are.

One of the possible errors that's really easy to make is forgetting to grep for callers of a function you just changed. Of course 99 out of 100 times you remember, but 1 out of 100 you will forget.

Another possible error is remembering to change the function signature, but just having a typo or mistake.

And finally, even if you make no errors at all -- when you pull from the server you get a bunch of function signatures and calls changed "under you feet", so any changes you had already pending (perhaps in different files) are now potentially silently invalidated, and there won't even be a runtime error to tell you about them.

There is really no real benefit to this behavior at all (beyond backwards compatibility of course). Explicit rest-of-args cost nothing.

Error messages are superior to wrong behavior, and this behavior is simply insane.


In JS, sending the "wrong" number of arguments is frequently a feature. There's no concept of language-level function overloading, and it allows for the authorship of functions that take a variable or unbounded number of arguments (useful when coding in a functional paradigm).


That "feature" would be better with an explicit language construct such as *args or params args[], though. As with so many complaints about JavaScript, it's the default behaviour that is a problem.


I'd say it's worse than a default behavior, since there's no sane way to reverse the default. Are explicit arg list checks really an option, when you want to opt out of the default? I'd say that's not practical at all -- so it's really worse, as there's no practical opt out of this.


ES6 brings "rest parameter" [0].

function(param1, param2, ...rest) {}

[0] http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html


I think the way libraries like jQuery use this behaviour to define their own undefined that is indeed undefined is rather neat, the whole of jQuery is wrapped in:

   (function(window, undefined) {...})(window);


I'm so tired of hearing how bad JS is as a language - guess what, it doesn't metter. The ecosystem and community is absolutely amazing and that's something you just can't beat - all the well documented, polished and maintaned libraries, frameworks etc, the amount of books, guides, conferences and so on, the ability to use JS everywhere, tools, services, cloud based solutions and much, much more. That's why people create all the amazing stuff and all of this results in one of the most important things - development speed. Sure, JS has a lot of quirks you need to be aware of and it's easy to write bad JS, but with some experience, you can rapidly write a maintainable, easy to read, flexible and modular code.


Yeah, same here. I have no difficulty writing large scale apps in JS because I play to its strengths and manage its weaknesses. These shit-for-brains "experts" can't, and somehow it's all the language's fault.

Here's a clue folks: you're the programmer, it's your job to work out how to programme for your target platform, and if you can't then fuck off and leave it to the professionals.


"it's your job to work out how to programme for your target platform" - exactly, but there is an active effort to try and put the JS garbage on each and every target platform!


> a function is not an object, not a datastructure that can carry data

Wait, what? That's the definition of a closure.

Most of this seems to boil down to the author saying "my programming brain was hardwired by Ruby, and I'm annoyed JavaScript is different." OK, I feel your frustration. As a reader, though, I'd far rather see a post from someone who has spent the time to become proficient in both ecosystems and can offer more considered pro/cons.

On one point, I'll agree: I wish Javascript had an easy way to say "referencing an undefined property of this object should throw an error."


I have always wondered why so many people like dynamically types languages... I mean, if I have a variable I ALWAYS know what kind of data I expect in it. If I try to use different kinds of data in the same variable then something is clearly wrong - either with me (for wanting that) or with the way I use the variable (and I would appreciate some warning about it).

The problem is that you hardly have a choice nowadays. Python, JS and PHP are dynamic, Java is a great language but crappy concept (don't tell me it isn't slooo... <wait for GC... ok, done> ...ow). Ironically, the ugliest language I have ever coded in (ObjectiveC) has the best design decisions (IMHO). ARC instead of manual memory management or GC, strongly typed but still allows generic object pointer (id),...


> ObjectiveC) has the best design decisions (IMHO). ARC instead of manual memory management or GC, strongly typed but still allows generic object pointer (id),...

It's funny, because objects in Objective-C are dynamically and weakly typed, and as flexible as in JS. The syntax has unnecessary rigidity that doesn't map well to actual semantics of the language.

Message passing in ObjC doesn't care about types (you can send any message to any object, and the receiver can capture the message and do whatever it wants). You can change/add methods (and "associated" properties) at run time, of instances and class definitions, just like in JS.

e.g. Cocoa bindings will subclass your objects (create a new subclass at run time and swap identity of your object) to replace setters with ones that notify the UI.

https://developer.apple.com/library/ios/documentation/cocoa/...


I have always wondered why so many people like dynamically types languages

Because you don't have to write a lot of boilerplate to tell the language things that it should be able to figure out for itself.

I mean, if I have a variable I ALWAYS know what kind of data I expect in it.

But that data might not always be of the same type. For example, in Python, I might want a variable to hold strings but also None, so that I can differentiate between, say, "the user explicitly entered an empty string" and "the user hasn't entered any string at all yet".

Yes, there are ways to do this in statically typed languages (for example, Haskell's Maybe), but it's still extra code that I have to write.


> Because you don't have to write a lot of boilerplate to tell the language things that it should be able to figure out for itself.

This is exactly my point; compiler can't figure out what kind of data I want, at least not in general. A good example is jQuery $.data() which tries to guess what kind of data you have in your HTML tag attribute. Guess what happens if you have a MongoDB ObjectId (as string), for instance "52259986890d6f24e9000000"? Exactly - it is a floating number. Believe me, it leads to some interesting debugging sessions... :)

I agree with you however that it is beneficial to have a way to set the var to None/null/..., indicating "not initialized". Win some, lose some I guess.


Guess what happens if you have a MongoDB ObjectId (as string)

But that's a matter of semantics, not static typing. You're going to have to do type conversion on the string regardless, because "MongoDB Objectid" isn't a native type for the compiler. But with static typing, you need to tell the compiler the type of the variable in addition to telling it how to do the type conversion: for example, in C++, you might have to say...

    var MongoObjectid id = new MongoObjectid("somestring");
..whereas in Python, for example, you could just say...

    id = MongoObjectid("somestring")


> You're going to have to do type conversion on the string regardless, because "MongoDB Objectid" isn't a native type for the compiler

My point was that jQuery .data() tries to guess how to handle strings and misses in some cases, because the strings are too similar to numbers. The fact that this particular string was a MongoID is actually not relevant to the problem, it just illustrates that this is a real-world problem.


Actually in C++11 you can just say:

    auto id = mongo::OID("1234...");
This gives you much (not all) of the brevity and flexibility of dynamic typing, while maintaining the power and safety of static typing.


The reason alot of people like dynamicly typed languages is that they don't have to babysit the compiler. Small example, in JS, if you have a function that works on a "age" property of an object, it doesn't matter what kind of object you send in, as long as it has an "age" property. You can do this easily in staticly typed languages as well, but you have to write more code (generics, class/struct-definitions, interfaces ...).

> I mean, if I have a variable I ALWAYS know what kind of data I expect in it

Really? Why did people invent generics/templates, interfaces and class-inheritance then? You won't always know what type you are receiving, and alot of the time you don't really care either, as long as it meets your criteria.

> The problem is that you hardly have a choice nowadays

Course you do: C/C++, Haskell, OCaml, Go, Nimrod... Soon you'll have Rust to play with as well.

> <wait for GC... ok, done>

Depends on your usecase. As long as your active memory use don't number in multiple GBs, GC is quite fast. I have an application spawning 1GB of garbage a second, this takes 5ms (a second) to collect. Not bad IMHO. The work they are doing on the new G1 collector also seems promising. Btw, GC can in many cases have lower overhead than ARC (Python also does ARC btw).

> strongly typed but still allows generic object pointer (id)

Last I checked, most of Obj-C prefers dynamic typing. NSArray and NSDictionary for instance, can contain any type. Regarding (id), most languages allows this. "Object" in Java/C#, void* in C/C++, interace{} in Go etc.

In the end, it doesn't really matter what language you use, as long as it gets the job done. If your language isn't available, you're mostly able to use another language anyway. Almost every language nowadays has a JS-compiler. There exists a Java Bytecode -> Native code compiler, same with C#.


> "Small example, in JS, if you have a function that works on a "age" property of an object, it doesn't matter what kind of object you send in, as long as it has an "age" property."

Shouldn't you just pass the 'age' property then?


Depends what operation you are performing. increaseAge function would probably require the object to actually increase the age, not just return an increased age value.

This is a poor example, i know, but the point is that while both is simple operations in both static and dynamically typed languages, dynamically typed languages allow you to do this without writing an interface, generic function, abstract base class or whatever and restricting the function to that particular use case.

The tradeoff is flexibility vs safety. I personally prefer dynamically typed languages as I've found that with a combination of discipline and unit-tests (which, IMHO, you should have anyway) I never really miss the static type-checker. But I understand those people who prefer static typing very well.


It's good to have dynamic typing as an optional feature in a language (e.g. how it is implemented in C#). It could be useful for some very specific scenarios - typically around integration of different systems. But I agree that it doesn't make much sense to use them all the time. I think people mean that they like decent type inference when they say they like dynamic languages. C# makes a distinction between 'var' and 'dynamic' to make it more clear.


^THIS TIMES A MILLION! Static typing, with good type inference, is awesome. Old-school C static typing, is not.


It's interesting to see so many people say "JS is great and we used it to build X" on one side and people who hate JS on the other side.

Obviously Node (and JS) has some things that it is strong in. People use it to build those things. Good developers won't use a tool in their box which is inferior to another tool they can use effectively. In between, there is a lot of room for "good enough" where tools overlap.

I think some developers are able to largely stick with a certain tool because development goes in waves. I can spend multiple months on a certain profile of work and then get hit with the same type of project a couple more times. Maybe by then I become an expert with that thing and I just keep doing those sorts of projects. You might think I'm crazy because I'm a "Node developer" but you probably don't know the nature of the work that I do.

Eventually I get hit with a different project and everything falls apart if I try to keep using the same tools as I had been using. So, I curse myself for being stupid and wasting time and start over with the tool I should have been using in the first place.

Some developers might have such a limited set of tools that they can't (or won't even try) to switch.

"So, I landed a big gig for the government. It's a healthcare site. I'm going to build it in Wordpress."

Following this thread further, look at some of the selling points of Node.

* It's great because as a front-end developer, you probably already know JS. With Node you can use JS on the back-end also!

* Because the front-end and the back-end are both in JS, I can use one programming language and re-use libraries for each side.

Great, let's encourage people who only know one programming language and a limited range of tools to just stay in that box.

There are things that X tool does well. There are things that X tool is horrible at. Perhaps rather than ragging on Node, the author should write an article explaining that developers should be expanding their tool-set so they have flexibility in handling different types of problems.


>Obviously Node (and JS) has some things that it is strong in. People use it to build those things. Good developers won't use a tool in their box which is inferior to another tool they can use effectively. In between, there is a lot of room for "good enough" where tools overlap.

People use JavaScript not because it's good but because it's the only option to develop in a browser. Having the same language on the client and the server is a very strong point, that's why they use NodeJS.


> Having the same language on the client and the server is a very strong point

Only if you're so incredibly strapped for cash that you can't hire real devs that can pick up another language in a day or two.

Almost every language used commonly on the serverside is vastly preferable to js.

This whole "well, it's THE SAME" benefit simply isn't. It's a red herring.

I'm convinced the whole ecosystem has sprung up because of hordes of terrible copy-paste browserside devs that don't actually fully understand what they're doing in js, who resultantly would be incapable of building anything serverside in another language at all because their overall comprehension of programming is marginal at best.

Anyone not stupid or insane just learns ruby or python or scala or go or even php or .NET.

PS: cue replies from all dozen people on the whole internet who know pointer math and still like coding webapps in js, who don't realize that I'm not talking about the 12 of them but the 12,000 who are doing the js/node problems on codeacademy this instant.


>Only if you're so incredibly strapped for cash that you can't hire real devs that can pick up another language in a day or two.

If your application is more complex on the client than on the server, that's the way to go.

I personally, prefer GWT here. Java on the client and the server is much better than JavaScript on its place.


> Anyone not stupid or insane just learns ruby or python or scala or go or even php or .NET.

I started with PHP and C#/VB.NET, before learning JS. I know Python, Scheme, Java, I've played a bit with Clojure and Ruby[0]. After all that, JavaScript (admittedly, usually through CoffeeScript) is my favorite language. It provides everything you need to build almost anything you want, wrt tooling.

I understand and agree that it has warts, as does every language. But to call its use "stupid or insane" is ridiculous.

[0] I have yet to understand the concept of blocks, as they seem to be just a half-assed implementation of first-class anonymous functions. If someone can show how they improve on them, that would be much appreciated.


....aaaaand scene. Cut!


I have literally no idea what you meant by this.


You didn't miss your cue, and delivered your lines perfectly. We're done for the day, we're not bringing in Eevee[1] and Dziuba[2] to shoot the "every language has warts hahaha what are you, a noob?" scene until tomorrow.

You did great, thanks again. Don't call us, we'll call you.

[1] http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-de...

[2] http://pages.citebite.com/b2x0j8q1megb


It depends on what you are building. Server side can cover so much ground these days. It could be the Ghost blogging app which was recently released or we could be talking about the muscle behind Google.

Node covers a lot of "good enough" space for what a lot of people are doing. The people who complain the loudest about Node are likely those who are working on things which aren't covered by that "good enough" circle.

I wish people would use real life project examples or include the sorts of work they do when they makes these kinds of arguments. It would help us see where this person is coming from.


The majority of people writing Node code don't know what that "good enough" space covers. Or they get so excited hitting something with that hammer that they stop looking in the toolbox.

Node is fantastic for rapid prototype development, or tiny little startups that need to do the absolute minimum amount of work so they can finish before running out of money.

Everything goes sideways when these cute little Node apps get pushed out to real production use (if you measure things in anything other than dollars per second, you don't get to chime in here and redefine production). Then the heavy hitters have to come in and patch Node itself, or rewrite it in another language.

I've gone in to a growing startup over a weekend and saved them $1000/mo in AWS instances by rewriting a Node app in 30 lines of Go.

I hate to cite examples of real world projects in threads like this, because it just devolves into "OMG YOU NOOB THAT WAS FIXED IN THE BASHFUL BADGER RELEASE" when said fix was the result of a bug you opened or a patch you submitted.


>It depends on what you are building. Server side can cover so much ground these days. It could be the Ghost blogging app which was recently released or we could be talking about the muscle behind Google.

Consider for example a rich text editor, or diagram editor with a complicated automatic layout. Doing such things in JS is extremely painful.


It's not the only option in the browser.


What are other runtime options?

- Flash? That's almost the same as JavaScript and it's getting obsolete.

- Java? No one enables it on the client, thanks to security problems.

- Asm.js/LLVM? These are immature and can't be used for production.


- GWT - Dart - ClojureScript


Every single one of these compile to the JavaScript runtime.

(Dart has a native VM in Chromium, but AFAIK it is a long way off from the real world)


Right and ClojureScript, for example, has full goroutines in it (i.e. core.async) if doing standard callback based async in JS isn't your thing.

Functionally, it makes little to no difference whether you're writing something that compiles down to JS or writing something that compiles down to its own runtime (assuming you turn source maps on your browser).


>Functionally, it makes little to no difference whether you're writing something that compiles down to JS or writing something that compiles down to its own runtime (assuming you turn source maps on your browser).

It actually makes a big difference. You can't use profiles, debugger, libraries, and other stuff which is platform specific but have to use JavaScript ones. Often, they don't play well with with languages which generate to JS.


That doesn't change the fact they use the JavaScript runtime, which was the question the parent was trying to address.


> They are not solvable by making a new ECMA spec.

As it turns out, many of the issues outlined are not only very much solvable by making a new ECMA spec but either already solved in ES5 or solved in ES6.

> JS has callable attributes

> This is a shitty design decision

I strongly recommend not following the provided link, which is basically inane, uses the term "slots" in a rather disturbing manner and makes completely incorrect assertions e.g.

> Self [is] slot-based. This gives one substantial advantage: not having to specify that you want to move a block of code as a value explicitly. So you can do, for example in JS

      // boom! we transplanted a method
      someVar.smartMethod = another.otherMethod;
to my knowledge, you most definitely can not do that in such a manner in Self. Slots manipulation in Self can only be done through primitive messages (e.g. `_AddSlots:`, which takes an object whose slots should be copied into the receiver).

> Hobjects are unusable for stable keys

> The mixup between objects and hashes is also a very bad idea, because it defies the premise that objects can have metadata on them - which alllow you to establish a rudimentary type system or at least any kind of introspection.

Magnificent baseless assertions. Javascript allows for object metadata through the prototype, or through properties (Object.defineProperty/Object.defineProperties) which — amongst others — allow setting non-enumerable properties. ES6 also introduces the concept of names. I'm not saying maps-as-objects is great, but I am saying these assertions are 1. wrong and 2. nonsensical.

> Fobjects are unusable for type systems since an object does not carry any type information.

> This one is a biggie. Even in the Ruby world, where everything is happily quacking like a duck, we often use the Object#class to get information about an object.

In ES5, the exact same behavior is provided by Object.getPrototypeOf providing access to the internal [[Prototype]]. Most implementations also provide direct access via the __proto__ property, which IIRC ES6 standardizes. And of course the `instanceof` operator has been there since ES3, but that's only ~13 years ago.

> Nothing will happen. Since ojects are hashes[...], our constant with the wrong key will be undefined, and will happily bleed into the callee. This makes stack traces huge.

'Nothing will happen' (and the related "What is the error that you will get if MyApp.Views.WidgetView is not defined yet? undefined is not a function of course! [...] And why? Simply because everything is a hash and the language is incapable of doing any kind of introspection." later) and 'objects are hashes' have nothing to do with one another. Hashmaps does not actually require unmapped keys to return nil or undefined. Javascript does because it is shit. Same for Ruby or Java. Python does not have that issue, accessing an empty key will raise a KeyError.

> and the language provides zero facilities for constants

All runtimes but MSIE (unless they've added it in IE11) already implement `const`, and it's standardized in ES6.

> Callback hell

> [...] In a normal situation this would have been fixed simply by adding a wait primitive to the language which would schedule the events when the result is still being fetched.

You mean, something like ES6's yield?

> Terrible exception handling

No objection there, javascript may well have a worse exception handling than Go, a language whose users try very hard to make others believe doesn't have exceptions in the first place. At least runtimes are finally trying to generate callbacks worth reading.

Not that this help when mixing with async, as your final traceback will lack 90% of the necessary context.


> All runtimes but MSIE (unless they've added it in IE11) already implement `const`, and it's standardized in ES6.

const implemented currently is very weird thing. It's more or less a read only variable, which silently ignores updates

var i = 0; for (var j = 0; j < 10; j++) { const C = i++; } // i == 10, C == 0 here

This is not something one would expect of constants honestly.

> You mean, something like ES6's yield?

yield is shallow, caller must be ready to cope with yielding explicitly, so it's not really a good replacement to proper coroutines that can pause arbitrary deep stacks.


> yield is shallow, caller must be ready to cope with yielding explicitly

TFA invokes C#'s `await` which is also cooperative and "shallow". Granted in C# there are APIs available for a synchronous function to "block on" an asynchronous one, but aside from that it's equivalent (the limitations are those of the underlying platforms, core.async loses the same features when doing from Clojure/JVM to ClojureScript/JS).

> so it's not really a good replacement to proper coroutines that can pause arbitrary deep stacks.

I agree, but I foremost went with the examples of "doing it better" which TFA provided, and TFA used `await` (if he'd used gevent or Erlang, I'd have been hosed)


Even I who seldom use JavaScript was able to see that the title post isn't written by somebody who actually knows the subject he's writing about. I knew some of masklinn's points but not all. Thanks masklinn.


> I strongly recommend not following the provided link, which is basically inane... This was my personal rumination on the differences between the two approaches to OOP. Or a way to verbalize it, if you will.

> to my knowledge, you most definitely can not do that in such a manner in Self. Slots manipulation in Self can only be done through primitive messages (e.g. `_AddSlots:`, which takes an object whose slots should be copied into the receiver). This is probably true, I haven't used Self in anger so I will remove that.

> I'm not saying maps-as-objects is great, but I am saying these assertions are 1. wrong and 2. nonsensical. First thing you do to diss a statement is call it flat out nonsense.

> In ES5, the exact same behavior is provided by Object.getPrototypeOf providing access to the internal [[Prototype]]. Most implementations also provide direct access via the __proto__ property, which IIRC ES6 standardizes. And of course the `instanceof` operator has been there since ES3, but that's only ~13 years ago.

Why do there have to be `typeof`, `instanceof` and `.prototype`? Whereas you actually want one way to get at the object's type?

> All runtimes but MSIE (unless they've added it in IE11) already implement `const`, and it's standardized in ES6.

Maybe I should note that I was talking about JS as it is deployable today, to narrow the scope.

> You mean, something like ES6's yield? This one? http://stackoverflow.com/questions/2282140/whats-the-yield-k... > Terrible exception handling No objection there, javascript may well have a worse exception handling than Go, a language whose users try very hard to make others believe doesn't have exceptions in the first place. At least runtimes are finally trying to generate callbacks worth reading. Not that this help when mixing with async, as your final traceback will lack 90% of the necessary context.

If your stack records the necessary metadata it could easily give you something like `closured on line X in Items.fetchItems` insted of the 'anonymous function' 5 levels deep.


ES6 has not been finished yet as far as I know.


It is not[0], but when TFA asserts

> They are not solvable by making a new ECMA spec.

I consider using the upcoming ("new") ECMA spec more than fair game to refute his assertions.

[0] although a number of its features are shimable, precede it by a few years, are already (possibly partially) implemented in some runtimes or are available through ES6 -> ES5 compilation via Traceur. See http://kangax.github.io/es5-compat-table/es6/


Yeah, though there are many parts that are effectively finalized, and are already making their way into browsers.

It sucks, but it's not quite as bad as the impression you get from "ES6 isn't done."


Aren't all these rants about programming languages as sterile as debating whether Spanish language sucks because it is not as regular as Italian language ? I really don't get it, people keep attacking issues of javascript or php. Fact is: 1) people use the languages of their choice to make programs. 2) Programs work, no matter as shitty the program is reputed to be 3) why look further ?

My view is: instead of ranting about languages (think about the meaning of that word), why not instead dissect what we do with them: programs, and find ways to improve them ?


> why not instead dissect what we do with them: programs, and find ways to improve them ?

The way to improve a lot of programs is to write them in a different language.


Another way is to fix/tune the algorithm


That may hit an upper bound, above which you have to rewrite in a different language. That upper bound may be quite low.


I'm very glad JavaScript is the language of the web. It has a combination of things I like that I don't find in many other languages:

* lexical scope

* first-class functions

* prototypal inheritance


Not many languages have prototypal inheritance, but most modern languages have first class functions these days. And what sane language uses dynamic scoping?


Do you mean lexical scope? Scheme has it and it is awesome. If you think it is not a good feature you should grab a SICP and see the magical stuff you can do with it.


He is asking what other sane language does not have lexical scope, as that was listed as one of JavaScript's advantages.


Oops you are right... I read it backwards, I can't edit it anymore :(


This article reads like this comic: http://imgs.xkcd.com/comics/rock_band.png

goes back to happily writing JavaScript


You are holding it wrong.

No seriously, you might be trying to use a fast glue/prototyping/event processing and browser deployed language to do something that should be done in a different environment. If your core logic task is algorithmic, consider C or Go and call that from your event framework. If it's data integrity/type-safety related, consider using your sql dialect.

(not a flamebait, but nosql is just a big distraction, please seriously consider postgres, it rocks, esp with json and plpgsql stored procedures that can be used to enforce data integrity braces and as independent unit testing for your data structures)

AngularJS, Express, node, and postgres is the most potent combination I've used in a long time.

Cheers,and good luck! F


Yes, JavaScript is terrible. But JavaScript is not the end of programming languages, it is a step for the next big language.

I think everybody agree that different languages for frontend / backend development are the not the best solution, so JavaScript is a big step forward.

But i think soon it is necessary for a complete rebuild for a new language, with all the things included that we learned and invented from the "old" languages.

Dart, TypeScript, Coffescript, and the 1.000 other language Modifications / frameworks try all to fix a little part of the problem. Thats nice but annoying too.


Is Dart an alternative for those problems?

Edit: I mean stuff like "callback hell", does it allow me to programm normally and still avoid blocking the loop?


If you're doing frontend dev, then you must use Javascript or a language which compiles to Javascript. I believe Dart currently has a mostly functional tool to compile Dart code to Javascript.

As for callback hell, Dart has "Futures" which are basically Promises. If you like Promises, you could use Dart...or one of the many excellent Promise libraries for Javascript; the syntax is almost identical.

(The linked article savages Promises for no obvious reason. I happen to like the syntax. In any case, Dart uses the same syntax, so if you buy the articles criticisms, Dart is no panacea.)


The "syntax" of promises in JS and Dart isn't really a syntax. They are library features in the form of fluent method chaining. This is merely a library pattern, it is not a syntax.

A syntax would be something like the async/await support in C#. Or the async and let!, do! etc along with pipelines in F#.


A valid point; that just seemed like the easiest way of phrasing it to me.

Anyhow, what I was trying to say is that the linked article trashes Promises, and Dart has Promises, so Dart is at least in that respect not a solution.


And this aspect is one of the biggest problems I got with JavaScript.

The only big things, which Dart seems to solve, is modularization and the many tiny JavaScript quirks, for which IDEs or a strong understanding of the language is needed.


Are there any compile-to-JavaScript languages out there, which do this?

I read about function* and yield, but this seems to require all functions to be rewritten.

Also I don't quite understand how this accomplishes to run 2 functions in parallel, if they are async.



Thank you!

Are there any non-ms solutions?


Funscript is not really MS - it's done by a third-party developer, and F# itself is open-sourced under a very liberal license, and runs well on Xamarin/Mono in OS X.

I don't think there are direct equivalents in other languages, although similar approaches exist. Checkout Elm for example:

http://elm-lang.org/Examples.elm


Haskell allows that.


As someone who maintains old 1000+ KLOC projects I have to agree. Have look at some large old Perl projects to see how JS code will look&feel in 10 years.

But on other side I see JS bytecode as great alternative to Java and JVM. Modern languages usually include JS as compilation back-end.


>But on other side I see JS bytecode as great alternative to Java and JVM.

Exactly how is javascript a better byte code than JVM byte code?


Obviously install base is huge.


For modern development of what?

Then don't use Javascript.

I'm not sure I can really appreciate another rant about how one language, framework, pre–compiler, VM, etc is terrible and everyone should stop using it.

Javascript's popularity has emerged organically. Its not because it has the best design. Its because it can get the job done and is browser based–and now server-side too. The browser is the next OS, the ultimate VM, if you will.

If you just stop picking at it and appreciate it for what it is...it is f'ing awesome.


It's operating a defacto monopoly on a layer of the modern development stack. This does not make it "f'ing awesome".

People rant about JS not because it's shit, per se. Everybody knows that. They rant because they long for better languages that are available across all web browsers.

I would like to see a standardised CLR-style VM that allows language modules to be loaded as requested by a particular web page. Otherwise we'll just be replacing JS with what will probably be another old fashioned imperative language (see: Rust). We don't want that. We want freedom to use whatever language we want.


> Then don't use Javascript

Like people have the choice. "Dont like HTML ? so dont write it" sounds stupid doesnt it.


The webpage is difficult to view in the Android Browser (though not Opera Mini) due to the overlay at the bottom.

http://m.imgur.com/9eOKqJZ

On that note, at what resolution, if any, do embedded code snippets from GitHub and the like stop getting get cut off on the mobile? At 800x480 they get cut off even in landscape mode.


The same happened on a windows phone


I don't get the "Fobjects are unusable for type systems since an object does not carry any type information."

You can just do

   if(myObjectToTest instanceof typeOfObjectIExpect)


I don't understand how the author thinks simply calling every little annoyance "shit", without further explanation, is very constructive.


Here we go again. Let's enumerate the technologies which are shit: HTML is horrible CSS is an abomination HTTP is wasteful, slow and old C++ is a horrible language (Linus Trovalds) C is dangerous Java sucks ..

I'll stop there and let you expand the list if you want.

Turns out the whole computing world is built on top of this terrible tech which many people hate, yet somehow it's moving forward.


All I know after years of being in the tech industry, every programming language ever invented has pissed off enough people that no one should ever use each language. I'm quite sure that languages not yet invented has already pissed enough people already that they'll be hated the day they are released.

Personally, I find such people childish in a way.

It's a tool in a toolbox. I've never seen a mechanic rant about the substandard design of a standard screwdriver because he pulled it first despite actually needing a phillips screwdriver.


Turns out the whole computing world is built on top of this terrible tech which many people hate, yet somehow it's moving forward.

Well, yes. Your hyperbole is actually the current state of affairs. Progress doesn't mean the things you're building on are good, just that they can be made to work. In fact, progress is the evolutionary process of throwing away some of the old stuff, calling it shit, and replacing it with the new hotness.


Because concepts from the bleeding edge of language research are slowly trickling down from Haskell & Co. to mainstream languages. Ten years after they emerge.


"JS has callable attributes, Hobjects are unusable for stable keys...object does not carry any type information, Null everywhere, since ojects are hashes"

I find most of the problems listed are related with dynamic type system of JS. These all can be solved most easily by a statically typed language.

Therefore the debate mostly is between static vs dynamic typing.


I would also argue that expecting an object to carry type information is an unfair expectation of a non-object-orientated language.


JavaScript is an objected oriented language.


Not really, from what I gather it's closer to a functional language that lets you implement objects with private data by using closures.


Yes really. It's an OO language based on Self's prototypical OO model rather than a class based OO model. Prototypical OO is still OO, unless you're claiming Self isn't OO, but the Smalltalker's who invented Self would very much disagree. Prototypes are objects, no closures or classes required.


FWIW by the way, I don't get all the JavaScript hate either, other than perhaps it's from people who erroneously think they don't have any choice except to use JavaScript on the client side. From what I've seen of JS as a language, I actually quite like it, but haven't used it for anything substantial.

I do like what we seem to be arriving at with asm.js; a subset of JS as the assembly language of the web, with people being able to choose the language that best fits their problem domain and target the JS machine.


Ah, I stand corrected, thanks. Makes sense; I think I had something about private vars in JavaScript and closures running through my head and confused it with 'JavaScript does OO with closures' :)


No problem.

People who don't like or get prototypes have certainly reimplemented classes with closures, but classes are not a requirement to be OO, objects are; classes are just one way to do it, prototypes are another. Objects don't require classes, though many a JavaScript programmer thinks so.


It is more about weak typing vs strong typing. Clojure has dynamic but stronger typing and it has less of these problems.


No matter if I agree with this or not; why the stab at Java there? I'm not sure what the resemblance, besides the name, is here? Or does OP just dislike Java (for some completely different reason) and could it just have as well been Perl or PHP or whatever a lot of people don't like?


Date API (old, not the new one that is arriving) was taken from Java. And Date library in Java is frankly... horrible.


Google Closure Compiler + @struct = new property definition outside of constructor is forbidden.

Or DEBUG_ON && Object.seal(this); at the end of every constructor.

Here, I've fixed "Hobjects" for you.

JavaScript allows you to write shitty code, but whether you do it or not is just a matter of skills and tools.


- Unfortunatly you can complain all you want you'll have to write some javascript if you do front-end development. And today there are quite a lot of tools (transpilers,linters,etc...) that can help you with that.

Fortunalty you can chose the language you want on the server.


Is it impossible to write an article like this without liberal use of swearing? Many of the points in the article are quite reasonable, but with the foul language used in it I cannot bring myself to read it all.

Foul English is far, far worse in my eyes at least than JavaScript.


Another rant by a programmer who clearly doesn't understand JS... It does have its drawbacks (what language doens't?) but if you have some coding discipline you can code pretty big application without headbanging.


Every time I read an article of someone blaming a language, that is not the language they love, I feel like I am reading an airplane pilot, driving a bus and screaming: BUT THIS THING DOESN'T FLY!!!


While I agree JS is a shitty language overall, and worst when writer larger apps.

Having someone who wrote this on a website that spend 30% of the screen estate for page footer isn't very convincing.


I've been meaning to pick up Dart for a new app, but there aren't any great frameworks for Dart apps yet. It seems Angular is being ported though.


Dart doesn't really need "frameworks" in the way that JavaScript does. The core libraries are very rich:

  * dart:async give you Futures (Promises in JS, no need for Q) and Streams
  * dart:core and dart:collections give you real data structures like List, Map, Set, Queue, LinkedList, LinkedHashMap, etc. Much more comprehensive than underscore.js
  * dart:html is much improved over JS's DOM, and have most of jQuery's functionality (see ElementList).
  * New and upcoming standards like Shadow DOM, custom elements and template binding let you declaratively define your HTML template in HTML with data-binding, which is the foundation of frameworks like Ember, Angular, Knockout, etc.
  * Polymer is a JS and Dart library for helping you write custom elements.
Also, the package system in Dart, pub, is very similar to npm and encourages smaller, focused packages rather than sprawling frameworks.

Check it out, it's a very nice language and environment. But I'm on the Dart team, so I'm obviously biased.


Well, this will probably just be ignored or downvoted, but as far as I can tell, ToffeeScript (a derivative of CoffeeScript which is a derivative of JavaScript) is the best language to be programming in today.

Of course "best" is subjective, but I believe that the combination of Node.js's superior module system and the available packages, the clarity of the language (which actually surpasses Python) combined with the asynchronous single-threaded event-based model, and ToffeeScript syntax which makes asynchronous code read like synchronous code, makes this a superior platform.

I do think that Go is a wonderful evolution of C, but the module system or at least ecosystem is inferior to Node's, and the language syntax and concurrency approach (although very useful and better than Node's in many circumstances) is old-fashioned.

Many people don't trust, don't learn, and ultimately cannot objectively evaluate JavaScript, simply because it is too easy to use. [sarcasm] And everyone knows that real programmers don't use easy languages. Those are for beginners.[/sarcasm] That's the real explanation for most of the JS hate. The other part of it is the people who did try to learn it, found out there were problems, and then for whatever illogical reason decided that they couldn't use CoffeeScript or any other similar language to compensate for those problems.


> In a normal situation this would have been fixed simply by adding a wait primitive to the language which would schedule the events when the result is still being fetched... 80 percent of the programming is about doing one motherfucking thing with another motherfucking thing and you need both of them to complete the action.

I love JavaScript, but I totally agree with this.


Agree. JS = gavno. It's faster than Ruby only because Ruby is slow like gavno as well.

The fact that many are eating gavno and are feeling happy about it does not make it healthy or tasty. The problem is when there are no other food to choose (browsers).

That's why I love backend development. I can choose a decent, compiled, strongly typed language and well-supported framework.


I thought I'd write up a response to this, pointing out how Javascripters get around these issues right now, and how they will come ES6: http://sidekicksrc.com/post/for-modern-development-javascrip...


Hey folks, thanks for all the constructive criticism and death wishes. Will do my best to respond in detail - but for now I've removed the fixed footer. Deployment from the train FTW.


Looks like learning rage.

When faced with a new thing to learn, point out all the mistakes and flaws that give you reasons to not learn this shitty thing in the first place.

Or it could be the 3rd stage of grief :)


Most of the comments in the article are about the horrible footer. Gosh, is indeed an awful footer.

Oh by the way I agree with half of what he said (just half) but I still enjoy javascript.


To me it seems the author is expressing his own inability to code in the language, why discuss someone's opinion?


Coffee Script makes it a bit sweeter.


yay ruby!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: