Live data from Hacker News

A 10x Faster TypeScript

devblogs.microsoft.com

891–900 of 943 posts

Re: A 10x Faster TypeScript

#891

Earlier quoted context omitted.

| with no frills. People say this like it's a bad thing. It's not, it's Go's primary strength.

Yes. For Webservers. Not for compilers. I wrote a bunch of compilers, and Go is not a language I would choose for this.

Unless, of course, you are not working on a greenfield project and instead are porting an existing compiler from Typescript, in which case Go is the language you would choose as it is the language that most closely resembles Typescript, allowing ease of bulk conversion by script. The same reason why it was chosen for Typescript.

Re: A 10x Faster TypeScript

#892

Earlier quoted context omitted.

> Humans aren't deterministic. Exactly, which is why I would want humans and LLMs to write maintainable code, so that I can review and maintain it, which brings us back to the original question of which programming languages are the easiest to maintain...

Well, we're in a loop then because my response was "you don't care about maintainable assembly". I want maintainable systems you want maintainable code . We can just accept that difference. I believe maintainable systems can be achieved without focusing on code that humans find maintainable. In the future, I believe we will build systems on top of code primarily written by LLMs and the rubric of what constitutes good…

We're stuck in a loop because you're flip flopping between two positions.

You started off by comparing LLM output to compiler output, which I pointed out is a false equivalence because LLMs aren't as deterministic as compilers.

Then you switched to comparing LLMs to humans, which I'm fine with, but then LLMs must be expected to produce maintainable code just like humans.

Now you're going back to the original premise that LLM output is comparable to compiler output, thus completing the loop.

Re: A 10x Faster TypeScript

#893
post #499

Earlier quoted context omitted.

What is the cross compilation support for NativeAOT though? This is one of the things that Go shines (as long as you don't use CGO, that seems perfectly plausible in this project), and while I don't think it would be a deal breaker it probably makes things a lot easier.

What is the state of WASM support in Go though? :) I doubt the ability to cross-compile TSC would have been a major factor. These artifacts are always produced on dedicated platforms via separate build stages before publishing and sign-off. Indeed, Go is better at native cross-compilation where-as .NET NativeAOT can do only do cross-arch and limited cross-OS by tapping into Zig toolchain.

> What is the state of WASM support in Go though? :)

The gc compiler considers it a first-class build target.

Like C#, the binary tends to be on the larger side[1], which makes it less than ideal for driving a marketing website, but that's not really a problem here. Installation of tools before use is already the norm.

[1] The tinygo compiler can produce very small WASM binaries, comparable to C, albeit with some caveats (surprisingly, the extra data gc produces isn't just noise).

Re: A 10x Faster TypeScript

#894

Earlier quoted context omitted.

Segfaults are very much a memory safety issue. You are correct that concurrency is the cause here, but that doesn't mean it's not a memory safety issue. That said, most people still call Go memory safe even in spite of this being possible, because, well, https://go.dev/ref/mem > While programmers should write Go programs without data races, there are limitations to what a Go implementation can do in response to a dat…

> Segfaults are very much a memory safety issue. How can a segfault lead to attack or exploitation? Edit: Answering my own question (from https://go.dev/ref/mem ): Reads of memory locations larger than a single machine word are encouraged but not required to meet the same semantics as word-sized memory locations, observing a single allowed write w. For performance reasons, implementations may instead treat larger ope…

Not all segfaults necessarily point to exploitable bugs, but a segfault is usually very suspicious. On common architectures, you get a segmentation fault when there is a memory access violation. Which usually means you've either read from, written to, or tried to execute code at an address that is not readable, not writeable or not executable in your address space. That is suspicious because unless your program is intentionally doing that (which is relatively rare, and obviously in that case you would want to explicitly catch it with a signal handler) it suggests that some assumption your program is making about memory somewhere is incorrect. Like Go says, arbitrary memory corruption.

Is that exploitable? It depends. It's easier to assume that it is than hope that it isn't.

However, while it is a more serious category of issue, I have two reasons to suggest people don't over-index on it:

- Concurrency bugs that can not lead to segmentation faults are by no means safe, they can still lead to exploits of arbitrary severity. Ones that can are more dangerous since they can violate Go's own safety guarantees, but so can the "unsafe" package, so you need to put it into some perspective.

- Concurrency bugs that can are likely to be less common. In my experience, it is not extremely common to re-assign shared map or interface values in Go. If you are sharing a value of map, slice, string or interface and do plan on re-assigning it (thus causing the hazard in question) you can work around this problem trivially by adding a tiny bit of indirection, using an atomic pointer to the value instead, and re-assigning that pointer instead. Making a new value each time is no big deal since all of the fat pointers in question are still relatively small (just 2-3 machine words) though it incurs more allocations and pointer indirections so YMMV.

And of course I recommend using all applicable linters, the checklocks analyzer from gVisor, and careful encapsulation of shared memory where possible. Even better is to avoid it entirely if you can.

Of course, as much as I love Go, some types of program are going to need lots of hairy shared memory and mutations interweaving. And for that, Rust is the obvious best choice.

Re: A 10x Faster TypeScript

#895

Earlier quoted context omitted.

Well, we're in a loop then because my response was "you don't care about maintainable assembly". I want maintainable systems you want maintainable code . We can just accept that difference. I believe maintainable systems can be achieved without focusing on code that humans find maintainable. In the future, I believe we will build systems on top of code primarily written by LLMs and the rubric of what constitutes good…

We're stuck in a loop because you're flip flopping between two positions. You started off by comparing LLM output to compiler output, which I pointed out is a false equivalence because LLMs aren't as deterministic as compilers. Then you switched to comparing LLMs to humans, which I'm fine with, but then LLMs must be expected to produce maintainable code just like humans. Now you're going back to the original premise…

There are more elements to a compiler than determinism. That is, determinism isn't their sole defining property. I can compare other properties of compilers to LLMs. No "flip flop" there IMO, but your judgment may vary.

Perhaps it is impossible for you to imagine that LLMs can share some properties with compilers and other properties with humans? And that this specific blend of properties makes them unique? And that uniqueness means we have to take a nuanced approach to understanding their impact on designing and building systems?

So lets lay it out. LLMs are like compilers in that they take high level instructions (in the form of English) and translate it into programming languages. Maybe "transpiler" would be a word you prefer? LLMs are like humans in that this translation of high level instructions to programming languages is non-deterministic and so it requires system level controls to handle this imprecision.

I do not detect any conflict in these two ideas but perhaps you see things differently.

Re: A 10x Faster TypeScript

#896

Earlier quoted context omitted.

We're stuck in a loop because you're flip flopping between two positions. You started off by comparing LLM output to compiler output, which I pointed out is a false equivalence because LLMs aren't as deterministic as compilers. Then you switched to comparing LLMs to humans, which I'm fine with, but then LLMs must be expected to produce maintainable code just like humans. Now you're going back to the original premise…

There are more elements to a compiler than determinism. That is, determinism isn't their sole defining property. I can compare other properties of compilers to LLMs. No "flip flop" there IMO, but your judgment may vary. Perhaps it is impossible for you to imagine that LLMs can share some properties with compilers and other properties with humans? And that this specific blend of properties makes them unique? And that…

> There are more elements to a compiler than determinism.

Yes, but determinism is the factor that allows me to treat compilers as a black box without verifying their output. LLMs do not share this specific property, which is why I have to verify their output, and easily verifiable software is what I call "maintainable".

Re: A 10x Faster TypeScript

#897
post #894

Earlier quoted context omitted.

> Segfaults are very much a memory safety issue. How can a segfault lead to attack or exploitation? Edit: Answering my own question (from https://go.dev/ref/mem ): Reads of memory locations larger than a single machine word are encouraged but not required to meet the same semantics as word-sized memory locations, observing a single allowed write w. For performance reasons, implementations may instead treat larger ope…

Not all segfaults necessarily point to exploitable bugs, but a segfault is usually very suspicious. On common architectures, you get a segmentation fault when there is a memory access violation. Which usually means you've either read from, written to, or tried to execute code at an address that is not readable, not writeable or not executable in your address space. That is suspicious because unless your program is in…

Yeah, I was just thinking if an implementation has the propensity to abort or fail early with a segfault, that's better than running with memory corruption and far more difficult to exploit. It's not clear from the upthread example how soon it fails after corruption so there is potentially a narrow window where such a bug could be exploited if found in the wild with the apropos attack surface.

Re: A 10x Faster TypeScript

#898

Earlier quoted context omitted.

There are more elements to a compiler than determinism. That is, determinism isn't their sole defining property. I can compare other properties of compilers to LLMs. No "flip flop" there IMO, but your judgment may vary. Perhaps it is impossible for you to imagine that LLMs can share some properties with compilers and other properties with humans? And that this specific blend of properties makes them unique? And that…

> There are more elements to a compiler than determinism. Yes, but determinism is the factor that allows me to treat compilers as a black box without verifying their output. LLMs do not share this specific property, which is why I have to verify their output, and easily verifiable software is what I call "maintainable".

An interesting question you might want to ask yourself, related to this idea: what would you do if your compiler wasn't deterministic?

Would you go back to writing assembly? Would you diligently work to make the compiler "more" deterministic. Would you engineer your systems around potential failures?

How do industries like the medical or aviation deal with imperfect humans? Are there lessons we can learn from those domains that may apply to writing code with non-deterministic LLMs?

I also just want to point out an irony here. I'm arguing in favor of languages like Go, Rust and Zig over the more traditional dynamic scripting languages like Python, PHP, Ruby and JavaScript. I almost can't believe I'm fighting the "unmaintainable" angle here. Do people really think a web server written in Go or Rust is unmaintainable? I'm defending my position as if they are, but come on. This is all a bit ridiculous.

Re: A 10x Faster TypeScript

#899
post #894

Earlier quoted context omitted.

Not all segfaults necessarily point to exploitable bugs, but a segfault is usually very suspicious. On common architectures, you get a segmentation fault when there is a memory access violation. Which usually means you've either read from, written to, or tried to execute code at an address that is not readable, not writeable or not executable in your address space. That is suspicious because unless your program is in…

Yeah, I was just thinking if an implementation has the propensity to abort or fail early with a segfault, that's better than running with memory corruption and far more difficult to exploit. It's not clear from the upthread example how soon it fails after corruption so there is potentially a narrow window where such a bug could be exploited if found in the wild with the apropos attack surface.

Ah I see what you mean. To be fair, it is still true that not every bug that can lead to a segfault is exploitable, including this one potentially, but on the other hand, I think the point is that Go's memory safety guarantees always prevent segmentation faults: by the time you've hit a segmentation fault, you have definitely broken the type system and nothing is guaranteed anymore W.R.T. memory safety. So any bug that causes a segmentation fault is definitely immediately suspect. I think that's the point they were going for, at least.

Re: A 10x Faster TypeScript

#900
post #832

Earlier quoted context omitted.

It does, via unsafe package, yes it does look ugly, that is on purpose. item := *(*int)(unsafe.Pointer(uintptr(start) + size*uintptr(i))) A random example taken from Internet.

The standard library uses unsafe for syscalls, for higher-performance primitives like strings.Builder, etc, so it's support is mandatory to run any non-trivial Go program

For a while the GOOS=nacl port and the Google App Engine ports of Go disallowed unsafe pointer manipulation too, so there is some precedent. Throughout some of the ecosystem you can see pieces of "nounsafe" build tag support (e.g. in easyjson).
Post reply on HN