The ‘context’ package imports the ‘fmt’ package to format three strings. The ‘fmt’ package then pulls in a number of other packages so it’s rather large (~500K in the executable, unstripped). So if you import ‘net’, you get ‘context’, then you get ‘fmt’, but it would be nice to make smaller executables for embedded devices that just use the ‘net’ package.
I think it could be a useful optimization to remove the dependency on ‘fmt’ and just generate those strings manually somehow, although there might be some work to do if the current behavior needs to be emulated as %v is used with some structs, for example.
For starters, would anyone else find this optimization useful?
Roughly, yes, I read the blog entry earlier. So I’ve identified a problem and a vague solution, but I would like to know if anyone else feels this is actually a problem.
For me, I might be able to fit my latency measuring utility on a MIPS based WiFi AP with limited flash space running LEDE, but that’s just my specific use case.
It’s not a problem for me personally, but there are some significant contortions already in the standard library to avoid internal dependencies. I’m mildly surprised something as small as context would depend on something as large as fmt. I’d be happy to see this fixed.
Thanks for that. One thing I’m realizing though is that I’m not sure of the actual delta of removing this dependency, because while ‘fmt’ itself is pretty sizable (how to quantify that), any other packages that ‘fmt’ imports that ‘net’ already imports anyway would not be included in the size reduction.
Short of re-building Go with a modified ‘net’ package and comparing executables with and without the dependency on ‘fmt’, is there a way to know the actual size difference?
So far, I look at the dependency trees with a quick and dirty utility I wrote that calls ‘go list’ recursively starting at a specified root package or the current directory, but it doesn’t have the smarts to do a delta between two dependency trees, nor does it (can it?) show package sizes / totals in the final executable. (One can also list dependencies recursively using go list with .Deps, but I wanted to see the hierarchy also.)
Then my “nofmt” version of Go replaces the three lines in context.go that use ‘fmt’ with a hardcoded string for now. I’ve indeed removed the dependency, as I compared a ‘go list’ diff between both versions:
% go list -f '{{ join .Deps "\n" }}' > go_list_deps_1.8.3.txt
% # switch Go to the nofmt version
% go list -f '{{ join .Deps "\n" }}' > go_list_deps_1.8.3_nofmt.txt
% diff go_list_deps_1.8.3.txt go_list_deps_1.8.3_nofmt.txt
3d2
< fmt
So for now I guess I can chalk this up to a failed idea, although I’m unclear on why the difference is that small.
Thanks, I hadn’t noticed your post before my quick test Dave. I could raise an issue anyway, but it might just turn into an (maybe informative) discussion of why this wouldn’t help.
I suspect that the big “unnecessary” things in that program are unicode and unicode/utf8 which get pulled in by reflect via context and sort. I don’t think that’s trivial to remove.
To clarify, this is my standard response to PR’s without issues. The intent is to avoid hurt feelings (on all sides) when time is lost due to misunderstandings.