Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Best part: a hello, world GUI app (a dialog with a textbox and a button that pops up a message box) is ~2.5 Mb on Win32.

This was something like 500 Kb back in 2000, but it's still a far cry from your ~200 Mb Electron hello world.



I remember some years ago that I was able to make this less than 1mb. It needed a little tweaking like upx but nothing very complex.

Lazarus should have been the golden standard for creating desktop apps. Every other solution I've tried is subpar either in licensing or costs in general, executable size and resource usage, non native components, extra dependencies etc


I think unfortunately what holds Lazarus back is the Pascal programming language. Although it is a very capable language that can hold its own against other languages, it suffers from a reputation of being obsolete.

It’s a pity that the C family of languages won out over Wirth’s languages. Pascal’s superior string handling alone would have saved us from countless security flaws.


And complex compiling. Pascal compilers are very fast.


Can someone recreate it in Go?


Go is basically Pascal with curly braces anyway. Wonder if a Pascal to Go transpiler could work here...


Delphi/FP Component Pascal has a well-developed object model that is more expressive than Go in general (inheritance, virtual methods including virtual static methods etc), so it's not a 1:1 mapping. But all of these still have a straightforward mapping to Go, even if the output wouldn't be idiomatic, so it should be possible to transpile.


> it's still a far cry from your ~200 Mb Electron hello world.

I think that projects that ship packaged web apps but attempt to use the system native web views where available are really nice, like Wails: https://wails.io/ (so for example, on Windows it would use Webview2, so you don't have to package an entire Chromium install yourself)

Here's a comparison of how the distribution sizes change, Wails in particular also has way faster builds than something like Tauri: https://github.com/Elanis/web-to-desktop-framework-compariso...

That said, I wish we got more native software, or even something like LCL that can target Win32, GTK, Qt or whatever else is available. Sure, writing components that are available on a lot of platforms and work similarly everywhere is a pain for the developers, but I applaud the effort regardless, since the above solutions like Wails don't actually do anything for the memory usage and CPU cycles, whereas native GUI software is better for most apps that don't try to be very interactive.

I could even see myself using Lazarus/Pascal more if it seemed to have a more active ecosystem, right now I couldn't tell you what are the equivalents of something like Spring Boot for webapps, or even consuming Web APIs in client software, handling OAuth2/OIDC/JWT, seems like mORMot 2 would fit the bill the closest?


As I understand, the main problem with native web views is that you now have to deal with all the inconsistencies of e.g. Blink vs WebKit. Also, browsers tend to be more aggressively updated, which translates to potential app breakage due to bugs or deprecated features.

With respect to Lazarus, I agree that the ecosystem around it is not exactly great. It would be interesting to see LCL ported to something more modern that is reasonably simple, cross-platform and has good tooling. E.g. Go, much as I dislike it as a language, would probably be a great fit for something like that. And Pascal being fairly conservative and easy enough to parse, I suspect you could even automate this translation for the most part.


One thing I've always kind of wished for was a way to write the WEB dialect of Pascal in Lazarus --- then one could use Web2C --- if one could just link in platform-specific GUI libraries....


2.5 MB is for most of the Lazarus Component Library (LCL) with minimal size increases even as program complexity grows. For example, Dadroit JSON Viewer EXE is less than 6 MB while having complicated tree views, JSON handling, networking, and more. By the way, an empty CLI EXE on Windows is less than 50KB.


Why doesn't the linker strip out unused code?


I imagine it's for the same reason Delphi can't strip much, which is that it supports run-time reflection. You can create an instance of a class using a string of the name.

Forms (windows) are deserialized during loading, which relies on this mechanism.


Best part for me that it's a single file executable. I chose to do a thing in Pascal last year just because of this one killer feature. I made some initial attempts to achieve this with something else but I didn't find any modern tool that could do that without some weird, sometimes involved, sometimes straight up experimental steps.


I think Go will do it, but I indeed enjoy Free Pascal for this as well. It's also nearly trivial to set up cross compilation using FPCUpDeluxe, so I've shipped applications to clients on Windows when I do all development and compiling on GNU/Linux.


.NET can create self-contained executables pretty easily (via _dotnet publish_), both including the required framework assemblies and without them. But they'll still be comparatively large.


I couldn't find the right checkbox to click in VS.


Are those not just large zip files?


Not necessarly, that is a possible option if you want to keep the JIT around, other one is to AOT compile, 100% straight machine code, like any other compiled language.


Does it matter what format they use to pack the exe with data?


For JIT binaries it’s best to apply /p:PublishTrimmed=true which (sometimes massively) reduces their size. Applications written in AvaloniaUI or, nowadays, WinUI 3 can be compiled with NativeAOT which reduces the size and memory usage even further.


> written in AvaloniaUI or, nowadays, WinUI 3

Be aware that this is what you're getting into when you pick dotnet for GUI applications. It's been that way for decades at this point, there are many unfixed bugs in WPF for example, in spite of it being touted as the final word in GUI development in its time and still being used for some Microsoft applications like VS.

Meanwhile, with Delphi you were using VCL 20 years ago, and you're still using VCL today, and its development velocity and performance is light years ahead of anything Microsoft put out during that time. This also applies to Lazarus's LCL.


Even so I would still pick WPF over VCL/LCL today if I don't need cross-platform support. It just does so much more, especially when it comes to data binding.

The funny thing about Windows GUI story is that the older the framework is, generally speaking, the better it is supported. WinForms still gets bug fixes and improvements; so does WPF. OTOH if you were early on the WinRT bandwagon, tough luck, and it's been meaningless churn ever since.


Wait what? AvaloniaUI is not WPF, neither is WinUI3 which is new and maybe something you'd consider if you only target Windows (I presume it's better than using it through Uno, otherwise you'd probably choose Avalonia to support all OSes).


GP argues that UI frameworks in .NET come and go, despite each one being “the final one”.



I was going to complain how Avalonia still has issues with large binaries even with NAOT but I just tested it on https://github.com/sourcegit-scm/sourcegit on Windows, and the resulting size of the folder without symbols (the binary and like 4 dlls) is ~55MiB. The binary itself is 41MiB which is as much as Qt6-based qBitorrent binary takes on Windows. So it seems while Avalonia works well enough on macOS, the size of binaries and memory consumption are higher than on Linux and Windows huh.


Fair enough, although I trust them more to sort out those issues, than to keep waiting for Project Reunion to deliver what was promised at BUILD 2020, or by C++/WinRT team at CppCon 2017 (which is WinUI 3.0 foundation).


Maybe you're the person to ask. My Python Qt app is sluggish when it loads tens of thousands of values from SQLite. Various variations of pagination and lazy loading hurt usability. But isolating the issue and testing with C++ and Rust show that those two languages don't have the performance hit of Python.

I could use C++ and stick with Qt, but I'd much prefer Rust. Rust has no good Qt bindings. What are my options?

The app makes use of QV/HBoxLayout, QWidget, Qdialog, QPushButton, and other really standard features. It reads from the filesystem, reads and writes to SQLite, and outputs sound from mostly ogg files at various speeds (through VLC behind the scenes). I stick with Qt because I like how it integrates with KDE and other desktops flawlessly.


> What are my options?

> I stick with Qt

These come up on search results if you combine Qt plus the language.

Go:

* https://github.com/mappu/miqt

Java:

* https://github.com/OmixVisualization/qtjambi

Nim:

* https://github.com/jerous86/nimqt

* https://github.com/seaqt/nim-seaqt

Zig:

* https://github.com/rcalixte/libqt6zig


Thank you. I don't see Java as having a performance edge over Python ))

Same for the other languages - they likely won't have the performance of C++ or Rust. But I'll test them anyway, even just for the academic exercise the endeavour is worthwhile. Thank you.


Java is about an order of magnitude faster than Python. It's a JIT-compiled statically typed language, after all, and Oracle's JIT compiler is the best in class.

That said, given your original request, I don't think it has much to do with language choice. Displaying a very large number of rows in a data grid or similar is a classic GUI task in line-of-business apps, and the answer has always been either virtualization (lazy loading) or pagination.

One trick to improve UX when virtualizing data is to do preloading asynchronously in the background - ideally on a separate thread - and start it before the user scrolls all the way to the end (e.g. when there's still a couple of pages of data left).


Yes, that is exactly what I have been doing. Thank you.

One thing that I would like to discover is how to adjust the scroll bar size so that it appears as if more records are loaded than actually are.


In Qt you should use the model/view framework if possible. It gives a virtualized list with a render callback. https://doc.qt.io/qtforpython-6/overviews/qtwidgets-model-vi...


Thank you. I will definitely peruse this.


Java is actually pretty fast, and certainly much, much faster than python. There are plenty of reasons Java isn't my preferred language, but speed is not one of them.


This is great to know, thank you. I still remember the days of the knock, knock jokes about Java.


The jokes were mostly about startup time for the JVM (only happens once as when its in RAM it stays there and the loading time doesn't repeat for the next java program you run). It was also a lot more notable in the 90s when java was a browser plugin to run applets and browsers were single threaded (so the browser froze for a few seconds while the JVM loaded).

I think it's been out of date for a long time with modern computers having much more RAM and speedy SSDs (and also JVM optimizations). For actual run time performance once its loaded the JVM has had great performance in the early 00s already and improved since. And for server side it was never an issue as you don't restart the server very often (so the JVM is always already loaded).


I'm not necessarily advocating java, I think rust is def the best solution in most cases -- but java definitely has a significant performance edge on python. The JVM will never be quite as fast as native code, but it's very fast these days and it gets better every year. Certainly much, much faster than python on the average.


Thank you, I will evaluate Java for this purpose, though I almost certainly won't actually use it in the rewrite.


https://areweguiyet.com/

Also did you test similar functionality in C++, I haven’t compared many implementations but I app I use that has an SQlite db being read with Qt(C++) is pretty sluggish whenever you touch the DB.

Maybe store the values in a dict and only read/write from sqlite when needed. Dicts are very fast in python.


This website is useless if accessibility compatibility is not mentionned.


Yes, that's what I'm doing. It's the initial load that is heavy.

I've also tried implementing lazy loading and pagination, with a pseudo-infinite scroll technique based on SQL LIMIT pagination, but the resulting CPU and memory spikes are noticeable.


> I could use C++ and stick with Qt, but I'd much prefer Rust. Rust has no good Qt bindings. What are my options?

There are several Qt binding for rust, for example cxx-qt. I haven't tried myself but it looks maintained. Why is it not good?

Otherwise, the most promising equivalent to Qt in Rust would be Slint.


Thanks. I forget why I discounted cxx-qt. It think it didn't support some common Q* object but I don't remember which. I'll experiment with it and with Slint, which I've been eyeballing anyway. Thank you.


Is Cython and/or avoiding copies an option?


Cython is a great idea, thank you. I'll definitely try that. The code is all properly typed anyway.

I'm not sure what you mean by avoiding copies. I'm rather stringent with memory, I don't have superfluous copies of data in memory. Or did you mean something else?

Thank you.


Sometimes Python code makes copies when we’re not expecting it to. Hard to know but performance optimization books/blogs discuss it.


I'll Google for that, thank you!


More generally, which all tools that can target multiple platforms, produce relatively small binaries for simple applications? And which of these are lean themselves?

May be I am doing something wrong, but I had installed Android Studio, then Android emulator, SDK, etc., and before I could get a hello-world app to compile, some 30 GB were gone from my disk space.

If it comes to it, I do not personally mind using multiple tools and code for different target platforms, as much as (a) both the tools themselves and the binaries generated are lean, and (b) the development tooling itself is on a single platform just so that I do not need to maintain multiple hardware. (I currently use Windows, would likely need to move over).

Thanks.


Java perhaps? That was one of the core promises of the Java ecosystem.


> produce relatively small binaries for simple applications

The problem is that you need to have a huge Java runtime installed or use something like Jlink which still produces very large binaries for GUI apps.

I think wxWidgets is the Lazarus alternative that is the closest to what grandparent was asking for.

https://wxwidgets.org/


Thanks.

Is there something similar for Android as well?

Asking ChatGPT, it has made recommendations for Haxe most importantly, which claims to support a large number of platforms.


On Android, Java running on top of the Android Runtime is the native framework for apps.


Who remembers Steve Gibson's 'little corner of the web'? He wrote super small Windows applications in assembly: https://www.grc.com/smgassembly.htm


Definately remember it fondly - and Jeff Duntemann who continues to update and publish his definitive works on learning assembly - the latest edition/revision is: "x64 Assembly Language Step by Step" - https://www.contrapositivediary.com/?page_id=5070


Vividly!

In particular, his tech e-mail announcement/newsletter was where I first learned of a small startup w/ the unlikely name of "Google".


That’s a lot. I don’t know the specifics of Lazarus, but this typically screams static linking with everything and the kitchen sink being thrown into this one binary. Entire cross-platform runtime, GUI assets, metadata, etc. Could be a fat debug build, too.


It was the common complaint about writing VCL apps in Delphi - that single message box app would be 0.5MB binary.

But that was the static overhead of VCL core library and the benefits were considerable compared to writing raw WinAPI.

And unlike MSVC 16kB WinAPI executable you didn't have chance of sudden surprise "oh, but you need to update msvcrt.dll to run this" because Delphi (and Lazarus/FPC) default to statically linking the runtime


That's indeed a statically linked binary. Release, with smart linking (so only things that are actually used are linked; otherwise it'd be ~20 Mb), debug symbols stripped. Measuring .exe size when linking dynamically would kinda defeat the purpose of the experiment, since you'd still need to distribute the DLLs to the users for any real world app.


Not Pascal but here is something I wrote on the same lines in C++: https://latedev.wordpress.com/2011/10/06/simple-windows-dial...


But if you don't target windows, but the web as target plattform, you will need just 53 bytes that will work, wherever a browser works.

<input type="button" onclick="alert('hello world')" />


Even if you do target windows, tauri apps can be a couple megabytes


Now do a data grid backed by a database.


Just some lines more? I am sure modern LLMs can print out tons of different versions for your specific usecase and it will be way less than 2.5 MB.

HTML and JS is compact. The browser is not. But often installed already, so my PWA is very small as a result, but behaves quite native.

(But if you mean, that Lazarus can do that easily with a GUI, that would still be cool. Can it?)


Can't you still do much the same with WinForm, or maybe GTK?


With WinForms you can do much better, in large part because .NET itself ships with Windows and thus the app can just rely on it being there, but also because C# compiles to bytecode rather than native code (so it's not exactly a fair comparison). Anyway, the identical hello world GUI app in C#/WinForms is ~11 Kb.

With Gtk, no, because it implements all widgets by itself rather than wrapping Win32, so it'll necessarily be larger. Also, statically linking it can be a pain (and AFAIK isn't even supported in Gtk 4 anymore).


Even if C# compiles to bytecode, NGEN has been part of the framework since version 1.0, although using strong named assemblies might be bit of a pain.

Then there is .NET Native and Native AOT.


You couldn't redistribute NGen'd binaries tho, it was basically a local AOT'd cache.

As far as Native AOT, last I checked it requires trimming which breaks WinForms (and WPF) according to the official docs.

I don't think this matters much, though. There's simply no practical reason to AOT-compile a WinForms app. Not when the framework is guaranteed to be there, and JIT compiler is plenty fast.


Is that statically linked or dynamically link? If the later, does it include all the libraries and assets it uses?


Does it have dark theme support and does it sync it's theme with the system one?


Not with the Win32 backend, since those widgets themselves don't have that notion.

Qt backend should be able to do that, though (but then of course you need all those Qt DLLs).


Windows widgets don’t have dark mode support on Windows?


Win32 ones don't only new WinUI ones do (similar to GTK2 vs GTK3+). You need to add that coloring manually. You can query the dark mode with Win32-only API[1] but you need to make your own styles or you can use undocumented APIs (that can break anytime) that Microsoft uses internally for the applications shipped with Windows[2]

[1]: https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-wi... [2]: https://github.com/ysc3839/win32-darkmode


(GTK 2 does support dark themes, of course, it just doesn’t have a concept of “light/dark theme variants” natively. And come to think of it, it’s the same in Win32: see e.g. the Zune theme for Windows XP.)


> Not with the Win32 backend, since those widgets themselves don't have that notion.




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

Search: