HNHacker News
TopNewBestAskShowJobs

mtzet

521 karma · joined November 25, 2016

submissionscomments
mtzet··on Show HN: C3 – A C alternative that looks like C
> I don't think Zig has the same goal.

It seems to me that the only meaningful difference in their goals, is that C3 wants to stay as close to C as possible, including having familiar syntax.

> Also, they usefully compare the languages [...]

The comparison seems disingenuous.

Zig has a module system where each zig file is a module and it has a mechanism to specify public parts of the module.

One of the standout features of zig is the integrated build system, which uses a reliable caching mechanism to allow incremental builds without rebuilding the world. It's somewhat remniscient of bazel actually.

The zig std library features hashmaps and variable length arrays. Strings are not different from slices of u8. It's unclear to me what C3 means by "built-in strings". The only reference I could find was under "crazy ideas", where they vaguely refer to needing to figure out memory management. That seems like a pretty big outstanding issue for a C competitor.

So the unique feature of C3 appears to be the contracts system of pre- and postconditions, which are only used as language hints to the compiler.

mtzet··on Thriving in a Crowded and Changing World: C++ 2006–2020 [pdf]
> I find it surprising that anyone could imagine that the creator of C++ is unaware of its issues.

While C++ adds a lot of new features, it does very little to solve the problems inherited from C. The lack of static introspection, a real module system and tagged unions are all inherited from C. I do think it's fair to think that if a problem is not addressed in 30 years, it just might not be considered important.

Adding tagged unions is not a sophisticated language feature. Fat pointers (c++20 std::span) also seems like a no-brainer. Maybe I'm biased by hindsight, but these features were implemented by contemporaries like Pascal?

Actually, the paper also contains a great section about fat pointers:

> The obvious solution is to supply an abstraction that holds a pointer plus a size. For example, in 1990, Dennis Ritchie proposed that to the C standard committee: "'fat pointers' whose representation will include the space to store the adjustable bounds at run-time" [Ritchie 1990]. For various reasons, the C committee didn’t approve. At the time, I heard the priceless comment: "Dennis isn’t a C expert; he never comes to the meetings." It is probably good that I don’t remember who said that.

mtzet··on Thriving in a Crowded and Changing World: C++ 2006–2020 [pdf]
At a 168 pages, I only had time to skim it, but this was much better than I thought it would be. He honestly addresses many of my complaints about C++.

In the discussion of variant, optional and any: - He bemoans that "The possibility of direct language, as opposed to standard-library, support appears not to have been seriously considered" - He acknowledges that "variant and friends address an important problem, but inelegantly." - He considers variant, optional and any a "stop-gap measure" - In discussion of a pattern matching library he acknowledges the need for "both closed sets of alternatives (algebraic types) and open sets (class hierarchies)." and explicitly says the aim is to remove the visitor pattern (whereas c++17 just added std library syntax for it)

In the modules discussion (9.3.1), he also identifies the problem that "[the hello world program] yields 419,909 characters for the compiler to digest". I wish he'd also address visiblity specifiers at a module level, rather than just at a class level.

In the static reflection discussion (9.6.2), he discusses the typical problem of iterating over members of a struct. This is indeed a point where C++ has not really progressed much since ANSI C.

The discussion of error handling in chapter 7 felt a bit lacking. My main problem with exceptions isn't performance, but that I can't determine if I've handled all error conditions. The idea of using exceptions for non-local errors and error codes for local errors is too vague. It also doesn't really make error codes much easier to use. For my money, I still think that using error codes and providing syntactic sugar for dealing with the common boilerplate is the best compromise. I can accept exception/panics when they are not supposed to be caught, but just cleanly terminate the application.

Maybe C++ will solve these problems in the future (C++23? C++26?), maybe not. In the meantime, the new languages on the block are attractive because they solve these problems _today_.

mtzet··on Gio – write immediate-mode GUI programs in Go
This gets brought up pretty much every time immediate mode GUIs are discussed on HN. I think your comment is reasonable, and I don't disagree, but I also think it's important to not throw the baby out with the bathwater and dismiss immediate mode GUIs for accessibility reasons.

It's not at all clear to me that the right approach is to have both the accessibility interface and the GUI be generated from the same components. It seems to me that it's just approaching the lowest common denominator of a passable GUI and a passable accessibility interface.

The traditional widget-style GUI paradigm asks you to essentially copy all your application data into their format and to keep this format in sync with your own data. This is tedious, and I believe hinders the creation of better GUIs. On the flip-side, owning your data structure means it can indeed hook into the accessibility API for you.

Immediate mode GUIs provide an alternative approach, where they only handle rendering stuff on screen. Since all the data structures are now properly controlled by the programmer, it is much easier to create dynamic GUIs. Taking a step back like this provides an opportunity to further the state of the art.

The solution I see to providing accessibility in immediate mode GUIs is that the programmer has to hook into the accessibility API themselves -- if it makes sense. It's not clear to me that certain advanced GUI programs can ever be very accessible. Yes, this is more work, but there's also an opportunity to create richer experiences for people with disabilities.

mtzet··on Systemd: The Good Parts
> when I was in the Systems Group at Sun we worked with AT&T on their solution which was the whole "run level" thing

Interesting that you mention Sun. Didn't SMF precisely replace runlevels with SMF milestones[1] in much the same way systemd replaces runlevels with target units?

[1] https://docs.oracle.com/cd/E23824_01/html/821-1451/hbrunleve...

mtzet··on The Return of Fancy Tools
On the other hand, I find the integration between Atlassian tools to be pretty barebones. It feels very clear to me that Atlassian tools are really developed separately, with a separate jira task to integrate specific parts. There's no "coherency" to them.

You are right that it's difficult to replace the entire Atlassian suite. The thing about Atlassian is that when there's if there's a box to check on a feature list, they've made sure to check it. If you go around the office asking everyone what features they want, Atlassian is going to check all those boxes. That's pretty hard to compete with.

mtzet··on What’s wrong with Git? A conceptual design analysis (2016)
Working at file granularity is fine, but I've never gotten a good workflow for using the CLI to stage individual hunks. Nothing beats selecting the lines I care about in magit (or any other GUI) and clicking to stage.
mtzet··on Perlis' Epigrams (1982)
> 20. Wherever there is modularity there is the potential for misunderstanding: Hiding information implies a need to check communication.

This is a really great point. Along the same vein: modularity has a cost too. A cost in terms of communication. The benefits of modularity should be weighed against this cost.

We're really good at talking about new patterns to increase modularity, in particular in the OOP tradition (always hide data, every data structure is its own little module with a public interface). We're very bad at talking about the costs associated with these.

mtzet··on Joe Is Wrong (2009)
These discussions tend to boil down to OOP vs FP. That's a false dichotomy. The alternative to OOP is not FP, it's pre-OOP imperative programming with various techniques a la carte.

Should data and functions be together? That's a choice you can make on a case-by-case basis. It makes total sense that a HashMap has an insert() method. On the other hand, maybe your Player object is just some data which is interpreted by a PhysicsSystem and MovementSystem etc. Maybe it's clearer that all the physics calculations are in a common PhysicsSystem rather than being spread out into several implementing classes.

Should you use a switch-statement or a polymorphic interface? If you're traversing a graph with a fixed set of nodes, or you need to change all systems when new nodes arrives, the (exhaustive) switch may be preferable. I'd certainly prefer it to the visitor pattern.

If you can extract a calculation into a pure function, then that's great. If you're doing something inherently stateful, FP techniques are probably not too great. Maybe you can afford a high-level functional interface, but keep the implementation stateful.

The problem with OOP, FP, etc. is not that the techniqures are BAD, it's that all techniques are trade-offs. We're very good at talking about the advantages of some technique, but seem always forget the costs associated with it.

mtzet··on How Safe Is Zig?
You're also forgetting: simpler language/explicit code => faster build times. Zero-cost abstractions are only zero-cost in optimized builds and and complex optimization isn't free.

Whether static checking vs faster iteration time is more important depends entirely on the context, but rust isn't going to help you when you accidentally did front-face culling instead of back-face culling.

mtzet··on How Safe Is Zig?
I think this is a roughly fair assesment, but I also think it's important to contextualize memory safety. Ultimately, the goal here is to produce /correct/ software. Memory safety is a subset of this, but there are other aspects to correctness as well.

I really like zig's approach of explicitness and fast iteration cycles. Fast compile times and the very flexible build system makes me hopeful for a really slick workflow for embedded development,where zig code can be used to deploy and test as well. For my own use I think it's a clear win.

On the hand, the amount of damage poorly architected zig code can cause is about as large as for poor c code. For typical enterprise code the rust compiler will make sure that many bad decisions will not even compile. There's still a risk of towering abstractions, but at least I could avoid spending as much time debugging hideous race conditions.

mtzet··on How to Study Mathematics (2017)
I think this misses a pretty important part of mathematics, which I find is nessecary to grokking fields like linear algebra, algebraic geometry, algebraic topology, and many more.

What's missing is /why/ the definition is the way it is. What is it trying to encapsulate? A lot of mathematics is built up from simpler ideas being generalized until finally a purely algebraic definition is reached. The algebraic definition is completely void of context and any intuition, but it is very powerful to work with. The definition is in a sense the /result/, not the starting point!

For example, a beginning student of algebraic topology might start reading Hatcher's Algebraic Topology. Here simplicial homology is defined in terms of abstract functions d with certain properties. How did they arrive at this definition?

One answer is to start with complex analysis. Here you can notice that the complex plane and the plane without zero can be told apart by the function 1/z. This function also doesn't have an anti-derivative. Thus you begin to see how to define topology of the complex plane. Now extend this line of reasoning to the calculus of differential forms and you end up with the de Rahm Cohomology. Finally, you can realize that you can get the same results without having any interpretation of your functions. Thus begins the purely algebraic theory. The proofs may be different, but you can now /guess/ the theorems.

Of course in the above I omitted that differentials forms are defined in terms of a wedge product, which is also an abstract algebraic definition. This also has an explanation...

Modern mathematics is rife with explanations like the above, but they are often hidden away. It's very remniscient of the simple vs easy discussion of programming. The algebraic definition may be "easy" but it carries a lot of baggage.

mtzet··on Zig, parser combinators, and why they're awesome
While having nice libraries is always great, I'd also like to plug the simple zig std library functions.

I was very pleasantly surprised by how easy was to start parsing simple stuff using std.mem.tokenize() and std.mem.split(). Somehow watching Andrew programming some Advent of Code using these very simple functions made it 'click' for me how parsers are just ordinary programs.

mtzet··on Zig, parser combinators, and why they're awesome
Well the choices so far seems to be manual memory allocation, RAII or GC. The complexity of C++/Rust indicates that RAII is certainly not a panacea either. GC offers distinct trade-offs as well.

Zig takes a stab at the problem by trying to make manual memory management more ergonomic. I've been pleasantly surprised at how easy I found it to do tasks in Zig I would otherwise have used a scripting language like Python for.

If go's fast GC is taking a stab at C's territory, then I think Zig is taking a stab at the managed runtime's territory. Ultimately the judge is still out.

mtzet··on Why northern Europe is so indebted
Yeah it seems kind of obvious. It's also worth pointing out that you can get a 30-year fixed rate loan at just above 1% in interest [1]. Money is cheap, so people are likely to borrow more.

[1] http://www.nasdaqomxnordic.com/bonds/denmark Select expiry 2053, no deferred amortization.

mtzet··on One Way to Represent Things
What simpler alternative is there? The OOP way would be to always hide data. This certainly has a different set of trade-offs, and sometimes requires the visitor pattern. Maintainable and simple are not words I would use to describe these cases.

The other alternative is to emulate sum types through run-time type information or using code generation like protobuf. I also fail to see how these approaches are simpler or more maintainable.

Sum types are not a panacea for all software development ills, but they're the simplest and most direct solution to a concrete problem: My data is either this type or that type.

mtzet··on Enable hibernation when Lockdown is enabled
> In 2012 Microsoft started requiring vendors ship systems with UEFI Secure Boot, a firmware feature that allowed[5] systems to refuse to boot anything without an appropriate signature. This not only enabled the creation of a system that drew a strong boundary between root and kernel, it arguably required one - what's the point of restricting what the firmware will stick in ring 0 if root can just throw more code in there afterwards?

I still think there's plenty of point. I usually don't care about what ring0 can do; I care about what the system can do. Root can steal or destroy my data, or make my system do bad things.

The reason for restricting what kernel will be loaded, is to restrict what will happen at userspace.

A common use-case is bitlocker-style encryption. The system decrypts my harddrive using keys from the TPM. My own userspace is secured at the userspace-level using a login prompt. To defend against an attacker sideloading a different OS, I rely on secure boot to only load my kernel and hence my userspace.

I'm actually having a bit of a hard time finding really good usecases for this lockdown feature. On embedded systems the secure boot keys are often fused in, but I suppose the kernel, but potentially not root, could be able to change the tpm keys on an x86 system?

mtzet··on On navigating a large codebase
The advice about using both grep /and/ the IDE is very good. Often they are framed as in opposition to each other, but in reality they're just tools. IDE's are great when they work, but it's entirely possible to make it confused.

I keep hearing to get better IDE's, especially from Java developers who seem to have nicer IDE's than us C++ schmucks, but even the best IDE will not save you when your program is really an interpreter for some ad-hoc, unspecified dynamic language implemented on top of YAML or XML.

I highly recommend having shortcuts for both ripgrep, fd and clangd in your editor. Also remember you can use the .rgignore file.

mtzet··on Datatype99: C99 with Sum Types, v0.1.0
I find it really interresting that such a simple concept as a tagged union, which appeared at least as far back as ALGOL 68, could be completely abandoned during the 90's and 00's where OOP reigned surpreme, and only seems to be gaining popularity again now that pattern matching is all the rage.

It's just baffling to me that tagged unions could be shunned in favour of the visitor pattern. How could that ever look like progress?

Being a millenial, I don't know what programming was like the 80's, but surely tagged unions must have been bread and butter for Pascal programmers?

mtzet··on Wayland is not ready as a 1:1 compatible Xorg replacement just yet
> Can Wayland handle this?

Yes.

mtzet··on OpenBSD on the Lenovo ThinkPad X1 Nano
It's a trade-off. SMD-soldering takes up way less space, which is important in an ultra-portable. Even if it was upgradeable, it's not clear to me that the CPU/motherboard even supports more than 16GB per memory slot. Adding an additional memory slot would greatly expand the physical requirements.

Even in my many years of having desktop PC's, I think I've only once upgraded RAM separately and never upgraded the CPU without replacing the motherboard.

If you're talking repairability, than I just haven't had to replace my RAM sticks due to wear.

mtzet··on Why Zig when there is already C++, D, and Rust?
Compile times will likely improve in the future, but they're still likely to be much longer than those in zig. Especially if you also consider the body of software surrounding zig/rust. I believe zig developers are more likely to take a stance that libraries should be more specific and smaller, while rust libraries tend to be more all-encompassing. Even if the resulting code is small and efficient, the compiler has to do more work.

I think Bryan Cantrill had a pretty spot on description of this kind of thing in his "values" talk, even if zig is not on his list.

mtzet··on Tell HN: Dropbox now requires access to contacts for Google login
They do provide provide first-party Linux support, which Google and Microsoft lack.

What other reason should I have for trusting Microsoft or Google over Dropbox? (Serious question, I've been considering my cloud sync provider recently).

mtzet··on Simple Bank Is Closing
What additional benifit does moving money around provide?

From my perspective, there is not much difference between money moving around in the banking system vs moving around on your budget sheet, except the banking system might charge overdraft fees if the accounts are mismanaged.

Based on that reasoning I've taken the approach to only have as many bank accounts as I need to utilize their services, and to interact with them as little as nessecary.

mtzet··on Death by 1000 layers: the perils of over-abstraction in Java (2017)
I don't know any C++ IDE capable of doing this. Do you have any in mind?
mtzet··on What is your favorite C programming trick? (2009)
Inline asm?
mtzet··on macOS unable to open any non-Apple application
Exceptionally bad is a bit harsh. Windows is first tier support with Linux coming in as a second. In my experience they are pretty good about fixing remaining issues in firmware updates, which can be installed using fwupd (I don't have a Windows partition at all). I belive there's even a GNOME Software front-end if you prefer things being very easy.

I don't need to use throttled on my X1 Carbon 7th and they recently added mainline support for the fingerprint reader. All I had to do was enable it in GNOME Settings.

mtzet··on Why Concurrency Is Hard
I disagree in the general. It's very easy to write a spec that contradicts itself and is impossible to actually implement.

Some things do have to be designed, and not just thrown together though. That may be through spec, but it could also be working things through on paper. Concurrency is certainly one of these. Other things need to be iterated on in code. I'd hate to play a platformer where the movement mechanics were specced out by a comitee before any code was made.

mtzet··on Microservices – architecture nihilism in minimalism's clothes
I agree wholeheartily that Conway's law is a very useful guiding principle for making "architectural" decisions.

I also think this applies much more broadly than just microservices vs monoliths. I recently moved ~40 repositories into just a few. What I've found is that anything that releases together (by teams and timeframe), should stay together. This helps ease modification of related components in an agile way, simplify tagging components, simplifies CI workflow (no multi-project pipelines).

Anything that breaks with this principle should have a concrete reason for it. If you need to combine the results of several teams into one large release, it may be easier to develop tooling for handling it all in one repository rather than developing tooling for handling many repositories. That's really the monorepo tradeoff.

Similarily, there are concrete reasons for breaking a service into smaller parts. Perhaps you want to horizontally scale a part of the service. Perhaps you need a part of the service to have a different lifecycle. But you're paying with increased deployment complexity, so you'd better get something worthwhile in return.

mtzet··on XMHell: Handling 38GB of UTF-16 XML with Rust
The problem with JSON is that it's only solving the trivial first part of the problem. You still have essentially a parser after the JSON parser to handle your own logic. The more features you add, the closer down the path from simple towards Yaml and XML you move. But even with XML, you'll have to implement your own domain-specific validation for those things not represented by schemas etc. In the end, your simple format isn't so simple anymore.

Sometimes I wish for specific configuration formats which are fit for the purpose instead of the bolted-on monstrosities like jinja-templated yaml. This has all the problems you mention, but I think we're losing something by the culture that we're not supposed to write our own parsers anymore.

← PreviousPage 2 of 4Next →