Proposal: JavaScript Structs

82 pointsposted a day ago
by Kholin

73 Comments

leetharris

2 hours ago

I am not sure how to really refine this thought I have had, but I have this fear that every language eventually gets so bloated and complicated that it has a huge barrier to entry.

The ones that stand out the most to me are C# and Typescript.

Microsoft has a large team dedicated towards improving these languages constantly and instead of exclusively focusing on making them easier to use or more performant, they are constantly adding features. After all, it is their job. They are incentivized to keep making it more complex.

The first time I ever used C# was probably version 5? Maybe? We're on version 12 now and there's so much stuff in there that sometimes modern C# code from experts looks unreadable to me.

One of the reasons I have so much fun working in node/Javascript these days is because it is simple and not much has changed in express/node/etc for a long time. If I need an iterable that I can simply move through, I just do `let items = [];`. It is so easy and hasn't changed for so many years. I worry that we eventually come out with a dozen ways to do an array and modern code becomes much more challenging to read.

When Typescript first came out, it was great. Types in Javascript are something we've always wanted. Now, Typescript is on version 5.6 and there is so much stuff you can do with it that it's overwhelming. And nobody uses most of it!

This is probably just old man ranting, but I think there's something there. The old version I used to debate about was C vs C++. Now look at modern C++, it's crazy powerful but so jam packed that many people have just gone back to C.

BiteCode_dev

19 minutes ago

Javascript is not simple AT ALL.

It has 3 ways to declare functions, multiple variations on arrow functions syntax, a weird prototyping inheritance system, objects you can create out of "new" on functions, object literals that can act an pseudo classes, classes, decorators, for i loop + maps + filter + for in loop (with hasOwn) + forEach, async / await + promises and an invisible but always on event loop, objects proxy, counter intuitive array and mapping manipulations, lots of different ways to create said arrays and mappings, very rich restructuring, so many weirdness on parameter handling, multiple ways to do imports that don't work in all contexts, exports, string concatenation + string interpolation, no integer (but NaN), a "strict mode", two versions of comparison operators, a dangerous "with" keyword, undefined vs null, generators, sparse arrays, sets...

It also has complex rules for:

- scoping (plus global variables by default and hoisting)

- this values (and manual binding)

- type coercion (destroying commutativity!)

- semi-column automatic insertion

- typeof resolution

On top of that you execute it in various different implementations and contexts: several browser engines and nodejs at least, with or without the DOM, in or out web workers, and potentially with WASM.

There are various versions of the ECMA standard that changes the features you have access to, unless you use a transpiler. But we don't even touch the ecosystem since it's about the language. There would be too much to say anyway.

There are only two reasons to believe JS is simple: you know too much about it, or you don't know enough.

wk_end

8 minutes ago

I feel like a large slice of JS’s complexity comes from footguns you aren’t really supposed to use anymore; whereas with C# the complexity feels quite layered, multiparadigmatic, something-for-everyone, syntactic-sugary. But I probably know too much about JS and not enough about C#.

BiteCode_dev

2 minutes ago

Well, all the people that used JS 15 years ago followed Douglas Crockford advice very much to heart.

nwienert

14 minutes ago

This is true, but what's also true is using biome or eslint more than half of your complaints are gone. JS has always had bad parts, but today it's a lot easier to avoid them thanks to linters. And if you do stay in the good parts, it's my favorite language, for many reasons.

That said, I hate the constant stuffing of features (though not this one which is much needed), more stuff around JS like WebComponents, or CSS adding a ton of sugar.

liveoneggs

10 minutes ago

It's on the list of languages that used to be simple, I think.

BiteCode_dev

4 minutes ago

Yes, but when "the good parts" came out, half of this list was already true.

There is a reason we ignore a good chunk of the language to be productive with it.

afavour

an hour ago

I think in this specific case it's JavaScript's requirement for backwards compatibility that bloats it... but there's a lot you can ignore. Like, you can declare a variable with var, let or const but there's absolutely no reason to use var any more. I feel similarly about the proposals to introduce records and tuples: https://github.com/tc39/proposal-record-tuple... in most scenarios you'll probably be better off using records rather than objects, and maybe that's what folks will end up doing.

But boy does it all get confusing.

> Now, Typescript is on version 5.6 and there is so much stuff you can do with it that it's overwhelming. And nobody uses most of it!

I'm not so sure about that. I think we end up consuming a lot of these features in the TS types that get published alongside libraries. We just don't know it, we just get surprisingly intuitive type interfaces.

hinkley

7 minutes ago

When they made class declarations imply strict, I thought that was a pretty wise move. But it might have been good if they applied more limitations than that, made them super-strict.

Such as for instance making 'var' not work in class declarations.

leetharris

19 minutes ago

> I'm not so sure about that. I think we end up consuming a lot of these features in the TS types that get published alongside libraries. We just don't know it, we just get surprisingly intuitive type interfaces.

Very true. As a downstream consumer, I can do all business logic in ancient, simple languages. But I'm sure these things are extremely nice to have for the more complicated upstream dependencies I rely on.

thot_experiment

an hour ago

> but there's absolutely no reason to use var any more

Naw, var has function scope and hoisting, both of which are useful.

hinkley

3 minutes ago

My job isn't to be infatuated with your code. It's to get through your code and get stories done.

People don't really get better at handling the complexity of large code bases. We are fundamentally the same organic matter that existed prior to the first computer coming into existence. So as code bases and library bases grow larger and larger, they need to be proportionately easier to read or even ignore.

Your code needs to be dead boring 90% of the time, otherwise you're imposing on your coworkers. And using variables before they're declared is just shitty behavior.

afavour

an hour ago

Not in a sensible codebase

munificent

8 minutes ago

I've been meaning to write a longer essay on this for years, but I believe the reason for this observation is different cohorts.

Imagine you are a C# programmer just as C# 1.0 is released. C# is a fairly simple language at that time (and similar to other languages you already know), so you can get caught up on it fairly easily and quickly. A few years later, C# 2.0 comes out. It's got a handful of features, but not too much for you to absorb. Likewise C# 3.0, 4.0, etc. As long as you stay on the C# train, the rate of new features does not exceed the rate that you can learn them.

Years later, another person comes along and is new to C#, which is now at version 5.0. They are presented with a huge sprawling language and they have to learn nearly all of it at once to deal with codebases they are contributing to. It's a nightmare. They long for a language that's actually, you know simple.

So maybe they find some other newer language, Foo, which is at 1.0. It's small and they learn the whole thing. After a couple of years of happy productive use, they realize they would be a little more happy and productive if Foo had just one or two extra little features. They put in a request. The language team wants happy users so they are happy to oblige. The user is easily able to learn those new features. And maybe some other Foo users want other new things. 2.0 comes out, and they can keep up. They can stay on the train with 3.0, 4.0, etc.

They never explicitly asked for a complex language, but they have one and they're happy, because they've mastered the whole thing over a period of years. They've become part of the problem that bothered them so much years ago.

Fundamentally, the problem is that existing users experience a programming language as the delta between the latest version and the previous one. New users experience a programming language as the total sum of all of its features (perhaps minus features it has in common with other languages you already know). If you assume users can absorb information at a certain fixed rate, it means those two cohorts have very different needs and different experiences.

I don't think there's a silver bullet. The best you can hope for is that a language at 1.0 has as few bad ideas as possible. But no one seems to have perfect skill at that.

dgellow

29 minutes ago

Do you have examples of unreadable C#? The language didn’t change much IMHO. You have new features, like records, but C# code looks pretty much like what I started with in 2009

leetharris

11 minutes ago

Now that I'm thinking about it, most of it is probably .NET bloat instead of C# bloat, but a few examples would be global usings, file scoped namespaces, records, target-typed new expressions, null coalesce assignments, etc. It's nothing huge, but combined with .NET bloat it can be overwhelming when you haven't worked in .NET for a while.

eddd-ddde

an hour ago

This is why always say the true beginner programming language is C.

Stupid easy to learn, have some loops, have some conditions, make some memory allocations. You will learn about the fundamentals of computing as well, which you might as well ignore (unknowingly) if you start with something like JavaScript (where is this data living in my computer?).

lukan

19 minutes ago

And this is why I always say, we have a world full of computer consumers, not programmers.

C as a first language is only easy, if you happen to bring along a deep technical interest (and pre knowledge) about the "technical fundamentals of computing".

Most people do not have that.

Tell them about heap and memory allocations and you will get a blank stare.

But show them some simple functions, to make some flashing graphics on the sceen - and they will have fun. And can learn the basics of programming at the same time.

And then you can advance more low level, for those who feel the call. But please don't start with it, unless you have some geeky hacker kids in front of you who really want to learn computers. Then C makes sense. For "normal" people not so much.

n_plus_1_acc

40 minutes ago

How can you teach C when there's no list of UB, there's sometimes no agreement on how to read the standard, and loads of non-standard-compliant compilers.

bobthepanda

20 minutes ago

Plenty of universities teach C every day even if that means specifying a compiler, and usually it’s a very boring compiler that gets chosen

throw49sjwo1

2 hours ago

> And nobody uses most of it!

Everybody who does Express, React, or any other popular advanced libraries with TypeScript is using these features. Some things are simply more useful to libraries than line of business code - that's fine. The line of business code is much better thanks to it.

leetharris

16 minutes ago

> Everybody who does Express, React, or any other popular advanced libraries with TypeScript is using these features.

This is very true and my original post was short sighted. You could, of course, make most upstream dependencies without modern language features. However, their complex jobs get much easier with these features.

Downstream, business logic is much easier to implement without these features compared to complex, low level functionality.

anon7000

24 minutes ago

For sure! In a basic API endpoint, I don’t need advanced typescript features.

But if I’m writing a module that a lot of other consumers in the codebase will use, and I want to make their lives easy, I might use a lot of advanced TS features to make sure than type safety & inference works perfectly within the module. Whoever consumes it can then rely on that safety, but also the convenience. The module could have some convoluted types just to provide really clean and correct auto-complete in a certain method. But most people don’t need to worry about how that works

tannhaeuser

an hour ago

React and Expressjs predate typescript, Expressjs considerably so.

throw49sjwo1

an hour ago

Doesn't matter, I'm talking about the type definitions - @types/react, @types/react-dom and @types/express.

authorfly

12 minutes ago

No, those are optional for the enduser to ever encounter.

nosefurhairdo

an hour ago

Yeah I was confused by this point as well. Especially because many of the recent Typescript releases are just improving performance or handling more cases (without needing to learn new syntax).

egnehots

31 minutes ago

Try Go. Go is really stable as a language and have a very small core feature set.

leetharris

18 minutes ago

This is easily the most appealing thing to me about Go. I learned Go through the "Learn Go with Tests" way and I had a ton of fun.

It is hard for me to recommend using Go internally since .NET/Java are just as performant and have such a mature ecosystem, but I crave simplicity in the core libraries.

Here's the link for anyone considering learning Go: https://quii.gitbook.io/learn-go-with-tests

carlosrg

9 minutes ago

Every programming language attempts to expand until it becomes C++. Those languages which cannot so expand are replaced by ones which can.

goatlover

4 minutes ago

Go will resist this as long as possible.

pier25

34 minutes ago

> or more performant

Obviously then can't make TS more performance (since it doesn't execute) but C# is very performant and even surpasses Go in the TechEmpower benchmarks.

leetharris

21 minutes ago

Absolutely. I love C# and .NET, they are incredible and very fast. I just meant to say that they aren't only focused on performance, but also focused on new features.

One of the best things .NET did was adding minimal APIs in .NET 6 (I think) that are more like Express. They removed a lot of boilerplate and unnecessary stuff, making it easier to start building an API.

dartos

an hour ago

At least typescript tooling hasn’t changed. It was a pain to set up when it came out and it still is.

At least we moved past webpack mostly.

pjmlp

2 hours ago

C23 has just been ratified, and C2y has already quite a few proposals.

Programming languages are like any other software product, evolution or stagnation.

Eventually they might implode, however whatever comes after will follow the same cycle yet again.

dangoodmanUT

2 minutes ago

I thought it said "Proposal: JavaScript Sucks" and was not surprised by the number of upvotes from HN

connicpu

2 hours ago

The general idea of types with a fixed layout seems great, but I'm a lot more dubious about the idea of unsafe blocks. The web is supposed to be a sandbox where we run untrusted code and with pretty good certainty expect that it can't crash the computer. Allowing untrusted code to specify "hey let me do stuff that can cause data races if not done correctly" is just asking for trouble, and also exploits. If shared structs are going to be adopted I think they probably need to be immutable after creation, or at the very least only modified with atomic operations.

jsheard

2 hours ago

Isn't it really no different to what you can already do with WASM threads though? C/C++ or unsafe Rust compiled to WASM can have data races, but the worst it can do is crash the WASM instance, just like how you can have use-after-frees or out-of-bounds array accesses in WASM but the blast radius is confined to the instance.

Granted, a JS runtime is significantly more complex than a WASM runtime so there is more room for error.

modeless

2 hours ago

SharedArrayBuffer can already do data races on the web. And they can't crash the browser or computer.

pjmlp

2 hours ago

That was gone with GPU access and WebAssembly.

afavour

an hour ago

I feel conflicted. Working with multithreaded stuff in JS is a huge PITA. This would go some way to making things easier. But it also feels like it would radically complicate JS. Unsafe blocks? Wow-eee.

With the rise of WASM part of me feels like we shouldn't even try to make JS better at multithreading and just use other languages better suited to the purpose. But then I'm a pessimist.

egeozcan

2 hours ago

Huh, I thought that most work that used to use workers switched to Webassembly.

Talking about JS proposals, I'm looking forward to this one: https://github.com/tc39/proposal-record-tuple

Records and tuples can make a lot of logic much more easier to read, and way less fragile. Not sure how they would play together with the shared structs though.

AprilArcus

2 hours ago

I don't think R&T will ever ship at this point, since the browser vendors are apparently unwilling to absorb the complexity that would be required to add new primitive types with value semantics.

sjrd

an hour ago

I've been following that proposal closely, and even (unsuccessfully) tried to contribute suggestions to it. I think what's killing it is that the authors of the proposal won't accept arbitrary values as fields of R/T, but all the potential users are saying that they won't use R/T if they can't put arbitrary values in them.

The reluctance of the authors is due to backward compatibility with sandboxed "secure" JavaScript (SES). That said, every other language in existence that has immutable structs and records allows to put arbitrary values in them.

So it's at a standstill, unfortunately.

Jcampuzano2

2 hours ago

JS devs - do everything but write in another language challenge level: Impossible.

pier25

26 minutes ago

There's a lot of that, certainly, but there are legitimate reason to use JS/TS.

Frontend is an obvious one but also using services like CF Workers or Deno Deploy which are optimized for V8. You're going to get better uptime and lower latency than anything else at that cost.

hyperhello

2 hours ago

Lots of programmers only really feel comfortable in C++ because it's the language they were trained in.

bastawhiz

2 hours ago

Call me when browsers support another language. What are we going to use? CSS?

modeless

2 hours ago

wasm

"but wasm has to call JavaScript to use browser APIs" WasmGC is shipped in Chrome and Firefox and enabled by default in WebKit nightly

johnfn

an hour ago

Let me know when WASM has a dev workflow that gets a change to your browser 1/10th as fast as Vite + TypeScript + React.

nuz

2 hours ago

WasmGC is just garbage collection? Not browser APIs

Arch485

43 minutes ago

Oh yeah. CSS is turing complete, after all!

modeless

2 hours ago

Huh, no types. So every field is 8 bytes I guess?

I suppose if you want a defined/packed memory layout you can already use SharedArrayBuffer and if you want to store objects in it you can use this BufferBackedObjects library they linked. https://github.com/GoogleChromeLabs/buffer-backed-object

I also expect that in browsers this will have the same cross-origin isolation requirements as SharedArrayBuffer that make it difficult to use.

whizzter

2 hours ago

Not sure this is a good idea or not, for one it'd be awesome for doing performance oriented and threaded code in JS/runtimes, the idea seems related to how C# struct's already work (and tuples under the hood). Interop with WASM code might also be simplified if struct-like access was a built-in.

The bad is that people wouldn't necessarily be prepared for their semantics (are they value or reference based?), how to shared prototypes between environments (mentioned as problem in the proposal itself), not entirely sure if this proposal would add to the complexity vs security for spectre like attacks.

It'd be useful, but worth it is another question? (And would all major players see interest in it? esp considering that it'd need to be "JSzero" level propsal if they go in that direction. (There was a post here a few days ago about layering runtimes with JS0 being the core with everything else being syntax transforms on top).

weego

2 hours ago

It's hard to take anyone concerned about the 'performance ceilings' in javascript object creation seriously at this point.

aardvark179

an hour ago

    Give developers an alternative to classes that favors a higher performance ceiling and statically analyzability over flexbility.
Is an entirely reasonable goal. Object shape in JS tends to go through a fixed pattern of mutation immediately after construction and although that can sometimes be analysed away by the JIT there are a lot of edge cases that can make that tricky.

You may not care, but I bet almost everybody who has actually worked on a JS engine does, and has good reasons for doing so.

bastawhiz

2 hours ago

I initially didn't like the high level idea, but I warmed up to it. My only concern is that the constructor isn't guaranteed to define the same fields with the same types, which kind of defeats the point.

I'd improve this proposal in two ways:

1. Explicitly define the layout with types. It's new syntax already, you can be spicy here.

2. Define a way for structs to be directly read into and out of ArrayBuffers. Fixed layout memory and serialization go hand in hand. Obviously a lot of unanswered questions here but that's the point of the process.

The unsafe block stuff, frankly, seems like it should be part of a separate proposal.

meindnoch

an hour ago

Leave. The. Language. Alone.

BoingBoomTschak

an hour ago

The similarity with CL's divide between structs and classes is uncanny; especially with ((:type vector) :named).

szastamasta

an hour ago

Please stop. What a nonsense. JS is a dynamic language where everything is a Hashtable. It will never be really fast as your structs won’t be in single cacheline, you won’t be able to calculate field address during compile time by pointer offsets. There’s no simd, no multithreading, no real arrays.

JS is such a simple, dynamic language. It should just stay this way. Please stop bloating it with every feature that’s trendy this year. We already have classes that we didn’t need. We don’t need structs for sure.

tantalor

an hour ago

High performance applications are already being written that depend on features like shared memory, but because the language has poor support for them then developers have to use ugly workarounds. This proposal solves that with built-in support.

>It should just stay this way

Counterpoint: JS has been evolving significantly, look at ES6 and ES8 in particular if you need help finding examples.

szastamasta

18 minutes ago

I just mean you won’t write a video codec or a 3d renderer in JS. It will never get there. Just leave these things to WebAssembly where needed and leave JS as a slow, dynamic language we use for web apps.

tantalor

12 minutes ago

It's a false dichotomy. Computers are fast. You should be able to write fast computer programs in any language.

The limiting factor on a program's performance should be the design of algorithms and data structures, not the programmer's choice of language or runtime.

rty32

22 minutes ago

Exactly. Without new features and syntaxes people would still be doing MyClass.prototype.method = function () { } like idiots. Such a meaningless argument for preventing progress.

szastamasta

20 minutes ago

Nobody needs classes nor prototypes in JS. Objects + functions is more than enough. I stopped using these few years ago and miss nothing.

PedroBatista

2 hours ago

I mean.. After ES6 with classes what is JavaScript anyway? Just bring Structs too, the more the merrier.

digger495

an hour ago

They should just go write golang, if this is what they want.