frontpage.
newsnewestaskshowjobs

Made with ♥ by @iamnishanth

Open Source @Github

fp.

Open in hackernews

Be Careful with Go Struct Embedding

https://mattjhall.co.uk/posts/be-careful-with-go-struct-embedding.html
62•mattjhall•3h ago

Comments

tymscar•2h ago
That’s actually crazy. Why is this even a feature?
jrockway•2h ago
Because

   type Foo struct { 
       sync.Mutex
       whatever string
   }
   var foo Foo
   foo.Lock()
   foo.whatever = 42
   foo.Unlock()
is convenient.
echelon•2h ago
It's dangerous. This is awful.

Any coding construct that can cause defects is an antipattern. Your language should discourage defects by design. Especially if the faults crop up at runtime.

This struct field dereferencing is like NULLs and "goto".

Language design that is anti-defect yet ergonomic include the modern Option<T> and Result<T, E> as seen in languages such as Swift and Rust, with first class destructuring that doesn't make it painful to use. They're almost impossible to misuse, yet feel convenient instead of frictionful. Rust's sum types and matching are another set of examples. Hopefully these patterns spread to more languages, because they're safe and convenient.

eru•10m ago
I mostly agree.

> Language design that is anti-defect yet ergonomic include the modern Option<T> and Result<T, E> as seen in languages such as Swift and Rust, with first class destructuring that doesn't make it painful to use.

Funny enough, this is only 'modern' in imperative languages. It's been a staple in the ML family since approximately forever. (But hey, I do appreciate progress when we get it!)

thrill•1h ago
Hmm, never realized the convenience came this way. Seems the compiler could emit a warning if two equal depth names might cause confusion, which could be ignored if acceptable.
sethammons•1h ago
almost always, the recommendation is to not embed your mutex; give it a name.

foo.mu.Lock()

This way you don't expose your primitives, preventing poor usage from causing a deadlock. Generally you don't want the user of your struct to have to know when or when to not lock.

eru•11m ago
Alas, locks don't compose, ie often your users will have to know about the internals when you are using locks.

But it's good advice when it works.

resonious•35m ago
I thought Go was all about being "simple" at the cost of convenience.

It is a bit ironic that this language that was was designed around "all of these features of other languages cause trouble, we will omit them" also has a bunch of features that cause trouble and get avoided.

Just to make my own stance clear: I like language features. I think this struct embedding feature looks pretty cool. But I also like interfaces and polymorphism. I think it's OK for a programming language to be powerful, and to put the onus on developers to not go too crazy with that power. And for that reason, I've always gravitated away from Go, and always jump on an opportunity to make fun of it (as I have here).

mikepurvis•2h ago
At risk of being excessively sassy this looks like a case of wanting the ergonomics of multiple inheritance without fully grappling with the complexities or implications of it.
gdbsjjdn•2h ago
In most cases people just want any inheritance, this is the backwards way the Golang devs decided to implement it based on their 80s view of programming languages.
metadat•2h ago
IMHO it should be a compiler error. This is just so loose... a wheel fell off.
ShroudedNight•1h ago
A wheel is generous. This seems more like inviting the computing equivalent of spilling twenty thousand tons of crude into the sea, which then promptly catch fire.
dgl•1h ago
See how it's used in the standard library io types, it makes for quite nice composition: https://go.googlesource.com/go/+/refs/heads/master/src/io/io...
mananaysiempre•1h ago
I’m sympathetic to parts of the Go design philosophy, but the only thing that comes to mind looking at this is “damn, that’s some awkward (nominal-looking) syntax for (structural) intersection types”.

(It also feels to me that this sort of anonymous embedding is materially different for interfaces vs structs, though I admit that from a type-theoretic perspective it’s not.)

bilbo-b-baggins•46m ago
You can’t have ambiguous methods so the problem illustrated here fails at compile time for interfaces.
whatevertrevor•22m ago
Unioning interfaces like this does seem convenient for composition/mixin patterns, I'm not sure if extending it to structs in general seems worth the cost of potential footguns though, especially external libraries and such where you probably don't want to think about the full potential tree of embedding conflicts.
mananaysiempre•1h ago
At the very least, the Go authors have been convinced this should be a feature since the Plan 9 C dialect[1].

[1] http://doc.cat-v.org/plan_9/4th_edition/papers/comp, look for “anonymous structure or union” and note that a (different) part of that extension has since been standardized.

bilbo-b-baggins•53m ago
Normally you wouldn’t contrive to use embedded struct fields in this way. And you can’t have the same kind of composition with methods - it’s a compiler error:

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

So the whole article is basically about using the language in a way you normally would ever do.

whatevertrevor•12m ago
This can be simplified, conflicting field names at the same level also don't compile:

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

Conflicting functions at nested levels also compile:

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

It's not about method vs field, it's about the nesting level of the conflicting identifier, if it's at the same level there's an error, if it's at different levels, the higher level hides the lower level identifier:

https://go.dev/doc/effective_go#embedding

amiga386•42m ago
Because it's useful.

https://go.dev/doc/effective_go#embedding

> Embedding types introduces the problem of name conflicts but the rules to resolve them are simple. First, a field or method X hides any other item X in a more deeply nested part of the type. If log.Logger contained a field or method called Command, the Command field of Job would dominate it.

> Second, if the same name appears at the same nesting level, it is usually an error; it would be erroneous to embed log.Logger if the Job struct contained another field or method called Logger. However, if the duplicate name is never mentioned in the program outside the type definition, it is OK. This qualification provides some protection against changes made to types embedded from outside; there is no problem if a field is added that conflicts with another field in another subtype if neither field is ever used.

typ•17m ago
It seems to come from a Plan 9 C idiom that GCC even has an extension for it.

https://gcc.gnu.org/onlinedocs/gcc-5.3.0/gcc/Unnamed-Fields....

Olreich•2h ago
If you need to grab a particular struct's version of the data, you can via `opts.BarService.URL` or `opts.FooService.URL`: https://go.dev/play/p/MUSYJhmoC2D

Still worth being careful, but it can be useful when you have a set of common fields that everything of a certain group will have (such as a response object with basic status, debug info, etc. and then additional data based on the particular struct). I don't know why they let you embed multiple layers and multiple objects though. I've never gotten value out of anything but a "here's a single set of common fields struct embedding".

tymscar•2h ago
So I got curious and I looked at the compiler source code, and it does a depth-first search.

The fascinating bit to me is that there is a consolidateMultiples function in go/src/go/types/lookup.go (lines 286-304) that detects when multiple embedded types at the same depth provide the same field name. I wonder why they don’t do this for all levels. How deep could this even be in practice for it to matter? You could just have a hashmap with them all.

dgl•2h ago
> I wonder why they don’t do this for all levels. How deep could this even be in practice for it to matter? You could just have a hashmap with them all.

While it may seem questionable for fields; it applies to methods too and is potentially more useful as a way to override them when doing struct embedding but wanting to preserve an interface.

linhan_dot_dev•2h ago
I like the Go language because it's straightforward and clear, even if it looks a bit plain.

I hope the feature mentioned in the article will cause a compiler error.

However, I wouldn't use this approach when writing my own code.

eru•9m ago
> I hope the feature mentioned in the article will cause a compiler error.

Read the article. It won't.

At best you can perhaps find a linter that'll report it?

> However, I wouldn't use this approach when writing my own code.

You might use it by accident.

digianarchist•1h ago
I'm surprised this wasn't in the recent post submitted here: https://blog.habets.se/2025/07/Go-is-still-not-good.html

It's a one of a few rough edges in Go.

eru•12m ago
You could add it as a comment there, or on the HN discussion?
bilbo-b-baggins•1h ago
Huh my IDE linter spits out warnings about this. Not sure which extension does it.
nemo1618•50m ago
Over the course of ~10 years of writing Go, my ratio of "embedding a struct" to "regretting embedding a struct" is nearly 1:1.

I do not embed structs anymore. It is almost always a mistake. I would confidently place it in the "you should be required to import 'unsafe' to use this feature" bin.

noisy_boy•19m ago
Am I the only one who found the described behavior to be intuitively correct? I did expect it to print "abc.com".
creddit•7m ago
I don’t write Go at all but given the first example, also expected this.

I was very surprised that either example compiled, though.

Be Careful with Go Struct Embedding

https://mattjhall.co.uk/posts/be-careful-with-go-struct-embedding.html
63•mattjhall•3h ago•32 comments

Sj.h: A tiny little JSON parsing library in ~150 lines of C99

https://github.com/rxi/sj.h
312•simonpure•9h ago•161 comments

Lightweight, highly accurate line and paragraph detection

https://arxiv.org/abs/2203.09638
58•colonCapitalDee•5h ago•6 comments

Show HN: I wrote an OS in 1000 lines of Zig

https://github.com/botirk38/OS-1000-lines-zig
107•botirk•3d ago•13 comments

40k-Year-Old Symbols in Caves Worldwide May Be the Earliest Written Language

https://www.openculture.com/2025/09/40000-year-old-symbols-found-in-caves-worldwide-may-be-the-ea...
101•mdp2021•3d ago•61 comments

My new Git utility `what-changed-twice` needs a new name

https://blog.plover.com/2025/09/21/#what-changed-twice
33•jamesbowman•4h ago•11 comments

Calculator Forensics (2002)

https://www.rskey.org/~mwsebastian/miscprj/results.htm
63•ColinWright•3d ago•25 comments

Procedural Island Generation (VI)

https://brashandplucky.com/2025/09/28/procedural-island-generation-vi.html
29•ibobev•5h ago•3 comments

DXGI debugging: Microsoft put me on a list

https://slugcat.systems/post/25-09-21-dxgi-debugging-microsoft-put-me-on-a-list/
216•todsacerdoti•11h ago•69 comments

I forced myself to spend a week in Instagram instead of Xcode

https://www.pixelpusher.club/p/i-forced-myself-to-spend-a-week-in
195•wallflower•12h ago•72 comments

Why your outdoorsy friend suddenly has a gummy bear power bank

https://www.theverge.com/tech/781387/backpacking-ultralight-haribo-power-bank
168•arnon•13h ago•205 comments

Timesketch: Collaborative forensic timeline analysis

https://github.com/google/timesketch
102•apachepig•9h ago•10 comments

How can I influence others without manipulating them?

https://andiroberts.com/leadership-questions/how-to-influence-others-without-manipulating
31•kiyanwang•4h ago•16 comments

Model Flop Utilization Beyond 6ND

https://jott.live/markdown/mfu
7•brrrrrm•3d ago•0 comments

INapGPU: Text-mode graphics card, using only TTL gates

https://github.com/Leoneq/iNapGPU
39•userbinator•3d ago•4 comments

Show HN: Tips to stay safe from NPM supply chain attacks

https://github.com/bodadotsh/npm-security-best-practices
17•bodash•5h ago•5 comments

Node 20 will be deprecated on GitHub Actions runners

https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
74•redbell•1d ago•24 comments

Unified Line and Paragraph Detection by Graph Convolutional Networks (2022)

https://arxiv.org/abs/2503.05136
85•Qision•11h ago•11 comments

Zig got a new ELF linker and it's fast

https://github.com/ziglang/zig/pull/25299
66•Retro_Dev•3h ago•15 comments

How Isaac Newton discovered the binomial power series (2022)

https://www.quantamagazine.org/how-isaac-newton-discovered-the-binomial-power-series-20220831/
52•FromTheArchives•3d ago•8 comments

Discovering new solutions to century-old problems in fluid dynamics

https://deepmind.google/discover/blog/discovering-new-solutions-to-century-old-problems-in-fluid-...
32•roboboffin•3d ago•2 comments

Apple Silicon GPU Support in Mojo

https://forum.modular.com/t/apple-silicon-gpu-support-in-mojo/2295
100•mpweiher•5h ago•38 comments

LaLiga's Anti-Piracy Crackdown Triggers Widespread Internet Disruptions in Spain

https://reclaimthenet.org/laligas-anti-piracy-crackdown-triggers-widespread-internet-disruptions
318•akyuu•10h ago•138 comments

Oxford loses top 3 university ranking in the UK

https://hotminute.co.uk/2025/09/19/oxford-loses-top-3-university-ranking-for-the-first-time/
238•ilamont•10h ago•342 comments

Bringing Observability to Claude Code: OpenTelemetry in Action

https://signoz.io/blog/claude-code-monitoring-with-opentelemetry/
24•pranay01•7h ago•11 comments

EU to block Big Tech from new financial data sharing system

https://www.ft.com/content/6596876f-c831-482c-878c-78c1499ef543
33•1vuio0pswjnm7•3h ago•17 comments

A coin flip by any other name (2023)

https://cgad.ski/blog/a-coin-flip-by-any-other-name.html
47•lawrenceyan•3d ago•5 comments

The Counterclockwise Experiment

https://domofutu.substack.com/p/the-counterclockwise-experiment
41•domofutu•1d ago•13 comments

Show HN: Freeing GPUs stuck by runaway jobs

https://github.com/kagehq/gpu-kill
28•lexokoh•10h ago•0 comments

Why, as a responsible adult, SimCity 2000 hits differently

https://arstechnica.com/gaming/2025/09/thirty-years-later-simcity-2000-hasnt-changed-but-i-have/
218•doppp•3d ago•284 comments