Fair point, I phrased that too broadly, and you are right about the loose correlation.
What I was gesturing at, badly, was more that Zig’s low-abstraction / explicit-by-default syntax tends to have you write more boilerplate-y code in general that are more annoying to write and maintain, while not buying you enough over a language with better tooling and ecosystem and compiler optimization like Rust.
Rust's enums can carry data. You can write the same thing in C, but because it does not have the enum feature, you have to do it yourself. They're sometimes called "tagged unions" for a reason, you use a union + a tag when doing it by hand:
I haven't actually compiled this, but it should compile to almost the exact same, if not literally the exact same, machine code. Yet one is way more verbose than the other.
I'm not sure individual examples is the right way to go about this. A correlation isn't a guarantee for every instance and it's easy to concoct individual examples which tell any story you'd like them to.
To properly answer this you'd need to compare a large number of identical implementations written idiomatically in several languages and see if there is a correlation.
If I were to throw my 2 cents in I'd say "a very weak correlation" is probably right. Not because verbose languages HAVE to result in more bloated code but because it seems to me languages fine having a lot of bloat in the syntax also tend to be languages fine having a lot of bloat in the implementation or attracted to abstraction (which never does seem to actually compile away fully in large projects, even though it often largely does).
Sure, I did not think that one example is a full survey of all possibilities. I think that it's quite intuitive that this feels right:
> it seems to me languages fine having a lot of bloat in the syntax also tend to be languages fine having a lot of bloat in the implementation or attracted to abstraction
Which is why I chose an example of the exact opposite: a language not known for bloat, taking way more code to produce the exact same thing as one that's more succinct.
It's not as good as some sort of scientific survey of a wide variety of options, but if you can find examples in all directions, assuming there's no correlation until proven otherwise is a pretty solid bet, I think.
I'm not saying it's not as good as a scientific survey, I'm saying it results in no information at all about the strength of correlation one way or the other.
E.g. one could seek to find a 6' preteen and 6' adult to construct a counterexample to the idea height is in some way correlated with age. Doing so gives just as little evidence of what the strength of correlation is as seeking to find a 5'9" preteen and a 6' adult to show the correlation is positive or seeking to find a 6'1" preteen and a 6'0 adult to show the opposite. I.e. it doesn't follow one can filter the search as they please and then assert that's what the correlation of the unfiltered searches should be assumed to look like. In all 3 cases of positively correlated, negatively correlated, and not correlated we'd expect to be able to construct an example which says whatever we want to say - that isn't the same thing as sampling what the actual correlation usually is.
I read my parent ask asking a question: is there a correlation, or not?
I am saying that I do not believe there is a correlation between source code length and binary length. If that's what benced meant by their question, then yes, I agree :)
I’m quite sure there is a certain amount of correlation unfortunately, mainly because there are micro patterns (e.g. IO, allocator) that can’t be modularized into functions. Lots of manual copy-pasta.
You can further reduce the difference by passing Expr by pointer in the C version. At that point I think the only difference in the assembly is the order in which the cases are handed.
Ah yeah, honestly both should probably be passed by pointer anyway. But that makes me wonder about the actual differences here and why... maybe something fun to dig into.
Passing by pointer (in C) reduced the difference a lot, but swapping the order of Add and Int in the Rust enum was enough to reduce the different to:
cmp ecx, 1
je .LBB0_3
vs
cmp ecx, 2
jne .LBB0_2
LBB0_3 and LBBO_2 were the same in both outputs (up to alpha renaming).
Oddly, both sources seemed to be quite sensitive to match switch and enum reordering, resulting in very different generated code. Possibly something to look into further.
Fair point, I phrased that too broadly, and you are right about the loose correlation.
What I was gesturing at, badly, was more that Zig’s low-abstraction / explicit-by-default syntax tends to have you write more boilerplate-y code in general that are more annoying to write and maintain, while not buying you enough over a language with better tooling and ecosystem and compiler optimization like Rust.
I don't think you can draw the conclusion that source length and binary size are correlated. For example, in Rust:
Rust's enums can carry data. You can write the same thing in C, but because it does not have the enum feature, you have to do it yourself. They're sometimes called "tagged unions" for a reason, you use a union + a tag when doing it by hand: I haven't actually compiled this, but it should compile to almost the exact same, if not literally the exact same, machine code. Yet one is way more verbose than the other.I'm not sure individual examples is the right way to go about this. A correlation isn't a guarantee for every instance and it's easy to concoct individual examples which tell any story you'd like them to.
To properly answer this you'd need to compare a large number of identical implementations written idiomatically in several languages and see if there is a correlation.
If I were to throw my 2 cents in I'd say "a very weak correlation" is probably right. Not because verbose languages HAVE to result in more bloated code but because it seems to me languages fine having a lot of bloat in the syntax also tend to be languages fine having a lot of bloat in the implementation or attracted to abstraction (which never does seem to actually compile away fully in large projects, even though it often largely does).
Sure, I did not think that one example is a full survey of all possibilities. I think that it's quite intuitive that this feels right:
> it seems to me languages fine having a lot of bloat in the syntax also tend to be languages fine having a lot of bloat in the implementation or attracted to abstraction
Which is why I chose an example of the exact opposite: a language not known for bloat, taking way more code to produce the exact same thing as one that's more succinct.
It's not as good as some sort of scientific survey of a wide variety of options, but if you can find examples in all directions, assuming there's no correlation until proven otherwise is a pretty solid bet, I think.
I'm not saying it's not as good as a scientific survey, I'm saying it results in no information at all about the strength of correlation one way or the other.
E.g. one could seek to find a 6' preteen and 6' adult to construct a counterexample to the idea height is in some way correlated with age. Doing so gives just as little evidence of what the strength of correlation is as seeking to find a 5'9" preteen and a 6' adult to show the correlation is positive or seeking to find a 6'1" preteen and a 6'0 adult to show the opposite. I.e. it doesn't follow one can filter the search as they please and then assert that's what the correlation of the unfiltered searches should be assumed to look like. In all 3 cases of positively correlated, negatively correlated, and not correlated we'd expect to be able to construct an example which says whatever we want to say - that isn't the same thing as sampling what the actual correlation usually is.
I think you are saying the same thing as benced - just because Zig source code is verbose is no reason to assume the binary should be larger.
I read my parent ask asking a question: is there a correlation, or not?
I am saying that I do not believe there is a correlation between source code length and binary length. If that's what benced meant by their question, then yes, I agree :)
I’m quite sure there is a certain amount of correlation unfortunately, mainly because there are micro patterns (e.g. IO, allocator) that can’t be modularized into functions. Lots of manual copy-pasta.
It required a little bit of messing with optimisation settings and library generation in Rust, but they emit very very similar x86-64 assembly:
https://godbolt.org/z/89W4srz4d
Nice, thank you for picking up after my laziness. Surely only a few bytes different in the binary, and much, much smaller of a delta than the source.
You can further reduce the difference by passing Expr by pointer in the C version. At that point I think the only difference in the assembly is the order in which the cases are handed.
Ah yeah, honestly both should probably be passed by pointer anyway. But that makes me wonder about the actual differences here and why... maybe something fun to dig into.
Passing by pointer (in C) reduced the difference a lot, but swapping the order of Add and Int in the Rust enum was enough to reduce the different to:
vs LBB0_3 and LBBO_2 were the same in both outputs (up to alpha renaming).Oddly, both sources seemed to be quite sensitive to match switch and enum reordering, resulting in very different generated code. Possibly something to look into further.
Why? Python is terse but has large binaries because of the runtime overhead. C++ is fairly verbose but can make useful binaries in double digit kib.