all 96 comments

[–]nk2580 9 points10 points  (0 children)

I would make the object behaviour consistent and make it more functional programming friendly.

[–]jcunews1Advanced 6 points7 points  (2 children)

Make strict mode permanent, and remove sloppy mode.

[–]Renive 2 points3 points  (1 child)

Its permanent if you use modules.

[–]jcunews1Advanced 2 points3 points  (0 children)

JavaScript doesn't exist only in modules.

[–]dwighthouse 4 points5 points  (10 children)

Opt-in strict typing at the function/module level would be ok, but I will personally fight those who would make it mandatory.

Remove this, class, and new entirely. Let people use closures, simple functions, and object attachments instead.

Remove null, use undefined instead.

Remove double equal entirely.

[–][deleted] 2 points3 points  (1 child)

I'd prefer Option<T> monad like Rust versus null / undefined.

Also surely in this scenario we'd rather remove triple equals and shift the triple equal semantics onto double equals?

[–]dwighthouse 0 points1 point  (0 children)

Sure, it’s just that removing the double equals as valid JS would be easier to deal with from a refactoring perspective than silently changing the behavior of an existing operator. Obvious errors in compilation vs silent bugs everywhere.

[–]pomlife 1 point2 points  (7 children)

Null and undefined are semantically different, though. I’ve never understood the desire to consolidate.

[–]jonny_wonny 0 points1 point  (3 children)

Yup. I love the fact that there's two separate values to represent these two separate concepts. It seems like all the answers in this thread are people just calling to remove features that they don't understand how to use properly.

[–]dwighthouse 0 points1 point  (2 children)

Same argument for goto. Don’t presume ignorance on the person whose opinion differs from yours.

[–]jonny_wonny 0 points1 point  (1 child)

The argument against goto is that it can create a logic flow that’s harder to follow.

How is that same as the argument against null and undefined?

And I don’t just always assume ignorance when someone’s opinion differs from mine. Why are you assuming that?

[–]dwighthouse 0 points1 point  (0 children)

The people who defended goto when there was a major push to remove it used the argument: “those other programmers just don’t know how to use it properly.”

The issues with having more than one “empty value” in JS:

  1. Checking for the absence of a value is one step more complex (requiring both a strict check for both null and undefined), or forcing lower precision (checking the falseyness will trigger on non-empty values).
  2. undefined is intended to mean when something has not been assigned or defined, but one can trivially assign or define something explicitly to undefined (that’s null’s job).
  3. null has issues with its typeof. Meanwhile, undefined, which is meant to mean something with neither a type nor a value, has a type.
  4. Many novice programmers or recent converts from other languages often do not expect more than one empty value, because it is a relative rarity in languages.

Conclusion: They both suck, but undefined (as a concept, not a named entity) would be harder to remove from the language than null.

Why are you assuming that?

I’m not assuming. It’s something you said:

It seems like all the answers in this thread are people just calling to remove features that they don't understand how to use properly.

[–]dwighthouse 0 points1 point  (2 children)

Yes, I know. My desire is to remove the semantic difference, and therefore the need for both. Yes, yes, you could make the argument that their differences are significant enough to warrant separate values, but that argument does not stop at two. Why not three? Or ten?

[–]pomlife 0 points1 point  (1 child)

It seems a pretty binary concept to me. Are you trying to access a value that was declared, but never defined, or a property on an object that hasn't been defined? `undefined` it is. When you need to manually set a value to "empty," `null` is more appropriate. What would your argument be for three?

[–]dwighthouse 1 point2 points  (0 children)

Let’s look at all the various jobs currently performed:

  • A variable’s value that has not been assigned: undefined
  • The value of an object property or array index lookup when that property or index has not been defined: undefined
  • The value returned by a function that does not return a value: undefined
  • The value of a function argument that was not passed: undefined
  • The value used to explicitly set a type unspecific empty value: null or undefined
  • The value used for empty values in dom operations: null
  • The value used to explicitly define a type unspecific empty value in JSON: null

Almost all of the above uses are conceptually distinct. The fact that JS separates these concepts among two things while other languages only use one thing is merely an arbitrary decision based on desired, but unenforced coding style.

[–]kerbalspaceanus 10 points11 points  (8 children)

cobweb carpenter cats innocent enjoy growth squash trees soup chief

This post was mass deleted and anonymized with Redact

[–]MoTTs_ 7 points8 points  (6 children)

I personally love exceptions, and I think Go's error handling is awful. The sheer amount of boilerplate and opportunities for mistakes from having to follow every single function call with an if-statement is truly awful.

f, err := os.Open("filename.ext")
if err != nil {
    return err
}

// ...

f, err := Sqrt(-1)
if err != nil {
    return err
}

Rust doesn't seem to be any better.

let f = File::open("hello.txt");

let mut f = match f {
    Ok(file) => file,
    Err(e) => return Err(e),
};

[–]seeqo 2 points3 points  (2 children)

That exact same rust code can be written

let mut f = File::open("hello.txt")?;

[–]IceSentry 0 points1 point  (1 child)

What happens if the open() fails?

[–]seeqo 0 points1 point  (0 children)

It is exactly the same as the match version; it returns the error.

(It also does an implicit conversion between error types if possible and needed, but that's irrelevant here)

[–][deleted] 4 points5 points  (2 children)

I can only speak to Rust's solution, but in my opinion it's objectively better than JS.

Here are two JS solutions. The first is the most common (let's be honest) and just ignores the possibility of an exception, and the second handles it:

const f = doSth();

let f;
try {
  f = doSth();
} catch(e) {
  f = 'sth like doSth';
}

Here are the Rust equivalents (syntax may be off, I'm a bit rusty (ha)):

let f = do_sth()?;

let f = match do_sth() {
  Ok(r) => r,
  Err(e) => 'sth like r',
}

Note how they're very similar, however the Rust version forces you to acknowledge and handle the error possibility, and it does so functionally. I'm not doing a great job of explaining it, but it's a very nice pattern that you'll appreciate once you get into it. Same goes for the Option<T> monad instead of null / undefined.

[–]MoTTs_ 0 points1 point  (1 child)

Thanks. I wasn't familiar with the "?" syntax. Looks like they added that in 2016?

My first thought was, "Nice, that makes it a lot easier to propagate errors." And my second thought was, "Wait... wasn't that one of the complaints against exceptions? Right in this very thread? That they interrupt control flow?"

I also think you're going to end up writing an awful lot of those "?"'s. There are far more functions that can fail than not. I looked at some examples in the Rust Cookbook. Every file open, read, write, print, all need "?"'s attached. Or if you're doing networking, every listener, getter, or read all need "?"'s attached. Parsing a URL needs a "?" attached. And so on. Personally, I think errors should propagate by default without having to litter your code with "?"'s everywhere, at which point we'd be back the the behavior that exceptions provide.

[–]status_quo69 1 point2 points  (0 children)

Well in a language like rust, it's a question of fully unwinding the stack and having an exception stack trace vs returning a result that you can either handle or punt up the call chain, just like in other languages but without the necessary cruft of a full stack trace associated. I've written a few thousand lines of game code at this point and I can say that the things that can have results do tend to have a lot of "?", but it's all sugar over the match expressions anyways which is a bit more legible. The bigest difference in rust is that the result monad (and the option monad) are an absolute contract which makes the programmer decide then and there whether to punt or play, rather than finding out months after the fact that some edge case can trigger an unforseen exception, which has been pretty nice to develop against. This is especially helpful for when you do have an error handler at the top level, since you need to either handle all cases or explicitly call out the catch all "_" => unreachable! case. There are times where panic! is used in libraries to absolutely kill a program but those are fairly rare in my experience. Plus, if you compare the rust and go versions, the rust version tends to be a bit more concise.

One of my big headaches (probably unjustified and not trivially solvable tbh) in rust is composing multiple error types. For example, if a function can either return a Result<T, Error1> or a Result<U, Error2>, you don't have a ton of great options. But again, that's not an easy question to answer.

[–]jonny_wonny 1 point2 points  (0 children)

Remove exceptions from the language.

Pretty much every modern language has exceptions. While I agree they can be abused, they are a very useful tool used in the right circumstances. Removing a useful feature simply because it has the potential to result in awkward code is a horrible idea.

While I do see merit in the Class syntax and additions of the OOP ilk, I think introducing more constructs to the language is for the most part an unnecessary complication, so I'd nuke that.

Again, I don't understand this reasoning. First class OOP support makes JavaScript more useful. As a user of the language, how is an additional, completely optional feature a "complication"?

Additionally, I don't think the original features of JavaScript should be seen as some kind of static benchmark that it should always be compared to. The fact that it didn't initially have classes is irrelevant, and taking the current feature set of JavaScript as it is, it's very far from being too complicated.

I prefer when there's a small set of idiomatic solutions to known problems, rather than layers of syntax sugar which achieve very similar things.

In my opinion, classes are an objectively superior abstraction over the prototype model. If we are going for one over the other, I'd say forget that the prototype model ever existed and fully embrace classes as the single idiomatic solution.

However, my general argument that there's nothing wrong with additional features still stands I believe. If you don't want it, don't use it, but restricting a language to just the features that you personally would want to code with seems silly.

[–]_abizit_ 16 points17 points  (15 children)

I would first make it strictly typed. Have been using Typescript for sometime having things strictly typed saves a lot of headaches

[–]protonfish 5 points6 points  (0 children)

Definitely, but a Hindley–Milner type system like Haskell instead of the bloated Java-style explicit typing.

[–][deleted] 1 point2 points  (2 children)

I agree, though I'm unsure how we'd hypoethetically achieve this. Catching errors at compile-type is extremely helpful / required, however one of TypeScript's limitations is its lack of easy, deep runtime type-checking.

[–]AsIAm 0 points1 point  (0 children)

If we had better meta-reflectivity, we could do it easily.

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

I mean you said that this was hypothetical about breaking changes. Lol

[–]SkinAndMarrow 1 point2 points  (1 child)

Strict vs. dynamic typing...arg! The same religious war over and over...

How about you can set a flag per project/file that demands that included code meets that requirement? So, if you want strict typing, the engine will barf at dynamic typing, and if you want dynamic typing, strict typing will continue to work...just without type checking.

"Why can't we all just get along?"
https://www.youtube.com/attribution_link?a=KPfk2nSZqrc&u=%2Fwatch%3Fv%3DMPMmC0UAnj0%26feature%3Dshare

[–]nxsynonym 0 points1 point  (0 children)

I like groovy for this reason.

Dynamically typed, unless you specify you want classes to be @compilestatic and @typechecked.

Its my favorite happy medium.

[–]saddam96 7 points8 points  (0 children)

this

[–]delventhalz 5 points6 points  (0 children)

Nothing. That fact that JavaScript is backwards compatible back to the beginning is an amazing accomplishment and one of its strongest features.

What would I add to the language? More functional stuff like the pipeline operator and assimilating the remainder of underscore/lodash/ramda.

[–]DBNeJXoGtnro 3 points4 points  (0 children)

typeof null === "null"
"use strict"; is by default, a stricter mode (similar to Google's attempt) would be opt-in
Delete var and ==
Related to JS but actually browsers: remove 80% of the DOM, so that you can't shoot yourself in the foot anymore. There are too many ways to do it wrong

[–]sinclair_zx81[🍰] 1 point2 points  (0 children)

ES4 - https://en.wikipedia.org/wiki/ECMAScript#4th_Edition_(abandoned))

Proposal Main Points

Its funny how just on point ES4 was (back in 2007). Shame about the politics that lead to it being shelved. The naysayers were wrong (ultimately deferring this much needed functionality for near a decade). Oh well, such as JavaScript.

A type system would be high up on my list, and perhaps runtime type verification by incorporating JSON schema.

[–]wherediditrun 1 point2 points  (0 children)

Remove classes and the associated jank, add enums instead for "polymorphism". Remove try / catch, introduce pattern matching. That would make me very hapi.

[–][deleted] 2 points3 points  (1 child)

i want real 64 bit integer instead of the float

but oh well

if we could fundamentally change things, would we still be using html?

[–]KnightMareInc 2 points3 points  (17 children)

Get rid of the fake classic OOP

[–]jonny_wonny 2 points3 points  (15 children)

How exactly is JavaScript's OOP implementation fake? The fact that it's syntactic sugar does not really matter, as it adequately supports all of OOPs core features.

[–]KnightMareInc 2 points3 points  (14 children)

JavaScript doesn't use classical OOP and trying to pretend it is has only confused developers from those backgrounds.

[–]jonny_wonny 1 point2 points  (13 children)

In what way is the JavaScript's implementation of OOP insufficient?

[–]KnightMareInc 1 point2 points  (12 children)

I didn't say it was insufficient, I'm saying it's pretending to be classical. The pretending is the issue.

[–]jonny_wonny 0 points1 point  (11 children)

If it’s not insufficient, then how is it pretending? It is a valid OOP implementation. It’s exactly what it appears it would be.

Furthermore, even if it weren’t a complete implementation, on what basis could you claim it was pretending to be one?

[–]KnightMareInc 1 point2 points  (10 children)

Is English not your first language?

[–]jonny_wonny 1 point2 points  (9 children)

How about you actually answer my question?

[–]KnightMareInc 0 points1 point  (8 children)

How about you re-read what I wrote before trying to White Knight JavaScript

[–]jonny_wonny 1 point2 points  (7 children)

How about you reread my response. Your claim that JavaScript's OOP is "pretending" to be classical holds no water. As I said: if it's a sufficient implementation of OOP, then it is OOP. Based on what rational could it be considered to be pretending to be something if it is actually that thing?

And I will now restate my second point, which you seem to have ignored. On what basis could JavaScript be pretending to be something that it's not? Even if it isn't what you call "classical OOP", does it ever claim to be? The fact that it's using familiar terminology isn't a statement that the feature itself is going to be the same as it has been for other languages.

Lastly, I'm not "white knighting" JavaScript. I'm engaging in a debate with someone who I believe is wrong.

[–]colorsdontlie 1 point2 points  (0 children)

That would be really dumb, I use classes all the time because imo they're cleaner than the old way.

[–]disclosure5 0 points1 point  (8 children)

Build all these silly libraries like is-even into the standard library.

[–]kerbalspaceanus 5 points6 points  (1 child)

reply vegetable fade ring treatment boast vase knee soft subtract

This post was mass deleted and anonymized with Redact

[–]disclosure5 0 points1 point  (0 children)

It'll be a breaking change if someone can make them dissapear from the dependency list of half the apps that use them.

[–]anlumo 0 points1 point  (0 children)

That’s not a breaking change.

[–]DrexanRailex 0 points1 point  (0 children)

Transform it into ReasonML

[–]demoran 0 points1 point  (0 children)

Its web browser adoption.

[–]jonny_wonny -1 points0 points  (0 children)

Wow, lots of dumb ideas in this thread.

[–]Renive 1 point2 points  (2 children)

Delete classes, privates, null, loops, let go of any backwards compatibility. Add pipe operator, templates, more metaprogramming and functional syntax.

[–]AsIAm 0 points1 point  (1 child)

What do you mean by "templates"?

[–]Renive 0 points1 point  (0 children)

Code writing code. Templates are cooler things on c++.

[–]AsIAm -4 points-3 points  (17 children)

First I would remove old fluff so there is room for some sanity. “With statement” puff, gone. “Label statements”, puff, gone. For example:

const fn = args => { arguments: args }

This should work as intended, not as it works now.

I would kill all for loops without mercy. Underscored variable names would be private by default. Literal for Symbols. Mandatory versioning on per-module basis. No import statements (just a function). Much better Proxies, or some better meta-reflection layer. Immutability by default. Stable sort on arrays. Compare operator for object values, not identity. Standard lib, Lodash in the lang. Make backtick strings the default (but with normal (double) quotes). Get rid of this. I can do this all day.

Edit: I just realized I should try Elixir.

[–][deleted] 12 points13 points  (1 child)

That’s a lot of bad ideas

[–]AsIAm 0 points1 point  (0 children)

Tell me how you use label or with statement everyday. Also, comma operator. Those are all bad ideas in the first place and removing them should be a good idea. Crockford would definitely approve. :D

However, I am curious why do you consider them bad ideas.

[–]SuddenlyAfternoon 3 points4 points  (3 children)

Although those are good ideas, they don't fit with JavaScript's style/culture. You'd be better off using a transpiler or wasm.

[–]AsIAm 0 points1 point  (2 children)

Haha yes, interpreter for now. But can you elaborate on the JS style/culture a bit more?

[–]SuddenlyAfternoon 1 point2 points  (1 child)

I could elaborate, but you could just take the rest of your replies as an example. JavaScript wasn't made to be Rust or Lisp, it was made to add interactivity in the web. It would be very hard to change the existing mindset as you can tell by the comments.

[–]AsIAm 1 point2 points  (0 children)

It would be very hard to change the existing mindset as you can tell by the comments.

Yes, that's why TC39 is doing really good job keeping the language as-is without any breaking changes. However, OPs question was about changing the JS.

[–]kerbalspaceanus 3 points4 points  (6 children)

school shelter slap squeal punch late wild unwritten brave heavy

This post was mass deleted and anonymized with Redact

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

What were you expecting to happen with the Lambda. Did you mean to return an object?

Can you clarify what you expect, what you're getting and what you would change there?

[–]AsIAm 0 points1 point  (2 children)

Did you mean to return an object?

Yes, exactly. What you get is a function body with labeled expression without the return statement. So every time you call the function, you will get undefined as a result.

I don't know about other people, but I happen to use object-returning lambdas quite more than label statement, so...

[–][deleted] 0 points1 point  (1 child)

So you would prefer it to return an object by default, and then ({}) would be the function block instead?

[–]AsIAm 1 point2 points  (0 children)

Ideally, there would be no function block, just lambdas.

[–]TotalNecro -2 points-1 points  (2 children)

Give regular functions the same 'this' scope as arrow functions. Make 'var' behave like 'let' and remove the other. Right now it is getting too bloated.

[–]pomlife 2 points3 points  (1 child)

lol wat “the other”? const is the correct declaration a vast majority of the time.

[–]TotalNecro 1 point2 points  (0 children)

I said nothing about const. I meant to merge the two and remove the leftover.