17 ms·
How small is the smallest .NET Hello World binary?
- Rochus 3y agoJust tried with my Oberon+ IDE and get a Hello.dll of 2048 bytes for this module: module Hello begin println("hello world") end Hello It uses the https://github.com/rochus-keller/Pelib https://github.com/rochus-keller/Pelib assembly generator.
- cyptus 3y agois the file filled with 0 bytes at the end? I think there are options to disable this
- Rochus 3y agoYes, it has about 700 zero bytes at the end; might be just some overhead due to the PE format; didn't have a close look, was just curious how big it is out of the box after skimming the article. Anyway the size of the DLL itself is irrelevant compared to the binaries required to run it (Mono + mscorlib.dll ~ 10 MB in case of Oberon+).
- analognoise 3y agoNicklaus Wirth was right. I felt that the first time I used Lazarus/FreePascal, and felt it to be true the more of his works I read. Recently though, I think maybe the way to get off the "cycle of reincarnation" for this type of thinking is to do WASM - but I cannot abandon hardware like that. I am mentally incapable of accepting a spiritual machine that I cannot break with a hammer upon my desk; [I am] too primitive; an indestructible global computer that runs on other people's hardware for thousands of dollars of compute time and is slower than an RPi (like Ethereum) is anathema to me in some fundamental way. I still want to get that (Wirth was right) on a shirt with his face on it.
- Rochus 3y ago> Nicklaus Wirth was right In what respect in this context? I should have explicitly stated that "Hello.dll" is a .NET assembly, i.e. Oberon+ uses the Mono CLR to run and debug the Oberon+ code (but not the .NET framework); it can also generate C99 (as a substitute for AOT compilation), but here it is about the minimal size of a Hello World .NET binary. WASM and especially the WAMR runtime might be a good alternative to the Mono CLR in future, but today it's too slow and only a few architectures are supported (much less than Mono).
- cxr 3y ago> It uses the https://github.com/rochus-keller/Pelib https://github.com/rochus-keller/Pelib assembly generator. Shouldn't Oberon+ be self-hosting? There's so much C++ ecosystem crud. It reminds me of all those projects for open source software hosting forges promoted as alternatives to GitHub and Gitlab, and then when you go to clone their code or file a bug... it's all on GitHub...
- Rochus 3y agoC++, in the moderate subset e.g. also used in Qt 1 to 5, I still consider to be the optimal implementation language for a compiler and IDE at the present state of Oberon+ development, not because C++ is such a great language, but because of the ubiquitous availability and the huge, proven code base, which allows me to implement a project like Oberon+ as a single person worlds faster and more robust than with any other technology I know. As an illustrative example of this efficiency, I would like to cite https://github.com/rochus-keller/LisaPascal https://github.com/rochus-keller/LisaPascal, where I was able to implement a parser and code browser within a week as a side project. With any other technology (including Smalltalk or Delphi) this would have taken months. A lot of development is still needed for Oberon+ to reach this point, and using the present approach I can support this development with sufficiently powerful tools.
- cxr 3y ago> As an illustrative example of this efficiency, I would like to cite https://github.com/rochus-keller/LisaPascal https://github.com/rochus-keller/LisaPascal, where I was able to implement a parser and code browser within a week as a side project. With any other technology (including Smalltalk or Delphi) this would have taken months. As a former Smalltalk developer, what do you think about it would actually slow you down (despite popular claims re productivity in Smalltalk)? Is it tooling for C++ static types? If so, then what about Delphi? And is it one goal of yours, then, to mold Oberon+ so that it would eventually be at parity, productivity-wise, with C++?
- Rochus 3y ago> As a former Smalltalk developer, what do you think about it would actually slow you down (despite popular claims re productivity in Smalltalk)? I was a Smalltalk developer in the early nineties as well, but then switched to statically typed languages and the source file concept for many reasons (performance, testing effort, integratability, etc.). For the present case performance is critical (parsing and cross-referencing of large code base) and also the specific required presentation/interaction features which come with Qt out of the box; and I already have a large toolbox based on C++ which I was able to reuse. > And is it one goal of yours, then, to mold Oberon+ so that it would eventually be at parity, productivity-wise, with C++? It would take more than a lifetime to achieve that goal given that my https://github.com/rochus-keller/LeanQt https://github.com/rochus-keller/LeanQt and https://github.com/rochus-keller/LeanCreator/ https://github.com/rochus-keller/LeanCreator/, which support my efficient toolbox today, have more than a million SLOC. My goal in the first place is to find out how I have to extend Oberon+ so I can use it in real-world (i.e. non-academic) projects with not too big restrictions compared to my current use of C++; reaching parity in terms of efficiency and the therefore required ecosystem is yet another challenge.
- creativenolo 3y agoHow would this compare to a non-.Net binary?
- _kbh_ 3y agoYou can make super small hello world binaries if you try. https://nathanotterness.com/2021/10/tiny_elf_modernized.html https://nathanotterness.com/2021/10/tiny_elf_modernized.html has a 120 byte hello world program for x86_64 ELF.
- Rochus 3y agoI just generated C99 with my Oberon+ example (see https://news.ycombinator.com/item?id=36652878 https://news.ycombinator.com/item?id=36652878) and compiled it with -O2. The generated Hello.c is 382 bytes, the Hello.h is 240 bytes, and the compiled Hello.o is 1264 bytes (compared to the 2048 bytes of the Hello.dll assembly). If I build a shared library which includes the runtime and some boiler-plate stuff the stripped version is 17760 bytes; if I instead build an executable, the stripped size is 17952 bytes (compared to the ~10 MB including mono and mscorlib.dll to run the assembly).
- DeathArrow 3y agoI think the limitation here is mostly the PE format, not the .Net framework.
- makach 3y agoThis was definitively not a dumb thing to spend time on. Diving into the details of a binary gives deep insight into how things are made and the concepts learned will enrich your knowledge. If it is interesting and you learn something it is always worth your time and effort.
- ClumsyPilot 3y agoi was hoping this is about 'real' baniraies, natively compiled .net executables, like the .Net AOT https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=net7 https://learn.microsoft.com/en-us/dotnet/core/deploying/nati...
- bob1029 3y agoYou can get a .NET AOT example in a few megabytes now. Looks like the most stripped down AOT compiled builds are about to crack the 1mb barrier: https://github.com/AustinWise/SmallestDotnetHelloWorlds https://github.com/AustinWise/SmallestDotnetHelloWorlds
- archargelod 3y agoBut isn't a dotnet runtime a feature? AOT strips a main feature of the language, while still doesn't even get close to compiled languages ( hello world < 300kb (or < 100 kb compressed))
- bob1029 3y agoTechnically, the runtime is the thing you need if you didnt use [native] AOT. A big example being that you don't need to emit/interpret IL in an AOT binary. I agree though, the minimal .NET example is still not close to a full-featured .NET platform. I kind of like the idea of opting-out of features though. Bringing the whole runtime for the party each time is a bit overkill (unless its already on every target machine). Lots of code doesn't need reflection. Some special cases actively dislike GC, etc.
- Rapzid 3y agoThat's why I love the ready to run option. It's aggressively AOT compiled but maintains the ability to JIT during runtime.
- pjmlp 3y agoI am quite sure that Go as compiled language doesn't do a 300 KB hello world (unless TinyGo is used), nor don't plenty of others.
- rcarmo 3y agoit would be interesting to compare this with non-Windows platforms. A while back I did a similar (but much less in depth) comparison of .NET Core 5 and 6: https://taoofmac.com/space/blog/2021/11/14/1600 https://taoofmac.com/space/blog/2021/11/14/1600
- userbinator 3y agoAs every section needs to be aligned to the smallest possible section alignment of 0x200 bytes (1KB), we inflate our file by at least that amount of bytes just because of that. 0x200 is 512, or 0.5K. It's been a long time since I've done PE size optimisation at this level but I remember 512 was the minimum accepted by Windows 9x but NT could accept alignments as small as 1. Also, I didn't see any mention of the old trick of overlapping the DOS MZ and PE headers, which was state-of-the-art when I was still doing this stuff: http://www.phreedom.org/research/tinype/ http://www.phreedom.org/research/tinype/ ...and then you realise that the demoscene has managed to do this in a 1k binary: https://www.pouet.net/prodlist.php?type%5B%5D=1k&platform%5B%5D=Windows&page=1 https://www.pouet.net/prodlist.php?type%5B%5D=1k&platform%5B...
- valevk 3y agoHow about .net core vs framework?
- MarkSweep 3y agoI have some comparisons here: https://github.com/AustinWise/SmallestDotnetHelloWorlds https://github.com/AustinWise/SmallestDotnetHelloWorlds
- ComputerGuru 3y agoHere's a story about producing the smallest possible with .NET Core [0]. [0]: https://medium.com/@MStrehovsky/building-a-self-contained-game-in-c-under-8-kilobytes-74c3cf60ea04 https://medium.com/@MStrehovsky/building-a-self-contained-ga...
- neonsunset 3y agoThis article will confuse people since the executable in question requires a runtime installed on the system (in fact, it uses .NET Framework 4.7.2, in 2023!). Most likely fair comparison for such solution would be .jar or even .py files. A good source of truth for an actual executable would be Native AOT binary, which can run on Windows, Linux or macOS. Naturally, it will be much larger, having to incorporate GC, possibly ThreadPool, Console and other auxiliary code.
- Kwpolska 3y agoThe .NET Framework is built into Windows, and a mandatory component of it since at least Vista. .NET Framework 4.7.2 specifically should be built-in on supported Windows versions.
- ad404b8a372f2b9 3y agoYou never have the right version installed though. Every time I've tried to install a .NET program it's always asked me to install a different version than the one I had.
- CrendKing 3y agoSounds like confirmation bias, because when the right version of .NET is ever used, you probably never knew it was a .NET program to begin with.
- ntdll 3y agoNot true in my experience. The "look and feel" of the program usually gives it away more or less immediately.
- grujicd 3y agoProbably, if that app uses WPF, which is "self-drawn" GUI library. However, if .Net app uses WinForms, that API is just a wrapper over standard Win32 controls and it looks like any other old school Win app.
- junon 3y agoI remember when the entirety of your C# binary would include the source code, and back before the concept of Release or Debug was prolific enough, closed source C# binaries would be distributed in Debug mode erroneously, allowing someone to extract pretty much a 1:1 replica of the codebase. Just a fun anecdote. I don't know if this is the case anymore.
- landr0id 3y agoI don't think it ever included actual source code, but .NET IL is just so rich that it made it extremely trivial to decompile, no?
- junon 3y agoIt indeed did, you could open up the .exe in notepad for example. It was all there.
- orphea 3y agoThis doesn't sound right. C# has always been a compiled language (to MSIL), from the earliest versions of .NET.
- xen0 3y agoBut that doesn't mean the source code wouldn't necessarily be exuded in a debug build. I don't know the truth of the original statement, but it isn't too unbelievable.
- pjerem 3y agoThis does sound unsurprising if you talk about a debug binary. It would allows you to debug it with the original source code. You are not supposed to run debug builds in production. But nothing will prevent you from doing it. Production binaries of course doesn’t embed any source or debugging symbols. It’s like erroneously shipping source maps files into your front end production build. It shouldn’t happen and it’s not necessary, but it’s just one configuration variable away so it happens a lot.
- planckscnst 3y agoThere is also this article about creating a tiny elf executable that's pretty interesting: https://news.ycombinator.com/item?id=21846785 https://news.ycombinator.com/item?id=21846785
- caeciliusest 3y agoThat was eye opening for me how the .exe could be brought down to less than 1KB... if someone could get a Hello World .exe in Flutter down to just 1MB, that would really be something.
- mihaaly 3y ago> Even though this is probably quite a useless project No. It taught me quite some.
- DeathArrow 3y agoMeanwhile it seems to be possible to write a Hello World program for DOS using just 20 bytes: https://www.gnostice.com/nl_article.asp?id=225&t=The_Smallest_Hello_World_Program_At_20_Bytes https://www.gnostice.com/nl_article.asp?id=225&t=The_Smalles...
- userbinator 3y agoIt's possible in 7 bytes + length of string (including terminator). "xchg ax, bp" will save 1 byte over what is in that article.
- hliyan 3y agoOn a side note, did anyone notice that the author's location is McMurdo Station, Antarctica? I didn't think they would have someone of their skillset at that station: https://usscar.org/directory?combine=&field_usscar_nsf_programs_value=All&field_usscar_scar_sci_group_value=Physical+Sciences&field_ant_research_locations=55&field_usscar_address_administrative_area=All https://usscar.org/directory?combine=&field_usscar_nsf_progr... Could be a fascinating story.
- Metacelsus 3y agoCheck out https://brr.fyi/ https://brr.fyi/
- tester756 3y agoHow did you find it? I don't see it in .net meta data nor about
- hliyan 3y agoGithub profile.
- spamtarget 3y agoThis case I don't understand the sentence: "This was a dumb way to spend my Saturday." What else you could do there?
- roamingryan 3y agoI've been down to McMurdo for a research trip. A couple of things that outsiders find surprising is that most of the people there are support staff and only a small fraction (maybe 20% or so) are the scientists. The support staff are basically people from all walks of life... fireman, carpenters, cooks, mechanics, etc. Basically everyone you need to make a modern city run. However, because of the selection processes, those folks are almost all extremely talented and at the top of their specialties. The number of "swiss army knife" individuals I met with very broad skill sets was astounding. The challenges associated with living and working down there tend to draw quirky and motivated individuals like bugs to a light. And many return year after year. It's a wonderful community.
- nathell 3y agoRelated: A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html http://www.muppetlabs.com/~breadbox/software/tiny/teensy.htm... Tiny ELF Files: Revisited in 2021: https://nathanotterness.com/2021/10/tiny_elf_modernized.html https://nathanotterness.com/2021/10/tiny_elf_modernized.html
- numlock86 3y agoHear me out: Create a runtime that prints Hello World without any input given and you could go as low as 0 bytes for your "binary"! (And yes, I am aware this already exists.)
- Karellen 3y agoYou'd still need a file header (or at least a magic number[0]) that the OS will recognise in order to launch the runtime with your binary. e.g. you'll need an initial "#!" or "\x7fELF" or "MZ" to have your "binary" even start to be run as an interpreted program, ELF, or PE binary respectively. [0] https://en.wikipedia.org/wiki/File_format#Magic_number https://en.wikipedia.org/wiki/File_format#Magic_number
- numlock86 3y agoI don't need a binary. Same rules as the article. The runtime prints Hello World without any input at all. 0 bytes. See "Stück" for example. Calling the runtime itself is not part of the problem. Again, see the article.
- Karellen 3y ago> Same rules as the article. The runtime prints Hello World without any input at all. Sorry, I don't understand how the OS decides to load your "helloworld" runtime, instead of e.g. the .NET Framework 4 runtime, to go with your 0-length binary? The program file created in the article has a valid PE file header, including a ".NET Directory" header section that tells the OS about the runtime to load. If you don't have an equivalent, how is your new runtime being loaded? > See "Stück" for example. I don't understand this reference?
- numlock86 3y agoCalling/executing the binary/runtime on OS level isn't part of what has been counted in the article. Why do you insist on this being relevant then? We are talking about input size (binary) for a runtime. Calling it isn't within the scope. > I don't understand this reference? Neither the article apparently.
- SillyUsername 3y agoOk this is like saying let's make an interpreted Python program run fast, knowing full well it's not intended for that. .Net's intention by using bytecode is safety, sandboxing and performance. Why not teach the right tool for the job and illustrate it being ported to C (or lower) if the aim is to make it smaller? Can you imagine a mechanical engineer trying to turn a screw with a pair of pliers with the justification that it's just a simple screw and they want to see what the minimal number of turns is whilst shaving the screw to improve grip? You'd think they were nuts...
- idlewords 3y agoBecause the true aim of this exercise is to understand and illustrate the various components of a .NET binary. It's like tuning your Geo Metro to go as fast as possible; you do it to learn about the inner workings, not to win a Formula 1 race.
- colanderman 3y agoI actually just did this experiment yesterday with C. Smallest "hello world" I could get from GCC on Linux is somewhere around 14 KiB. (Lots of startup code and unnecessary ELF sections.) So C# has a leg up here. (Granted it's apples-to-oranges, given that this blog post is for C# managed mode (as opposed to AoT).)
- colanderman 3y agoCode-golfing some more, I could get it down to 448 bytes (leaving out standard library, reimplementing syscall/2 by hand, and convincing the linker to drop useless sections). So C does win out here, but moreso by virtue of object format than anything I think.
- colejohnson66 3y ago> .Net's intention by using bytecode is safety, sandboxing and performance. Not true. You can get all of that in C++ if you’re careful and enable compiler flags that no one uses. The entire reason for the IL platform that .NET uses is for cross-platform executables, just like Java. .NET does give one safety in the form of bounds checking and what-not, but that’s the runtime, not the byte code. There’s no “bounds check” opcode; array dereferences are managed by the runtime and bounds checks are elided if safety can be proven (like Rust does).
- ledgerdev 3y agoThis is far more relevant and exciting This is way more exciting. https://twitter.com/MStrehovsky/status/1669502394827419648 https://twitter.com/MStrehovsky/status/1669502394827419648 > "A fully self-contained natively compiled C# Hello World, including GC and everything can be as small as ~440 kB." .net classic framework is windows deprecated legacy, and really no new apps should be built on it.
- TravHatesMe 3y agoUnless you're building an app relying on office/COM apis
- pjmlp 3y agoOr a proper development experience for Windows Forms and WPF.
- kcb 3y agoWhat's different about the development experience. In Visual Studio it doesn't make much of a difference if you're target framework or .Net 5+.
- pjmlp 3y agoDesigner is still buggy, the new out of process model makes it incompatible with existing component libraries, requiring a rewrite. In many things, .NET Core/.NET 5+ is the Python 3 of .NET ecosystem.
- ComputerGuru 3y agoThe resulting exe doesn't really "use" the framework in any way, other than relying on an implementation detail of the backing ucrt.dll library exposed as an unmanaged pinvoke (c# ffi) call.
- mrlonglong 3y agoAs it happens, I was playing around with martypc and msdos 6.22, and installed TurboPascal v1 on it. I built a hello world com that was just under 1k.
- password4321 3y agoThis "minimum viable program" stuff is great! Michal Strehovský used the framework currently known as .NET (as opposed to the Framework formerly known as .NET per OP) to create a snake game in under 8KB with no .NET [nor .NET Framework] runtime dependency. (Medium sucks and Twitter isn't useful right now, but I believe ~"hello world" supported Windows 3.11.) https://medium.com/@MStrehovsky/building-a-self-contained-game-in-c-under-8-kilobytes-74c3cf60ea04 https://medium.com/@MStrehovsky/building-a-self-contained-ga... [https://web.archive.org/web/20200103110836/https://medium.com/@MStrehovsky/building-a-self-contained-game-in-c-under-8-kilobytes-74c3cf60ea04 https://web.archive.org/web/20200103110836/https://medium.co... | https://archive.ph/b6qXE https://archive.ph/b6qXE] https://news.ycombinator.com/item?id=22010159 https://news.ycombinator.com/item?id=22010159 (2020) https://news.ycombinator.com/item?id=22104734 https://news.ycombinator.com/item?id=22104734 You can see the latest work (and sponsorship!) at https://flattened.net https://flattened.net: "bflat - C# as you know it but with Go-inspired tooling".
- andai 3y ago>Can C# apps hit the sizes where users would consider the download times instant? Would it enable C# to be used in places where it isn’t used right now? I wonder if this could be used to make C# webassembly more viable. If I remember, a significant part of the download size is the .NET libraries (themselves written in C#?) On that note, is there any 2D game framework/engine that targets the browser that uses C# and produces small binaries?
- ramesh31 3y ago>I wonder if this could be used to make C# webassembly more viable. If I remember, a significant part of the download size is the .NET libraries (themselves written in C#?) Until WASM ships GC, you're stuck with having to download an entire runtime regardless. >On that note, is there any 2D game framework/engine that targets the browser that uses C# and produces small binaries? Godot supports C# scripting and WASM compilation, probably your best bet.
- andai 3y ago
- msephton 3y agoVery cool. I love stuff like this. I remember a Snake game being made in 8KB of .NET
- markus_zhang 3y agoWhat can we do if we use C or x64 assembly?
- Eiim 3y agoSomething like this? https://codegolf.stackexchange.com/questions/55422/hello-world/229974#229974 https://codegolf.stackexchange.com/questions/55422/hello-wor...
- kazinator 3y agoYes, it was a dumb way to spend a Saturday. You have to count the size of that ".NET Framework 4.x.x", against which the reductions in the hello program are insignificant.
- tgtweak 3y agoProbably 2-4MB in memory while running
- tgtweak 3y agoProbably 4-5MB in memory while running . CLR is heavy.
- metaltyphoon 3y ago.NET 8 Aot changes that drastically. It’s on par or better than Go.
- tkubacki 3y agoPersonally I don't like .NET anymore because it's almost exclusively C# only (which seems quite dated compared to eg. Kotlin). JVM env is much more scattered across multiple languages.
- jug 3y agoAnd personally I think C# is moving forward almost too quickly, as if Microsoft has a compulsion to always introduce new features to the language with each new release, accelerating especially since post-.NET Framework. Funny how different views one might have!
- teh_klev 3y ago> and really no new apps should be built on it. You know you don't need to use the new features, you can still build your apps the way you like and gradually adopt stuff you think might be better for you. Many of the new features aren't always aimed at line of business apps but have been added to improve "systems programming" capabilities. And they aren't taking anything way from you (unless you're jumping from .NET Framework to .NET 5 and beyond, e.g. remoting).
- _ea1k 3y agoThat's funny, because so many of the early sales pitches for .net focused on polyglot as a main feature.
- tkubacki 3y agoDear downvoters please do care to express your opinion instead of downvoting. I will help you making strong statement - why would I use smaller ecosystem (.net vs jvm) and worse general purpose lang (C# Vs Kotlin) if I am not Microsoft shop ?
- osigurdson 3y agoIt seems amazing to that a post about making something small on an end-of-life, Windows only framework. It would have been far more interesting to see what is possible with AOT and trimming.
- p0w3n3d 3y agoCongratulations. You've just dropped unicode support, and made a C call to puts. Wouldn't be easier to compile it using C compiler? thats_just_c_with_extra_steps.jpg
- thebears5454 3y agoYeah skipping compiling kinda really ruins it
- p0w3n3d 3y agoOn the other hand I understand the value of the teardown as educational. I never wrote in C# though, except for some project during studies. I like how they put everything in the binary, living next to normal PE32 executables, but interconnecting between them. It's really done well, too bad it's not interplatform. Java would benefit from such comprehensive packing...
- Alifatisk 3y agoLove these, keep it up! I am glad I am not the only one faschinated in producing lowest possible builds.
- jheriko 3y agothere are some nice examples here showing how to overlap the headers and a few other tricks. https://github.com/rcx/tinyPE https://github.com/rcx/tinyPE