#[derive(Copy, Clone)]
enum Expr {
Int(i32),
Add(i32, i32),
Neg(i32),
}
fn eval(expr: Expr) -> i32 {
match expr {
Expr::Int(x) => x,
Expr::Add(a, b) => a + b,
Expr::Neg(x) => -x,
}
}
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: #include <stdint.h>
typedef enum {
EXPR_INT,
EXPR_ADD,
EXPR_NEG,
} ExprTag;
typedef struct {
ExprTag tag;
union {
struct {
int32_t value;
} Int;
struct {
int32_t left;
int32_t right;
} Add;
struct {
int32_t value;
} Neg;
};
} Expr;
int32_t eval(Expr expr) {
switch (expr.tag) {
case EXPR_INT:
return expr.Int.value;
case EXPR_ADD:
return expr.Add.left + expr.Add.right;
case EXPR_NEG:
return -expr.Neg.value;
}
__builtin_unreachable();
}
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 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 :)
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.
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).
> 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.
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.
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.