JavaScript Is Weird
jsisweird.com
jsisweird.com
That's not really a JS problem, that's a floating point problem. Plenty of languages will have the same issue.
+!![]
"" - - ""
(null - 0) + "0"
Calling these things weird is fair enough but I can't help thinking this is code you'd never actually write outside of the context of a "Look how weird JS is!" post. It's like picking examples from the Annual Obfuscated C Contest to show how hard it is to understand C. Yes, some languages enable you to write weird garbage code that's hard to reason about, and ideally they wouldn't because enforcing sane code would be great, but come on. Most of these things aren't a big problem that we suffer every day. Just be moderately careful about casting things from one data type to another and all these problems go away.
If all electrical activity ceases, does memory survive? (Answer is very likely yes given cryonic experiments. Brain is protein, ion currents have tendency to auto fire on defrost.)
Just like we invented TypeScript because JavaScript wasn't very good.
The fact that there has to be a different language on top of your language to make it sane says all that needs saying really.
Like most bad things, it's only around because a big company said so.
Like all bad things in JS, there was a push to remove it at ECMA, but Microsoft had reverse-engineered JS into JScript and refused to go along with the changes to fix the weirdness.
Even Javascript's weak typing makes sense in this case. Why automatically convert everything? Becausethe expectation was that inputs to your Javascript would be HTML attributes which are all strings. Automating type conversions from strings made sense. But once you move to larger scale programing, Javascript's weak typing is awful
While the fact JS can be used to build all these things puts a floor on its quality, that floor is uselessly low.
But that there is a very broad range of successful applications partly relying on JavaScript for their success undercuts the idea that JavaScript is inherently rubbish. Whether it has some subjective "quality" is a conversation best left for art galleries.
[French Narrator] 5 minutes later...
"I'm not using popularity as the metric."
It's true that being popular doesn't necessarily make something good. But it's also true that having some flaws discovered later doesn't make something that revolutionized the world and massively uplifted the standard of living of basically everyone in it bad.
> Even if you're a JS developer, most of this syntax is probably, and hopefully, not something you use in your daily life.
So I think you should look at this site more as something fun you might not have known if you're an js developer than as criticism of js.
That being said, the !!"" isn't that weird of a syntax is it? I see and use the double exclamation mark all the time.
Most people arent going to "know" what '+!![]' will resolve to because it makes literally no sense to combine those operators into a single expression in anything approaching normal code.
The fact that [] is truthy is something everybody learns in their first weeks of JS programming otherwise you would be writing `if (someArray)` and wondering why your code is broken.
A weird one would be to explain why +[] is 0 and +{} is NaN. That is nonsensical.
perl -e 'print !!"whee"'
1
php -r 'print !!"whee";'
1
awk 'BEGIN {print !!"whee"}'
1> the !!"" isn't that weird of a syntax is it?
Why would someone say not not empty string in code somewhere? Or do you mean seeing !!var_that_could_have_empty_string isn't too weird?
More accurately it's a binary problem. 0.1 and 0.3 have non-terminating representations in binary, so it's completely irrelevant whether you're using fixed or floating point.
Any number that can be represented as the sum of powers of 2 and 5 have a terminating decimal representation, whereas only numbers that can be represented as the sum of powers of 2 have a terminating representation in binary. The latter is clearly a subset of the former, so it seems obvious that we should be using decimal types by default in our programming languages.
Oh well.
https://iquilezles.org/www/articles/floatingbar/floatingbar....
> integer unscaled value + integer scale
binary float does the same, just using 2^exp instead of 10^exp for scale.
Note: I'm using a notation for infinitely repeating decimals that I learned in school - 0.(6) means 0.6666666...; 0.(01) means 0.010101010101...
This will be a problem for any base representation when it has to be boxed in finite number of digits or memory.
One good thing is decimal is widely used format, so it is good to go with that for representing stuff. But, it is more of an accidental advantage that decimal has. Nothing more.
I think there are arguments to use decimal as representation is there, (where I originally came to know about this problem) [1].
No. "1", "3" and "10" can all fit easily in just four bits.
Just use rational numbers and solve the problem for good.
[1, 2, 3] + [4, 5, 6] // -> "1,2,34,5,6"
[,,,].length // -> 3
> [1, 2, 3] + [4, 5, 6] // -> "1,2,34,5,6"
What would you expect instead?
> [,,,].length // -> 3
Is there any use case where you would want to deal with sparse arrays?
> What would you expect instead?
If I let my first instinct speak:
[1,2,3,4,5,6]
And then if I think a little more, then maybe:
[5,7,9] //with obvious caveats
In no way do I expect what GP actually provided.
[1] https://tc39.es/ecma262/multipage/ecmascript-language-expres...
I am very happy with JS and TS and I think the coercion rules are easily worked around with linter rules and policies, but they are definitely weird and I think the language would be better if it simply threw exceptions instead. But then, such an issue shoud not be surprising for a language that was designed in 10 days.
If someone does not like the ECMAScript specification, that is fine. But at least use a proper unofficial documentation like MDN.
If you ask experts it is because you want to get an actual correct answer, but if you ask neophytes it is because you want to get an answer that might be obvious even if not correct.
An addition operation over two numerical vectors of length 3.
I would expect the result to match its inputs and provide a numerical vector of length 3.
Thus: [5, 7, 9]
So if applying an operator to arrays spread the operation across all the elements that way, it would imply that the same should happen generally for all object properties, with whatever weird implications that would entail.
a.foo = 1
b.foo = 'there'
a + b // { foo: '1there' } ?Not really. Now explain why [,,,].map((e,i) => i) is [,,,] instead of [1,2,3] please ;)
Array(4) // [empty × 4]
a=[]; a.length=4; a // [empty × 4]
Array(4).map(n => n) // [empty × 4]
[,,1,,].map(n => n) // [empty × 2, 1, empty]
My go-to way of avoiding this annoyance is "Array.from(Array(N))": Array.from(Array(4)).map((n,i) => i) // [0, 1, 2, 3]
Alternately there's a recent "fill" method, that assigns all elements (including empty ones) to a given value: Array(4).fill(1) // [1, 1, 1, 1]The second is only weird in that you are constructing an array with implicit undefined values, which is exactly what I would expect to happen if my linter didn't complain about the syntax and I had to guess what might be happening.
Like GP said, comes from other languages. That line can be copy/pasted into python and it performs concatenation.
"WAT $a .= "World!"; ?"
I don't think this is too weird if you think about it. JS allows trailing commas, so the last one is ignored. Effectively this is `[ undefined, undefined, undefined, ]`. A syntax error would have made sense here, but the length of three is a result of the usual syntax rules, not a particular strange quirk of JS.
Turns out several months before, someone was doing some refactoring, moved some methods around, but also changed a "==" to a "===" in the process. Generally a good idea, but it slipped through to production without anyone noticing or breaking any tests.
The issue ended up being that a rare code path in a tangentially related method would cause that method to return a float instead of an int. This propagated through, eventually causing a check of 0.0 === 0 to fail where previously 0.0 == 0 passed.
What bloat are you referring to? TS compiles down to plain JS.
Edit: I accept the downvotes for my tone and have updated it. However, I do feel that by the exact same argument "toolchain bloat" exists, surely one could seamlessly argue "testing bloat" exists, and it should be transparent from the popularity of TypeScript that it's a good tradeoff
Someone arguing a little defensive programming is equivalently strong to a type system is clearly unaware just how much work a good type system does for you. I of course agree with you: when you're fetching data that you don't know the type of, recklessly casting it to some type is going to cause issues. This is true in every language that has ever existed. It's also why tools like IO-TS[0] exist, and of course you can enforce this with JSON Schema techniques or custom validators or a million other options.
Edit: in case the ultimate point of this comment is not clear, by using a type system and some type validator on your fetches, you are able to reduce the need for defensive programming exclusively to your fetch points. Clearly, defensive programming at the fetch points was already needed, so this is why I do not agree with the claim TypeScript's value add disappears from remote fetches.
The IO entry point of your code will always be unknown no matter what programming language you are using. In typescript, you do validations in these cases to make sure outside data fits into your type system, from then on (probably about 99% of the rest of the code) won't need any validation whatsoever because the compiler is already doing it for you.
Bloat is the amount of time you lose doing code review to check if things are possibly null or doing null checks on stuff that is never null or a bunch of other stuff that the compiler will do for you just by writing some minimal types. The compiler does this stuff automatically without getting tired, can't say the same thing for humans.
Additionally, I think it is safe to say a JavaScript user who grabs a TypeScript library and uses it without importing the types to be misusing the library. Imagine if someone were to have a whole test suite was available to them while they develop, and they opted to never run it. And then they complained to you the tests didn't catch any errors. You would look at them sideways, no? Misuse and poor application (human error) are of course things TypeScript cannot solve.
For the same reason that, as the saying goes, there is no such thing as a "compiled language", no, "C" doesn't give you a warning about types. The compiler you're using gives you a warning. If you want a typechecking pass over JS, then use a tool that does typechecking. Eschewing with a typechecker and then complaining about the lack of type mismatch warnings, however, makes little sense.
In this case, complaining about the environment as a whole does make sense.
(+ (not (not '())))
The value NIL is not of the expected type NUMBER.
Similarly in Ruby: +!![]
undefined method `+@' for true:TrueClass (NoMethodError)
[Condition of type TYPE-ERROR]
Interestingly, Python does the same thing as JS in this case, even though it is typically quite strongly typed. Edit: not quite the same, as the empty array is converted to False in Python, just as it is in Ruby (in CL, nil/'() IS the canonical false value); but still, Python outputs 0, it doesn't complain like the other two.yep, this is one of those Python weird bits. in Python, booleans are ints, True is 1 and 0 is False. and i don't mean it in a JS-ish way like "they can be converted to...". no, True is the integer value 1. in fact, the type bool is a subtype of int. if you think of types as sets of values, and subtypes as subsets of their parent set, that `book < int` relation suddenly makes a lot of sense ;)
>>> +(not not [])
0
>>> (not not [])
False
>>> 0 == False
True
>>> 1 == True
True
>>> True + True
2
>>> True - False + True * 0.5
1.5
>>> isinstance(False, bool)
True
>>> isinstance(False, int)
True
>>> bool < int
True
so, if you accept that the operation `not []` makes sense to be defined as True (because `bool([])` is False), and that it makes sense for False to be the integer 0, then `+(not not [])` being 0 is just a logical consequence of that :)for the record, i do think it's weird for Python to define bools as ints, and to make all values define a boolean semantics via __bool__().
The rationale for making bool a subset of integers is for ease of implementation and substitutability (which aids backwards compatibility)47, as explained here:
> In an ideal world, bool might be better implemented as a separate integer type that knows how to perform mixed-mode arithmetic. However, inheriting bool from int eases the implementation enormously (in part since all C code that calls PyInt_Check() will continue to work -- this returns true for subclasses of int). Also, I believe this is right in terms of substitutability: code that requires an int can be fed a bool and it will behave the same as 0 or 1.
I have some Python code where there are still a number of uses of 0 and 1 for false and true, because it was written before Python added a boolean type.
https://stackoverflow.com/a/23465314
For me it’s only rows [[]], [0], [1], i.e. array-unfolding related, but all others are regular weak-typed comparisons like in perl and other dynamic semantics. <snip> Edit: just realized “if (array)” is okay, nevermind.
object.someField === null || object.someFeild === undefined
madness, or to a potential error if a programmer thinks that null can not be there.We could do an exception for null === undefined, but it’s against its spirit and will not be accepted.
^ languages that treat non-existent key as undefined are usually doomed to introduce Null atom in some form, or to work around that limitation constantly in metaprogramming
You never do them on purpose. The problem is when you do them by accident because of a mistake in your code, and the error slips through unnoticed, doing the wrong thing.
> weak-typed comparisons like in perl
Perl has separate operators for working on strings vs numbers, so you are always explicit about performing a numerical vs string comparison etc. Not so for JavaScript.
But the values which you compare do not have to be of the same type, and it does not end at scalars (which are really ephemeral in their exact typing even in native API, see perlapi). Basically it has two flavors of ==, each with its own preferred coercion. Perl also has contexts, e.g. boolean and scalar which can operate on lists and hashes (@list == 5). While the form is different, semantics are similar.
The problem is when you do them by accident because of a mistake in your code, and the error slips through unnoticed, doing the wrong thing
If your string array contains some [[0]] by accident, I’d say there is not much left to do anyway. === doesn’t report this either, it only has narrower trueness, which may decrease or increase an error surface depending on how your conditions are spelled. And to be clear, I’m not arguing against using === in places where identity^ or strict equality check is necessary or desired (you may desire it most of the times and that’s valid). My concern is that (a) everyone blames == anywhere, for completely zealous reasons, (b) I have to type a poem to test for null and calm down someone’s anxiety.
^ I know it’s not exactly identity, but is close enough for practical purposes
Carmack-like people utilising this stuff for good are few and far between, for your everyday joe programmer this is a footgun, a very-nonobvious and non-intuitive one (hence footgun moniker) that they write in crunch, it slips past reviews because reviewers are just joes with couple extra years, if at all, and then whrn things break after deployment, its an absolute pain to debug.
I mean:
!!!true
In what language does that (or its equivalent) not evaluate to false? False, True = True, False # Have fun debugging!In that Go example above, the author is reassigning true and false to be their opposites.
Some people add two exclamation points as a shorthand to cast a value to a boolean. So if you wanted to see if something was 'truthy', you could say `!!truthyValue` and it would return ` true` instead of the value itself. Literally what your asking the language is "give me the opposite boolean value of the opposite boolean value of `truthyValue`"
Now you can probably see why three exclamation points is silly, it's not giving you anything that a single exclamation point wouldn't give you. Both `!truthyValue` and `!!!truthyValue` evaluate to false, you are literally saying "give me the opposite boolean value of the opposite boolean value of the opposite boolean value of `truthyValue`"
The example in Go is intentionally misleading because Go lets you reassign the values for `true` and `false`. It's going through all the same steps I described above, but it's starting with a value opposite of what you think it is
Kinda crazy to me that Go doesn't reserve the words "true" and "false", but ¯\_(ツ)_/¯
To "implement decimal numbers" in .net on x86 hardware simply means writing a custom decimal implementation in software.
JS had implicit integers since the beginning. It has had arrays of integers (what's necessary for fast decimal implementations) since BEFORE the release of WebGL a decade ago. It has also added BigInt this year. Just like .net, there's decimal libraries available if you know to use them.
https://github.com/MikeMcl/decimal.js/
The real takeaway is that modern processors should definitely add hardware support for decimal numbers.
That is the whole premise of the site, though. They even say that these examples aren't common syntax or patterns before you start.
am i being punkd?
Including JS - http://mikemcl.github.io/decimal.js/
https://github.com/tc39/proposal-decimal
Seems like it's a long ways away from being available, though.
> that's a floating point problem. Plenty of languages will have the same issue.
yes, many (most) other languages do have the same floating point issues, but that doesn't make them less weird. JS numbers are IEEE floating point numbers, therefore floating point issues/weirdness are also JS issues/weirdness :)
> Calling these things weird is fair enough but I can't help thinking this is code you'd never actually write outside of the context of a "Look how weird JS is!" post.
the verbatim code snippets in particular, yes, you're completely right. but the underlying problems that these snippets exemplify are still there on actual "real" running code. they just look less suspicious on the surface.
> Just be moderately careful about casting things from one data type to another and all these problems go away.
true. but still, these things can happen, and when they happen, they tend to sneakily manifest as weird UI bugs, like rendering "NaN" or "undefined" on the screen (we have all seen those... there's plenty of meme images about them too), instead of noisily breaking with an exception, which is way more noticeable and actionable for us programmers when doing introducing these bugs in the first place hehe.
it's true that they are not the most common kind of bugs, i'll give you that, but when they happen, they can be incredibly frustrating in my experience, because you may only realize after they have been affecting user for a looong time (maybe years), but you just didn't know because JS decided it was a good idea to carry on after one of these nonsense operations like adding an array to a number, giving you nonsense results instead of useful (runtime) type errors.
story time!
i remember an ugly case of this which involved some search filters on a big-ish system. the JS code was quite generic in how it handled filters, and looked fine. for some time, all filters were single-value, as simple strings, but at some point the system started handling multi-value filters, which were encoded as arrays of strings. well, the programmers who implemented the UI for multi-valued filters just tried sending array of strings as filters to the existing filtering system, and it seemed to work correctly in the results it yielded, so they assumed the code was prepared for that too (it looked generic enough), and so they shipped the feature that way.
it was only years later, when i was porting some of that code to typescript, that typescript complained about invalid type operations. i was converting between languages pretty willy-nilly and assuming the existing system worked correctly, so i suspected typescript was being dumb with that type error. but no, it was actually complaining about an actual bug. when passing arrays of strings as filters, the underlying filtering system was at some point coercing those arrays to strings by accident. so ['apples', 'oranges'] became 'apple,oranges'.
the search results were always right when the multi-valued filters had only one value (because ['apples'] coerced to string is 'apples') and kinda right in some naive cases of multi-valued filters (because of how the text search engine worked), which was probably why the original programmers thought it was working correctly and didn't give it much more though or more thorough testing. but the search results were definitely not correct in most non-naive cases of multi-valued filters.
so our users had been affected by this bug of multi-value search filters basically not working for years, and we only discovered it by accident when porting some of the JS code to typescript because typescript was kind enough to tell us about this nonsense operation statically, without having to even run the code. i wish that JS were also kind enough to complain about these nonsense operations, albeit at runtime. it would have made this problem obvious from the get go, and would have prevented the original programmers from shipping a broken feature to thousands of users.
plot twist: although the story may make it seem that i was the competent programmer that figured it all out when porting the code to typescript, in reality "the original programmers" also included me (probably, i don't remember really), just some time before the typescript port :/
If a user does need to do scientific computing, they could use a "# use-floating-point" pragma or something so that literals get interpreted as floating point. Otherwise, we map them to rationals.
Of course, doing rational arithmetic is much slower (for example, Gaussian elimination is exponential for arbitrary precision rationals, while it's famously O(n^3) for floating point), so there's a danger of people accidentally using it in triply nested loops etc., but I have a feeling that if you need to do that kind of thing you know that you might run into performance issues and you think twice.
I haven't come across the "pragma" directive in a Javascript context. I guess it's another new feature (I have trouble keeping up these days).
In modern JavaScript, you can use BigInt literals by suffixing an n, like this:
const maxPlusOne = 9007199254740992n;
If I could magically redesign the language, I would make all integer literals be effectively BigInt values, and I would make all decimal literals be effectively decimal values so that 0.1 + 0.2 === 0.3. I would reserve the letter suffixes for more performant types like 64-bit floating point numbers that have surprising behaviour.Sadly, most people don't understand the distinctions, so this will never happen. (Even in reply to your post people keep talking about "decimals", as if the number base is at all relevant here.)
The number base is relevant, because money is discrete, and measured in units of exactly 1/10^n, and if you try to use floating point numbers to represent that you will cause your future self a world of pain.
This is technically impossible. Almost all of the real numbers can't be represented in a computer. The most you can get is the computable reals. But to be able to represent some of those and to do arithmetic on them, you have to use somewhat complicated representations such as Cauchy sequences.
The use cases for computing with exact representations of (computable) irrational numbers are fairly limited (probably mostly restricted to symbolic algebra). In 99% of cases, if you need the square root of 2 that's probably because this comes from some sort of measurement (e.g. you need the diagonal of a square with sides 1), and if it's a measurement, there's going to be an error associated with it anyway and there's no point in insisting that this number that you measured is "exactly" sqrt(2).
This is different from rational (and, in particular, integer) numbers, in which case there are many valid use cases for representing them exactly, e.g. money.
It's technically impossible for the integers too.
> Almost all of the real numbers can't be represented in a computer.
Almost all of the integers can't be represented in a computer.
What, exactly, is your point?
For every integer, there exists a computer that can represent it. Even with constant memory, I can right now write a computer program that will eventually output every integer if it runs for long enough.
By contrast, for almost all (i.e. an uncountable number of) real numbers there exists no computer whatsoever that can ever hope to represent any of them.
Another way of seeing that is that, while Z is infinite, any single integer only requires finite amount of memory. But a real number may require an infinite amount of memory.
The integers can also be represented fairly easily as a type. For the naturals, for example, it's as easy as
data Nat = Z | S Nat
(ML-type languages allow to do this very concisely, but you can do theoretically the same type of thing with e.g. Java and inheritance; if you use Scala or Kotlin, use a sealed class, if you use Swift, use an enum, etc.)The integers are slightly more complicated (if you just try to add a sign, you'll have to deal with the fact that you now have +0 and -0), but still not hard. Rationals are a bit harder in that now you really have multiple different representations which are equivalent, but you can also deal with that.
By contrast, you won't be able to construct a type that encodes exactly the set of real numbers. The most you can do is to provide e.g. an interface (or typeclass) Real with some associated axioms and let any concrete type implement that interface.
The distinction is irrelevant in the context of computers.
> By contrast, you won't be able to construct a type that encodes exactly the set of real numbers.
You don't need to encode exactly, just like you don't need to encode the integers "exactly".
All you need is a way to guarantee a finite number of significant digits in your real number approximation.
Floating point numbers give you that, problem solved.
No. For example, floating point addition is not necessarily associative. In that sense, floating point numbers aren't even a field and it's wrong to say that they can be used as a stand-in for real numbers.
Floating-point numbers are incredibly useful and it is amazing that we can exactly analyze their error bounds, but it's wrong to treat them as if they were real numbers.
Arbitrary-precision rationals would get extremely hairy extremely quickly and simply break down for a huge number of use cases. People use exponentiation, square roots, and compound interest! If a "senior developer" who actually works with real account balances doesn't understand floating point, why would you expect them to understand why they can take the square root of 4, but the square root of 2 crashes their application? Or why representing the total interest on a 30-year loan at 3.5% takes over 400 bits?
The reality is that software engineers need to understand how computers work for the field they're working in. Many (if not most) programmers will never encounter a situation where they're responsible for tracking real account balances. The ones that do simply need to know how to do their job.
Way too much abstraction for that to be an argument.
Oh for sure. I agree. That's not what we're arguing though.
We consider >70% passing.
The only reason I have learned some of that oddball stuff with JavaScript is because of some job interviews e.g. when I was earlier in my career, I used to Google things like "top 30 questions asked in a JS interview", etc, but I forget it after that until I'm about to look for another job. However I wouldn't do this type of learning any longer, since I wouldn't want to apply for a company asking these types of questions.
In the end at work you should use ES6/TypeScript with linting, proper tests and these cases would never occur.
I really enjoyed the questions... and even though I am working in TypeScript, I got only 9/25. Precisely because I avoid f---ed up parts of JS, except for trivia games (https://dorey.github.io/JavaScript-Equality-Table/unified/, http://www.jsfuck.com/).
Some parts of code need not to be understood. They need to be blocked by types, tests, and linters (https://p.migdal.pl/2020/03/02/types-tests-typescript.html).
There are a lot of people being born every year. If a 16-18 year old teenager is getting into web development, they were 4-6 when that talk was given in 2012. Sure, that talk still appears here and there, but it's past its prime and you'd have to be in the right place at the right time to run into it.
Crockford's book (JS: The Good Parts) was ubiquitous among JS devs who were coding between 2008 and 2015 (give or take). These days, younger devs have never heard of it. Due to the Seinfeld Effect, if they read it, it would seem trite and obvious not realizing how revolutionary it was at the time.
The parent comments floating to the top here seem to have a common theme of "I knew that already how did the rest of the world not also get the memo at the same exact moment I did?"
Though, I hope that now people learn JS without its worst parts.
In any real codebase, expressions such as `true + ''` should not be understood. They should be eradicated.
> This website is literally about JavaScript. I mean what did you expect, a .NET application? This website is 99.9% poorly optimized and highly questionable JS. And yet, you have JS turned off.
"What, are you going to check if the results are accurate? Go ahead "
But if you open it console while doing the test, it says:
"Hey, stop cheating! "
This annoys me every time because I use Tree Style Tab, and a website tries to detect DevTools. See Samy Kamkar's website [0].
[0]: https://samy.pl/
<script>var answers="I SAID STOP CHEATING! >:( You will get answers and explanations at the end, you dang dastardly dangusson."</script>
I love sites that have easter-eggs in noscript/console. Noscript I can see being annoying (i.e. instead of showing content), but there are some exceptions like this site.
#4, #13, #14, #21 and #24 are floating point problems and are nothing to do with JavaScript.
A bunch of them are just "learn the language" issues:
#2 I only got wrong because I never noticed JS allows trailing commas. Trailing commas are pretty damn common in most modern languages though. The syntax for empty initialisation of arrays is weird (and I'd argue is a mistake), but the behaviour is exactly what you'd expect.
#5 is the comma operator as also seen in C and C++.
#8 is something nobody should get wrong. Three nots in front of a true is false. Of course it is.
#10 is just an octal literal. They're becoming increasingly rare in modern languages, and were never quite as common as hex literals, but they're also not terribly obscure.
#15 is one I'm slightly ashamed I got wrong. It makes no sense to use increment operators on a bare value. This is common to just about all languages that support increment operators (and it's those, if any, that don't agree are in the wrong)
#22 is a slightly surprising counterpoint, but it also makes sense. I don't know of a language that has a NaN literal, and JavaScript is no exception. So that NaN is actually a global that is bound to the floating point value NaN. Because it is a global, it can be incremented (but incrementing NaN is still NaN).
Everything else is a type coercion issue.
#18 and #23 are coercions I really disagree with. Coercing things to a number shouldn't produce NaN. That truly is crazy. Throwing is the only reasonable behaviour here. Ruby is even worse than JS here ("true".to_i produces 0), Python gets it right.
Other than that, the coercions are all fairly make sense, and are consistent with what other languages do. Now, implicit type coercion (especially under the guise of abstract equality) is a terrible idea because it's easy to do it by accident and get nonsensical results, but the coercions themselves are, by and large, pretty sane.
No one used to risk it because IE was inconsistent with what it meant.
Imagine trying to explain to them that this was their fault? Even trying to find the words to explain what happened made me feel bad that their first experience programming was tarnished by a language that will gladly allow you to do nonsense.
Maybe strongly typed compiled languages would be a better fit?
One can argue that if you want to program it might be too much information for starters - but IMO basic types are such a fundamental concept that it would be better to teach that concept early on.
It also clears up a lot of newbie confusion as you cannot assign string to an int by mistake with strongly typed language. Such scenarios are then handled by compiler so newly starting dev has quick feedback on fundamental issues with his code without having to ask people around.
@ozim, I don't believe you are trolling!
JS is an absolutely awful language for beginners; it's a 155mm howitzer pointed at your foot. Although you can get the hang of the basics quickly, AND it runs in the browser (super-convenient unless you're headless), those "basics" that you thought you'd got the hang of turn out to have semantics that make sense, but are not what you expected.
I wrote JS (about 0.2 of my time, I guess) for my job, for about 20 years. I got 18 out of 25 on that test. Now, I think it was actually an easy test; I got a third of my answers wrong because I haven't learned about a third of JS semantics. I'm either not very good, or not as smart as I like to think.
A certain recent colleague of mine would probably have got 25/25; he was cleverer than me, and he was REALLY into Javascript.
Try a Pascal-type language, to learn an imperative-type language. Modula2 is better. Learning Prolog is (I think) purely declarative, so it gives you the view from the other side of the curtain - as it were. Forth is a perfectly-feasible beginner's language; it was the second language I learned.
I can't recommend any OO language for beginners. Not because I think all OO languages are way too difficult, only all the ones I've used. I haven't used Smalltalk.
I haven't used any flavour of Lisp. That language is so pliable that I'm sure there's a flavour that would be good for beginners.
[edit] Actually, I wish I had learned a functional language like Lisp as my starting language; I strongly suspect that would have made me a better programmer throughout my career.
I agree OO is too much for any beginner. Getting started with procedural thinking + basic types is in my opinion a requirement.
I agree nice parts about starting with JS is that basically only things you need is text editor and a browser.
Unfortunately data types will show up one way or the other so there is no need of hiding those. Even in Excel creating formulas one has to understand text vs number and difference between '.' and ',' and how operating system configuration make sometimes '.' to be decimal separator and sometimes ','.
To be fair the primary reason is not really a virtue of Javascript per se, but the fact that it runs in the browser is a large pedagogical gain that no other language can easily match and is hard to overstate. Learning to program is overwhelming for most students, and setting up your environment is a major component of that. Being able to run your code natively in the browser is a huge boon. Even better, having that code immediately be useable in a very real sense boosts motivation significantly. For most students it really is preferable to let students get very comfortable with basic code constructs before having to interact with the underlying system in any meaningful way.
At the language level, Javascript also has some nice affordances that let you treat constructs as simpler than they are in your curriculum and expand on them later. I think the best example of this is `var`. Viewing variables as uncomplicated "buckets" that happily contain any data you want to shove in them is a good starting place when introducing the very first building blocks of something like if/else control flow.
Most languages are built with semi-experienced programmers in mind and are ill-suited for many beginners and actively bad for children. As an easy example: as a developer I like seeing type specifications for numbers, but pedagogically having to introduce the difference between ints and floats on the first day is just empirically confusing for most students. Much better for them to be "magic" until you can properly motivate them to care (which can be just a few weeks in!)
I could write on this topic far longer than I have, but the short of it is that Javascript has done a truly surprising number of things right for a teaching language. I'd still love to remove some of the zany examples here if I could though.
Adding types is, again, confusing to most beginning students and adding any sort of build process is asking for tears.
The bugs, while unpleasant, just aren't actually that bad pedagogically. Students readily accept explanations of the form "computers are dumb and do what you tell them, if you tell them to do something that doesn't make sense they will do something that doesn't make sense" which is close enough to correct to not give them a terrible mental that is difficult to unlearn later.
Additionally, at this stage of learning students should be writing many small programs. Such programs are typically easy for teaching aids to debug in seconds (or to suggest a radically simplified re-write).
It is like learning how to snowboard, I am now on a level where I can go downhill quite quickly, but I don't have enough experience to not crash if something unexpected pops up.
Learning with `var` is just a bucket seems to be that it is going to cause a lot of frustration and pain later on when person thinks he gets it.
1. Tell the student we're oversimplifying, and maintain their trust in us so that they'll follow along when we do so.
2. Revisit oversimplified explanations when they have enough knowledge and context to understand more detailed and correct explanation.
The point I've been making is that Javascript makes it easy to pace our explanations of complex programming topics while still allowing students to consistently writing working code. Most languages require a large amounts of either upfront understanding or faith in "magic incantations", both of which hinder learning (this is not a criticism of those languages, they were designed for professionals). So Javascript still manages pretty admirably, all things considered.
I'd argue that if you don't know about type coercion in JS, you don't really know JS. It's a feature; none of these operators will throw; it's a conscious design choice.
However, that is not to say JavaScript is without footguns. For example, the classic `[1, 2, 3, 10].sort()`.
No one is calling them that except you. The site says it right at the front:
> most of this syntax is probably, and hopefully, not something you use in your daily life.
Your obsession with having to choose Side A or Side B won't let you see this for what it is...
Just showing weird syntax in JS. That's all. Good lord.
However, deciding which language to use for a certain task is a legitimate choice that people to make. When making such decision, people need to analysis the pros and cons of a language. For countless times, I have seen people claiming JavaScript is bad/inconsistent/weird for reasons like `"1" + 1 === "11"` but `"1" - 1 === 0`. All I am saying here is things like these should not weigh too much when deciding whether to use JavaScript.
- you have to package your complete runtime in the Wasm binary, this leads to a large binary and memory footprint
- DOM manipulation requires calling Javascript code, and calling JS from WASM is costly
Languages that perform their own memory management (C, C++, Rust etc) will be extremely small. Just one big array of bytes/instructions.
Further, tree shaking is much harder with a dynamic language.
My understanding is that a WebAssembly implementation would usually be smaller than a JavaScript one, assuming you’re using a language without a runtime.
JS may be weird, but the kind of weird that works well enough and is rather easy to pickup and maintain with reasonable rules in place. When it comes to JS my empirical experience has often been: most of the time, the issue is situated somewhere between the keyboard and the chair.
But guys who control web standards resisted for decades to suggestions for other languages, though it was fine to have flash/activex for the same period of time, until Apple killed it for good. Even JS “2.0” (a theoretical better but incompatible version of itself) had no chance, because reasons.
Javascript is okayish generally, but its unusual parts come from the times when it was used as a glue between textual inputs and some~ data structures.
Stroustrups’ phrase is just a stockholm syndrome (in his case self-induced).
Edit: webassembly support is not really required to transpile anything to a browser, see asm.js
Javascript got popular because it was here first, so developers used it and became able to work with it. When this happens, javascript had inertia which is impossible to stop. Javascript allows one to deploy anything on any platform with a web browser, without copying files.
Webassembly is great, but it's not easy to build WASM files, the toolchain software used (compilers linkers etc) are not mature (only rust can build to WASM natively), and it requires that all language compile to wasm, so compiler developer need to implement a WASM compile "target", which takes time and is not always possible depending on language (python comes to mind, because of its large library, global interpreter lock, etc).
Also, WASM doesn't have access to the DOM or webGL, meaning that you still need to make JS calls to interact with a webpage.
And you could easily copy and learn from scripts before minification became the norm. And you just have to refresh some page after updating your sources to see the result.
In essence, it's very expensive to risk losing backward compatibility or to make large portions of js software obsolete just to remove some bit of language ambiguity.
It's very frustrating but it's true for all languages out there. Same concept when linus torvalds yells "YOU DON'T BREAK USERSPACE". Backward compatibility almost has its own philosophical chapter on software design.
Also remember how painful it was from switching from python 2 to 3. I guess a solution would be heavy usage of linters, typescript or other compile-to-js solution, but in the end, a lot of developers are just wishing very hard for better solutions.
Personally I am really not willing to become a professional JS dev. I'm too perfectionist and nitpicky to have the courage to suffer so much for such thing. Deep down I know it's a bad choice, but I'm too lazy.
I've had the same issues with PHP in the past too, which makes me believe that whosoever created these languages had ease of use as a higher priority than strictness, i.e. it's okay to assign bool, int, string to the same variable.. just get the job done.. okay.
On the other end of the spectrum is a programming language like Pascal (or object Pascal which I used for some time) where I had to write so much boiler-plate code that it made a simple job difficult. Maybe good for big projects but checking if email is valid before form submission, it may be too much boiler-plate code for some people with such traditional languages.
Pure JavaScript is definitely a bit too loose for my liking, but I thought Swift went a bit too far in the other direction.
I worked on a high-profile project for my company under a strict deadline and Swift was a major part in ensuring we delivered a rock-solid implementation in record time.
It's a fun quiz nevertheless, at least for someone like me who is not very proficient in Javascript.
CSS in the console is a nice touch though.
Ty for bringing it to attention. Indeed a cool feature to create emphasis and structure. Haven't bothered with it yet but will consider it. Another cool one is using console.groupCollapsed (as long as you are staying in a callback context).
First time i ever see a form behave like that oO
Every programming language has some weird stuff in it.
If you are writing code like that then you are the problem not the language.
Is this just for the clicks? Is this developer click bait?
What I find sorely lacking is sane syntax for working with arrays. Eyeing Python with envy every time.
And some pattern matching would be nice too.
You can (and sometimes will) run into instances of this without noticing, because while you won't explicitly write
true++
you might do something like x = someFunction()
x++
not realising that someFunction() might return a boolean under some circumstances.Anyone who worked with a sufficiently large JS codebase ran into one of these cases and got unexpected results at some point due to this.
I'll just externalize my embarrassment and say that JS is indeed weird! Another excuse is that I typically try to avoid implicit type conversion except for idiomatic "tricks" such as using !! to convert to a boolean.
Cool website though!
2. One or two of those , questions got me. I don't _hate_ it, but there's a little frustration there. Mostly I just need to know the syntax. If I was writing javascript for money, I imagine it would bite me once or twice, then I'd just memorize the rule.
3 (the biggie) implicit conversion. Oof. seems like a lot of types can be converted to other types, and it's not obvious to me what the precedence hierarchy is. With C I have to look up the edge cases around signed/unsigned, but usually it's just use the next bigger one int -> long. Java does the .toString for everything which has bitten me once or twice. I really don't have a sense of javascript implicit conversion. Some of those seem really subtle.
If you write code like this, you have bigger problems than using JavaScript. For most of the examples, it's like saying "Here's what happens when you plug a fan to a faucet". There's no point really.
JavaScript is weird just like any other language can be weird when you use it in weird ways. And yes, it's certainly one of the weirdest.
If you want to talk about things weird in JavaScript, let's talk about ES modules in Node.js and the Browser, or the number of decisions you have to make to bootstrap a simple web app in JavaScript, and how a language written in 10 days is shipped to billion of devices today.
But, this kind of content, (while well made technically) is always the same one about JavaScript.
So you never did something like this:
x = performCalculation(getParam1())
y = performCalculation(getParam2())
sum = x + y
only to discover that "performCalculation()" sometimes returns a boolean instead of a number? JS is a dynamically typed language after all and functions like function f(x) {
if (x >= 0) {
return Math.sqrt(x)
} else {
return false
}
}
are perfectly valid. If you use a 3rd party library that uses return values like this, you might run into such case without realising it.Sure, you won't explicitly write "true + false", but "f(x) + g(x)" is not uncommon and might indeed evaluate to "true + false".
Also, in this case, the function should return NaN so it's not polymorphic.
Sure. But what if that's function comes from a 3rd party component that doesn't have great documentation or relies on another package and thus a behaviour like this simply bubbles up through the call chain?
And don't think this can't happen - NPM in particular notorious for this kind of deep dependencies. Also mixins and monkey patching are a thing in JS, so just importing a module can lead to an unexpected change in behaviour.
x = checkFoo()
y = checkBar()
z = checkBaz()
if (1 === (x + y + z)) {
....
}
It's a rare construction but I have used it intentionally once or twice in the past decade.The float examples aren’t weird in JS, they’re the same in all languages that use IEEE 754 floats, which specifies that NaN != x, where x is anything.
“This is due to a decision made by the IEEE-754 committee for a few reasons, such as space efficiency and the fact that the function isNaN didn't exist at the time.”
This explanation feels like it’s trying hard to downplay the reasons and make it sound arbitrary and almost whimsical. It doesn’t make sense to allow NaN - NaN = 0 (Note that Infinity - Infinity == NaN), and it’s important that NaNs used as input to computation produce NaNs as output (other than when using boolean tests).
I have been a web dev for about 10 years now and I rarely if ever run into these issues. More likely, I face issues and bugs regarding state and just flaws in the logic rather than issues based on that the language wasn't designed so great.
For sure this can be worrying if you do something really important but at the same time you have a lot of other languages to choose from.
With the advent of linters most of these patterns started being rightfully considered bad form by default.
Currently even innocent stuff like +new Date() (outputs a timestamp) is already something that I've rarely seen make it through review.
JS is goofy, but ES2015 managed to avoid making the same mistakes. Shame it took so long to implement it.
At the moment the bigger problem is the painful transition from whatever module system you had to ES Modules.
Especially browser<->Node.js interoperability suffered massively from this.
Hopefully there will be no further standards in this field.
The scope was just too broad.
I didn't enjoy the quiz, it just reminds me how depressing the base layer of the thing I'm most passionate about in life is. The expression [1,2,3]+[4,5,6] returning what it does is just a bummer, it just sucks. Calling it weird is giving it undue merit, as if it's cute somehow that it's so awful.
> This website is literally about JavaScript. I mean what did you expect, a .NET application? This website is 99.9% poorly optimized and highly questionable JS. And yet, you have JS turned off.
Yes, a website can be about Javascript and still be a collection of documents in web standards, like HTML+CSS, possibly with optional interactive features that could be implemented in Javascript.
I mean, what did you expect? That it is impossible to edit a book on paper about Javascript because obviously paper cannot run Javascript code? Even I have books about Javascript, and they render fine.
const
x = [1, 10, 2],
y = x.sort();
Now: what is the value of x? (Edit: and y?)And that's the first gotcha: sort() is in place.
* Except Object.create(null), which throws.
I think perhaps this "makes the most sense" from a language designer/implementor's perspective, but it also gives ample opportunity for WTF moments in actual use.
If the question is about const, const with Arrays/Objects are by reference rather than value, nothing is stopping them from being modified later in the code.
When is the last time you took an in-person test where the proctor told you if you were right/wrong after every question?
You need to grade current knowledge. In fact, I would have removed the multiple choice altogether for this test and had a input(type=text)
EDIT: OK, ok: I get it, it is just a fun website, not the BAR.
By the time I saw the answers, I couldn't remember why I guessed which way on each question.
> Output: 0
> You answered: I give up
> You answered incorrectly.
No I didn’t.
(Not my fault there were two potentially correct answers!)
The reason is that JS is dynamically typed and thus functions are free to return multiple result types. So you might run into one of these and get unexpected results because at some point in your code one of the functions returned an empty array instead of a number or a boolean, or divided by zero, or...
It's good to at least be aware of these edge cases so you can avoid them.
Biggest problem for JS, from the beginning was people start writing without completely understanding it. Even myself seeing my initial JS code feel embarrassed. Noone understand what is or handle loose typing, prototype, closures, functional concepts like currying before coding. I took almost an year to understand same. Although that time there are hardly my resources like now. But I still see, people directly jumping into JS.
(They’re all empty strings).
The real lesson is that this doesn't necessarily matter, if they're not essential to the code you write most of the time.
Also some of those about floating point math, which is not JS being weird, but rather about needing to know what a float is.
I recently tried to make a simple flask app to sort pictures on my computer. I used file:/// since there were a lot of them.
I was quite unhappy to discover that CORS is quite restrictive...
In a language like Java you have objects and classes at the bottom of the language. How would you add maps to the language? Well, you create a Map class, implement put, get, has methods, etc.
Now imagine a language where you have functions and maps as your basic primitives, but you don't have classes and objects. How do you add objects and classes to the language? You can do something like this: objects are maps, information about their basic class is saved in 'prototype' property, constructor is a function that returns an object, etc. That's how JavaScript works. You can read about this in more details here https://exploringjs.com/impatient-js/ch_proto-chains-classes... , if you keep the basic idea in mind the details are easy to follow.
Works fine in Chrome.
Then we can get into a lot of fun when we get to type systems like SML and Rust where you start to really touch on some power (but can become intimidating). I'm still a bit weary of trying to hop into Haskell.
“11” - 1 = 10
(ノಠ益ಠ)ノ
What would "abc" - "def" mean? Would "abcd" - "bcd" = 0? So it's already an absurd thing to do
Why are we so afraid to call trash "trash"? It's not attacking the creator, but just how can we make progress if things are not perceived as they are?
so that's what it's called.
I've never used it but reading about it I kept going ohh, ahhh and wow! In stead of my standard: ** ** *k * ** *sh?!?
I've never used Elixir so can't say whether the criticisms are justified.
Python has an interesting C FFI interface, among other approaches, that can at least allow CPU and memory-bound tasks to be accomplished inside of a native code module. You see a lot of domain specific work in Python due to these approaches, cython, etc..
Crystal lang is what I would urge all Ruby devs to look at. (an LLVM-based compiled language that has HTTP in it's standard library, for one thing...I'd pit it against Go, for example.)
As I see large front-end teams frequently pushing JS from a typescript base lately, I'm not sure that even the JS community supports "everything JS" anymore. At the point one does backend Node.js work with typescript or other more rigidly typed systems, I have to wonder if targeting V8 is really the desired option any more, and if the programmer would not be better off switching to a high-performance and feature-complete typed backend language system. (the single-threaded JS execution model being a needless constraint at this point, for example. It's great as an event loop)
Given how close typescript is to javascript, wouldn't it be more appropriate to treat it as just a dialect of javascript (like coffescript was) rather than a different language like python or go would be?
1) TS to WEBASM (once JS is out of the picture, might be awhile, lol...)
2) TS as an LLVM IR frontend (compiled TS on the server)
which is basically predicated upon industry familiarity as it's selling point, so yeah, I could see where it's also just a JS industry side-effect. A wart remover, lol
There could definitely be improvements, but trash seems to be taking things too far.
As an experienced Python programmer learning JavaScript, this isn’t true for me yet but I hope it becomes true. I think JS will be much more useful to me than Python.
> Which is fairly easily banned with a linter.
Any particular recommendations?
https://github.com/standard/eslint-config-standard
I would start with that and tweak what you don't like
TypeScript.
I don't understand what this actually contributes to the discussion beyond it being a tired, beaten-down programming meme.
It's ES3 API is missing a few things, like Object.keys, etc. I still happily code for browsers in ES5 with a few polyfill functions.
JS works fine for it's core competency: manipulating DOM elements and local data representations.
It's not JS's fault that the browser is the way it is and that HTTP is the way it is and that using a remote directory "browsing" protocol via a specialized file browser that renders hypertext isn't a 2-way bound GUI framework...
Seems like you had a bad experience with espruino / jerryscript or something and are projecting based on that?
Dynamic languages are easier to program in. That’s a fact, and why they are so popular.
> Dynamic languages are easier to program in.
Only if you don't care about writing correct and maintainable programs. The only thing that dynamic languages make easier is writing code. Or, more specifically, the first couple of versions of it. That's not what typical programming as a process mostly consists of.
Your browser has an embedded scripting engine. Embedded, meaning, the source code for your browser includes the scripting language engine, and JS can run on that and script various permitted things via the browser API.
ES6 may have been ratified six years ago, but it's not the target code your front-end build chain spits out, is it... browsers don't uniformly support it yet. fun facts.
Look, I've been programming JS since it was invented. I'm not impressed by "classes" that don't exist, arrow functions, async/await, futures, promises, fibers, and assorted hacks that don't mirror the actual CODE (what computers execute) a JS engine actually is based upon. I don't need these tools, why should I use something that I need to transpile when I can code directly for browsers as they are in 2021, including legacy browsers? I don't find ES6 "easier" in any way..
Regarding dynamic languages on microcontrollers: Dynamic languages cannot directly control memory allocation and manipulation, typically are heap based and have no concept of a stack frame, and are basically just a computer program written whose corresponding code instructions (machine code) and execution path is scripted by your high-level language. Read a JS engines source code, study embedded C, and get back to me as to how suitable you find it for timing deterministic embedded programming. LOL
Types are directly related to memory size allocations.
Study the recent crop of LLVM languages, including some very interesting ones like LuaJIT, which should be right up your alley, and note the role Garbage Collection (check the Boehm implementation, for example) plays in many of the object-oriented languages, as well as Go.
Look at the actual assembler instructions you require a computer to perform as a result of your high level specification.
I am NOT speaking gibberish.
I agree that dynamic languages are considered easier to program in.
When speaking of programming languages, they are not all on the same level. One cannot say "oh assembler is fine and all but i prefer lua", as it's like comparing apples and atoms.
there's a reason that you can implement a lisp in c, but that the contrary is not viable nor makes any sense. (although metaprogramming c with lisp makes a lot of sense :D)
It didn’t “affect” node, it was the whole reason it came to exist: its cooperative multitasking was a good way to tackle concurrency (remember c10k), and V8 was available and easily embeddable. Without the event loop there would have been no reason to choose JS.
> JS = a single threaded event loop, ON PURPOSE. That directly affected Node.js as an implementation.
That's not a criticism. It's not different to desktop app dev where you try to keep your processing away from the main thread, only it provides an easier interface through async programming. Synchronous = main thread; async = other thread.
Amazingly intuitive model.
> ES6 may have been ratified six years ago, but it's not the target code your front-end build chain spits out
C++14 may have been ratified 7 years ago but it's not the target code your build chain spits out
> Look, I've been programming JS since it was invented...
You're free to write pure assembly, and you don't.
> Regarding dynamic languages on microcontrollers
Python in particular has made this kind of programming mainstream
> Read a JS engines source code, study embedded C, and get back to me as to how suitable you find it for timing deterministic embedded programming. LOL
You're gatekeeping, and that's also your ego. You need to work on that.
> there's a reason that you can implement a lisp in c, but that the contrary is not viable nor makes any sense.
What!? I can build C in Lisp as much as I can build any other language. I parse the syntax, create machine code, and output a binary. How the hell do you think languages are built? How do you think C was built?
Just stop, man. It's not gibberish but it's bullshit.
> Not a comp sci major eh?
I guess you're a comp sci major.
Do you know what a Pointer is?
Do you know what passing by reference means?
Do you know what a heap allocation is vs pushing something into the stack?
Do you know what code and bss segments are and what they are for?
This is not about being right or wrong, I just can’t stand to watch total nonsense go unchallenged.
No, you cannot write a hardware device driver in a dynamic language, which is not to preclude code generation approaches, but to point out what low level hardware programming actually consists of: manipulating memory, registers included
Do you think Arduino would have had any success at all if you had to write C or Assembly to use it?
2) I saw your comment below. You cannot write device drivers in the language of your choice on any of todays popular operating systems, nor on any embedded devices. Device drivers must have low level access to things like memory locations and cpu registers. Such things are not exposed to Javascript and not available. This is not even speaking about performance and garbage collection etc.
Look, Javascript is someones computer program. It can be implemented in very little code: here's an example: https://github.com/cesanta/v7
Languages are not all equal nor do they all function in the same way, and that's not my opinion.
Javascript syntax itself is one thing, and you can certainly feel free to Javascriptify some C++ libraries and make it all look a certain way for specific tasks, while managing things behind the scenes, up to a point... but there is no getting around the fact that SOMEONE and some languages are needed to implement low level systems functionality.
the power of Cython or the Python C FFI is that it allows you to script/glue modular native code.
You then state "C++14 may have been ratified 7 years ago but it's not the target code your build chain spits out"
no, a C++ COMPILER spits out assembler code that then gets assembled and linked into an executable.
The C++ or C code corresponds directly to a given set of assembler instructions which correspond directly to CPU instructions.
You claim that Python programming of microcontrollers is mainstream, but this is not true nor possible. Python SCRIPTING of code modules (that cannot be written in Python) is certainly one way to assemble a system from pre-built legos.
If you refer to knowing what I'm talking about as gatekeeping and egoism, might I suggest that you insist less forcefully in the correctness of incorrect things you state? we could be done with this spat in short order if YOU would refrain from speaking falsehoods. lies.untrue things.
I look forward to your lisp c compiler. make sure that it's 100% lisp from the bottom up, or I'll consider you're having ceded my point. Consider that the lisp you author in has a garbage collection system that lisp cannot have written originally, nor has any semantics for the underlying memory structures of, but hey, I guess if one is committed to pretending that all languages are equal for all tasks, who am I to question ones self-identification with a given language.
You couldn’t have picked a worse example - your CS major seems to be needing a refresh. NodeJS came to be precisely because V8, single threaded and using an event loop, was GREAT at a high volume web servers. It massively reduced the overhead vs multi-process or thread based web servers and absolutely dominated performance benchmarks and concurrency. We started playing with 1M concurrent connections while you might barely get 100 on Apache a few years earlier. There were other async servers at the time (Tornado, Puma, Netty..) but the async-by-default ecosystem in node was a unique advantage.
Fast forward to today, it’s not an accident that the majority of high-performance web servers now are asynchronous and/or using cooperative multitasking (or even libuv directly, a spin-off of nodejs development): VertX, Actix, h2o, Jetty, go with goroutines, etc. It’s a much more efficient model.
2) "you couldn't have picked a worse example" HAAAA! You are wrong. wrong wrong. A) Do you even know what a memory leak IS and why/how it occurs? B) Did you understand what I said regarding stack allocation and out-of-scope equals "memory gone" and how that fundamentally differs from heap-based allocation as ALL JS OBJECTS ARE!??? you are wasting my time, friend.
you are straight up copying marketing lines from node.js with no apparent understand of what a single threaded event loop even is! (it is a gui system. almost all windows-style apps since 199whatever have an event loops as ONE of it's threads. Open X-code or Visual Studio and make a generic desktop app, and add a button and make it's click handler call a method of something or other. Check a moderately complex audio visual production application for clues on just how many threads one uses and for what purposes are they separate threads, etc.)
You then mention VERTX AND GOROUTINES RIGHT AFTER EXTOLLING THE VIRTUES OF A SINGLE THREADED EVENT LOOP. GO LOOK UP WHAT THOSE 2 SPECIFIC TECHNOLOGIES USE AND DO, VERSUS A SINGLE THREADED EVENT LOOP.
Do note why single core limits exist for single hardware thread execution worlds and stop saying that interleaving tasks on a single execution core is superior to architecting synchronized activity across all cores, and do note that you are primarily referring to CRUD web-dev while positing very erm controversial positions on programming language use-cases.
Node JS is a terrible high-volume web server as all of the alleged virtues you extol are workarounds from the single threaded execution model of what was never designed to be a server language. I will say it again: HTTP is a stateless protocol involving a request (method call) and response (what it returns) it then goes out of scope and disappears. no memory leaks. no heap memory allocation. no malloc. no new, etc. it's just poof gone. got it? this was done on purpose by smart computer people. If you want to run each request as a separate OS process, don't blame HTTP, but the primitives were designed for efficiency.
please DO look up what heap vs stack allocation is. please DO look up what a register vm vs a stack vm is. please DO not confuse scripting or glue code with machine code, as the machine code of your javascript program is precisely the javascript runtime with it's execution paths being puppeted by your script language. you are literally pushing someone elses buttons and calling it computer programming. no offense, that's why it's a high level language not a low one.
when you resort to reductio ad absurdum suggesting assembler as the tool for all programming, you are not engaging with anything I have said or written here, as tools have purposes, not everything is a hammer/nail
in a way, you are not wrong, as a macro-assembler, or C or C++ or Rust or Zig or Nim etc (non garbage collected compiled language capable of outputting machine code as the final target) is the next level up from asm.
Why do you suppose that Chrome is not written in JS but rather largely in C++?
I don’t know what you’re excited about yelling in caps - VertX uses and event loop. Goroutines are cooperative scheduling. Yes, they can also coordinate over multiple threads (guess what, node can too) but the underlying architecture for processing requests is the same.
> Node JS is a terrible high-volume web server
Again, why would that be? Node was invented precisely to be a high performance server. It’s literally it’s purpose, and it delivers. Check out any benchmarks like TechEmpower and guess which platforms you’ll find near the top. I’m not saying it’s the best choice but just stating facts. Nothing else to say here - you obviously have strong opinions but zero hands-on knowledge on this area.
JS is a great programming language with a lot of quirks and footguns, most of them easily avoidable by enforcing good coding styles, using easily available and widespread tooling.
And most language have linters or compilers that issue coding-style related warnings, including C, so this is not specific to Javascript.
There are also great things about it: the ease at which one can write in a functional style code, anonymous functions (vs Python), closures (vs Java), immutable strings, the fact that there is not a shitload of classes to instantiate to achieve anything (vs Java), block-scoped variable definitions, sane default function parameter handling (vs Python).
Javascript engines are also very fast nowadays because of the ton of engineering going into them.
I'd say, above all arguments, you can rapidly build very fast, lightweight and program programs with it.
Sure, you can pull a shitload of pointless dependencies and write bloatware that re-render the world on each keypress, and that's what many people do. And to make things worse, they wrap their shit with an entire browser that uses a lot of ram and processing power. But you are not forced to do that. You can also write efficient server code that does not show up in top, has few dependencies if at all, consume a negligible amount of memory and run without failure for months. That's possible too. Frontend-wise, you have amazing frameworks like Svelte that do wonders and would allow you to build very lightweight apps rapidly.
That said I would often pick TypeScript so your program is statically type-checked and your code is documented through types, especially for more-than-one-person / non-trivial projects.
I also use and like other languages like Python and D (and a bit of Rust) that have good stuff which JS doesn't have (list comprehension, borrowing, traits, named parameter, sane coercion to False…), or bad stuff which JS has. Javascript is not always the best answer, or even a good answers, but it can be one.
JavaScript has a bunch of quirks, but it's still great. In the StackOverflow survey, JS reliably ranks highly in the list of "most loved" languages. https://insights.stackoverflow.com/survey/2020#technology-mo...
Node.js is a thing because people liked JS so much that they wanted to use it on the server side. You may think they're all fools, but it's actually pretty nice. I like the latest version of Node better than working in Python (mostly because node_modules are better than virtualenvs, IMO.)
You can use TypeScript to address many of the quirks described in TFA, but you can also reliably avoid them just by never using == and always preferring ===, using String() before using + to concatenate, and using Number() before subtracting.
I basically never encounter situations like the ones depicted in TFA in real code, because I never try to add two arrays or subtract two strings or what have you.
“Admitting like this has a bunch of quirks, but it’s still great.” (not arguing for it though)
Criticism is a driving force behind change to the better. Calling something “great” without pointing out great sides I find… pointless and harmful.
To name a few great points, distinct from other languages:
JS has a pretty shameless object model, where you (usually) have ordered keys, and every key is a property with an {enumerable, writable, configurable, get, set} descriptor. It is much more usable and practical than in almost all other languages. (They do that for “efficiency”, but that’s non-sequitur)
JS has very useful destructuring syntax, which many languages lack of and that leads to assignment bloating and boredom. Also, jit optimizes out temporary objects, so foo({x, y}) / function foo({x, y}) works almost at the same speed as foo(x, y).
JS has a nice Function type, which allows easier metaprogramming and substitution of ‘this’ object. Functions are objects, so you can function foo() {}; foo.x = 1; console.log(foo.name, foo.x).
JS bare objects may have methods and properties: t={_x:1, get_x(){return this._x}, …}
JS doesn’t treat syntactic lists in a last-value-only way, so you can expect foo(…a, …b, c) to work, and to work as intended. E.g. Lua cannot do that, and python (afair) requires you to collect items into a single array (not sure, correct me if I’m wrong).
But what people usually mean by “great” is “it generally works”. I know it is an american thing, but some aspects of js, including those you meet everyday, are really just trashy. It would be nice to not have them at all.
> how can we make progress if things are not perceived as they are?
People aren't blind to JavaScript's failings. The evolution of JavaScript has been a mix of adding new features and fixing what they got wrong before, e.g. the way it has two different isNaN functions. [0]
[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
It's odd, there are developers who make the language they work part of their identity and see attacks on that language as attacks on their identity.
I don't get it, but it is what it is. If you call javascript trash, you will offend people.
Basically, it was meant to be a dialect of Scheme, but with map and array data structures at the bottom, as opposed to lists (hello, Clojure!). Suddenly, the last-minute decision was made to add Java-like syntax and OOP to this language and rebrand it as 'JavaScript'. Brendan Eich did the best he could in the limited timeframe to implement this. Then in 2015 'design-by-committee' approach was accepted and horrible feature creep started. We can then investigate every feature and how it pushed individual company's agendas while compromising the integrity and vision of the language, but that's a typical design-by-committee story.
I have no idea how you could come up with this sentence after this brilliant display of what an insanely stupid language JavaScript is.
C, C++, Perl (oh, Perl!) allow you to do weird things, too, so do lots and lots of other languages.
A certain knowledge of this weirdness is very helpful, though, in avoiding it.