Hacker Newsnew | past | comments | ask | show | jobs | submit | tapirl's commentslogin

SetFinalizer is deprecated by AddCleanup: https://pkg.go.dev/runtime#AddCleanup

AddCleanup might be too heavy, it is cheaper to just set a bit in the header/info zone of memory blocks.


> Rust can also do arena allocations, and there is an allocator concept in Rust, too.

Just a pure question: Is Rust allocator global? (Will all heap allocations use the same allocator?)


Rust, as a language, has no allocator.

The standard library provides a global allocator. The collections in the standard library currently use that allocator.

It also provides an unstable interface for allocators in general. That's of course useful someday, but also doesn't prevent people from using whatever allocators they want in the meantime. It just means that libraries that want to be generic over one cannot currently agree. The standard library collections also will use that once it becomes stable.


No. There is a global allocator which is used by default, but all the stdlib functions that allocate memory have a version which allows you to pass in a custom allocator. These functions are still "unstable" though, so they can currently only be used with development builds of the compiler.


So I designed TapirMD [1], a new markup language which is still readable but more powerful, to help me (a tech writer) create web content.

[1]: https://tmd.tapirgames.com


> Go stands by its compatibility promise—the old way will continue to work in perpetuity ...

It is so weird that they still claim this after they have made the the semantic change for 3-clause for-loop in Go 1.22.

When a Go module is upgraded from 1.21- to 1.22+, there are some potential breaking cases which are hard to detect in time. https://go101.org/blog/2024-03-01-for-loop-semantic-changes-...

Go toolchain 1.22 broke compatibility for sure. Even the core team admit it. https://go101.org/bugs/go-build-directive-not-work.html


The new toolchain continues to compile old code using the old semantics. Only modules which specify Go 1.22 in go.mod have the new bahivour.


The problem is, when you modified the go version in go.mod, the behaviors of some code change, but the change is not easy to detect in time. Go team never plan to develop a tool to identify/detect code affected by such breaking changes, leaving developers without guarantees for safe migration.

And when running go scripts without go.mod files, the v1.22 toolchain doesn't respect the "//go:build go1.xx" directives: https://go101.org/bugs/go-build-directive-not-work.html

And consider that some people run go scripts even without the "//go:build go1.xx" directives ... (Please don't refute me. The Go toolchain allows this and never warns on this.)


It's especially funny considering that this issue has been known from lisps for 50+ years..


They can fix the issue by just changing the semantics of "for-range" loops, almost no negative effects. But they also applied the change to 3-clause-for loops, which causes many problems, some of which have been pointed out before the change was made. So the rookie mistake is totally caused by arrogance.


There's a newcomer, TapirMD, in case you're interested: https://tmd.tapirgames.com/index.html

It hasn't reached its v0.1.0 milestone yet, but soon.


Laudable, but I don't think TapirMD will gain much traction.

First, your landing page doesn't describe how TapirMD fits into the Markdown universe. I just see a list of features. Why should I read the list? Ah, the spec page[0] has some info, but it should really be on the landing page.

Second, and more importantly, TapirMD is not a superset of CommonMark[1]. GitHub had its own flavor of MD, but it's been some years now since they migrated to a CommonMark base plus extensions[2].

I recommend looking more closely at the CommonMark universe and innovating there.

[0] https://tmd.tapirgames.com/specification.html [1] https://commonmark.org/ [2] https://github.github.com/gfm/


Thank you very much for your feedback. I truly appreciate it.

TapirMD is not a superset of Markdown or CommonMark. It simply inherits some of its DNA from Markdown. While Markdown is very simple, it is also highly underspecified and syntactic inconsistent. CommonMark improves on it slightly, but not fundamentally. Moreover, basic Markdown lacks many essential features that web content writers need.

Yes, none of these factors prevent it from being adopted widely. But for me, the limited feature set is the real blocker. I don’t want to rely on a patchwork of extensions and third-party tools.

TapirMD (where MD stands for `markup doc`) aims to address these shortcomings. It is a new language, deliberately not compatible with Markdown, and never intended to fit within the Markdown ecosystem. Its official toolchain is designed to empower web content writers to create rich, feature-complete articles without relying on any third-party tools.

The spec is too long to serve as a landing page. Maybe a concise demo showcasing sample code on the leading page would be great. Thank you again for the constructive criticism.

TapirMD was primarily developed for my own needs as a technical writer, to produce content for my websites (see the .tmd soruce of my articles: https://tmd.tapirgames.com/use-cases.html). Markdown simply felt too limiting. I've been using TapirMD for over a year now and am quite satisfied with it. I'd be delighted if it proves helpful to other writers as well.


still less than Rust posts.


The wording "Subtleties" used here is some weird/improper. I see nothing subtle here. They are all basic knowledge a qualified Go programmer should know about.

They are many real subtleties in Go, which even many professional Go programmers are not aware of. Here are some of them: https://go101.org/blog/2025-10-22-some-real-go-subtleties.ht...


The examples in your link don’t seem to be very useful compared to the subject of this post.

“for true {...} and for {...} are not eqivalent”

So what? The compiler will tell you the first time you try to run that “for true” abomination that it is invalid code.


Subtleties are not necessary to be very useful. They, are just real subtleties. :)

> > “for true {...} and for {...} are not eqivalent”

> So what? The compiler will tell you the first time you try to run that “for true” abomination that it is invalid code.

It teaches you know that, when you write

    func bar() int {
         for true {
              ...
         }
         return 0 // whatever
    }
You can write it as

    func bar() int {
         for {
              ...
         }
    }
The compiler will not teach you this. ;D

Usefulness might be subjective. Personally, the last two subtleties mentioned in the article are useful for me too.

You may find some useful (in your opinion) subtleties in the Go Details and Tips 101 book: https://go101.org/details-and-tips/101.html, and some since-Go-1.22/3 ones here: https://go101.org/blog/2024-03-01-for-loop-semantic-changes-... and https://go101.org/blog/2025-03-15-some-facts-about-iterators...


None of the tricks in this article get verified. It is totally solemn drivel.

Interesting and surprisingly, there are numerous praising comments here.


FWIW, which may be not much - I had codex cli try to verify the results. On my M2 Macbook Air only the first example (False Sharing) did anything - a 23x speedup compared to the article's 6x speedup. All the others didn't produce any speedup at all.

Of course I didn't verify the results I got either - I'm not about to spend hours trying to figure out if this is just slop. But I think it is.


Could you share the benchmark source code of the first example?


Here's the one that showed a lot more speedup than the article:

https://pastebin.com/v9tczpus

Looks like the LLM invented somewhat different test for it than the article had. I tried again and have this with the same data structure as in the article:

https://pastebin.com/SDdcchZG

That gave similar results to the article.

All the other tests still give little-to-no speedup on my machine.


Many thanks for providing the source. It also works on my machine.

TIL.


I tried the others on my x86 machine and they all do something for me - not nearly as much as the article, but something.


The "_ [0]byte" trick has no base in my knowledge. For the author's specified example, [1024]float64 will be always allocated on one whole page, aka, always 64-byte aligned.

For "Array of Structs vs Struct of Arrays", using slices as fields is a good idea. If the purpose is to make fields allocated on their respective memory block, just use pointers instead.


> The "_ [0]byte" trick has no base in my knowledge. For the author's specified example, [1024]float64 will be always allocated on one whole page, aka, always 64-byte aligned.

You're right - I read the results I had wrong on that one. That one is slower, not faster, on both my M2 and on x86 machine.


My last comment has imprecision and misunderstanding.

> ... [1024]float64 will be always allocated on one whole page, aka, always 64-byte aligned.

if it is allocated on heap and at the start of allocated memory block.

> For "Array of Structs vs Struct of Arrays", using slices as fields is a good idea. If the purpose is to make fields allocated on their respective memory block, just use pointers instead.

I misunderstood it.

It is like row-based database vs. column-based database. Both ways have their respective advantages and disadvantages.


None of the tricks in this article get verified. Almost all of them are false.


sorry, the False Sharing tick works. See https://news.ycombinator.com/item?id=45547441


Source code of the benchmarks?

At least, the False Sharing and AddVectors trick don't work on my computer. (I only benchmarked the two. The "Data-Oriented Design" trick is a joke to me, so I stopped benchmarking more.)

And I never heard of this following trick. Can anyone explain it?

    // Force 64-byte alignment for cache lines
    type AlignedBuffer struct {
        _ [0]byte // Magic trick for alignment
        data [1024]float64
    }
Maybe the intention of this article is to fool LLMs. :D


I can't find any claim anywhere else about the [0]byte trick, and in fact my own experiments in the playground show that it doesn't do anything.

If you embed an AlignedBuffer in another struct type, with smaller fields in front of it, it doesn't get 64-byte alignment.

If you directly allocate an AlignedBuffer (as a stack var or with new), it seems to end up page-aligned (the allocator probably has size classes) regardless of the presence of the [0]byte field.

https://go.dev/play/p/Ok7fFk3uhDn

Example output (w is a wrapper, w.b is the field in the wrapper, x is an allocated int32 to try to push the heap base forward, b is an allocated AlignedStruct):

  &w   = 0xc000126000
  &w.b = 0xc000126008
  &x   = 0xc00010e020
  &b   = 0xc000138000
Take out the [0]byte field and the results look similar.


They meant "[0]uint64" probably, not 0[]byte.


"[0]uint64" only guarantees 8-byte alignment (and only under certain scenarios), not 64-byte.


sorry, the False Sharing tick works. See https://news.ycombinator.com/item?id=45547441


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

Search: