``` fn Vec(comptime T: anytype) {
return struct {
// ...
}
}```
IMO having a first class generic type parameter syntax is better but this demonstrates OP's point.
fn MyType(T: type, comptime tag: [] u8, comptime count: usize) type {
const capitalized = some_module.capitalize(tag);
return struct{
fn name() []const u8 {
return capitalized;
}
array: [count]T,
};
}
for exampleFurthermore, the original argument wasn't about whether something can or can't be done in C++, it was that this one feature in Zig subsumes what would require a multitude of features from C++, such as consteval, templates, SFINAE, type traits, so on so forth...
Instead of having all these disparate features all of which work in subtly different ways, you have one single feature that unifies all of this functionality together.
Rust on the other hand... that might be ten years.
I still think that language support us important, but unfortunately due to what happened, I suspect that will take a long time. And that’s disappointing.
I agree it'd be nice if it weren't confined to our community, though.
Don't coherence rules prevent it?
error: type capture contains reference to comptime var
I'm not sure how you were suppossed to use it but here's my attempt: fn capitalize(tag: []u8) []u8 {
tag[0] &= 95;
return tag;
}
fn MyType(T: type, comptime tag: []u8, comptime count: usize) type {
const capitalized = capitalize(tag);
return struct {
fn name() []const u8 {
return capitalized;
}
array: [count]T,
};
}
pub fn main() void {
comptime var hello: [5]u8 = undefined;
@memcpy(&hello, "hello");
var v: MyType(i32, &hello, 10) = undefined;
v.name();
}
If you allow `capitalized` to be it's own instance then there's no reason to mutate the comptime parameter in the first place, and it can be replicated in C++17. #include <cstdio>
namespace detail {
template<size_t N>
struct Capitalize {
char data[N];
constexpr Capitalize(const char (&tag)[N]) : data{} {
for (size_t i = 0; i < N; i++)
data[i] = tag[i];
data[0] &= 95;
}
};
}
template<typename T, size_t N, const char (&tag)[N], size_t count>
struct MyType {
static constexpr auto capitalized = detail::Capitalize(tag);
constexpr auto name() const {
return capitalized.data;
}
T array[count];
};
int main() {
static constexpr char hello[] = "hello";
MyType<int, sizeof(hello), hello, 10> value{};
std::puts(value.name());
}
I'd agree that zig's comptime encompasses many of C++'s features, and I appreciate the approach they took to new features by way of builtins (like @typeInfo + @Type for reflection), but this is not a good example.Furthermore, why is type traits among the list of features that you claim is subsumed by comptime? not only is that not the case, but type traits are not so much a feature of C++ as they are of its standard library, implemented using templates (a feature of the language).
https://github.com/ityonemo/clr
They're popping up all over. For some reason, Zig folk want Rust things and Rust folk want Zig things.
When it comes to Zig, one crowd says it's too early because it's not 1.0 fast enough. And now, are you saying that the feature development is basically done? What point are you trying to make?
Rather, both languages' correctness-related claims rely on them being in some better or worse effort/correctness sweet spot, and that can only be measured empirically for those two specific languages. Crucially, results comparing Rust to C or C++ are not relevant. Zig offers more soundness than C, and even if it offers the same soundness as C++ (and I disagree -- I think it offers more) the language's claim is that its simplicity assists correctness. We can only tell to what extent that is true with more empirical observation; I don't think there can be any good guess made here regarding the size of the effect.
If you look at MITRE's CWE Top 25 [1], #2 (Out-of-bounds Write) and #6 (Out-of-bounds Read) are soundly eliminated by both Zig and Rust. It is only when it comes to #8 (Use After Free) that Rust's additional soundness comes into play. But because it comes at a cost, the question is to what extent eliminating #8 adversely impacts the other top vulnerabilities, including those higher on the list. It may be the case that eliminating the eighth most dangerous vulnerability through sound language guarantees may end up being worse overall even if we're only concerned with security (and it isn't the only concern). We can only try to assess that through empirical study.
[1]: https://cwe.mitre.org/top25/archive/2024/2024_cwe_top25.html
> I don't believe
Of course, we're debating against a belief, and you have plenty of reasons to not believe it that it will be impossible to be swayed by any sort of evidence, and you will always find a way move the goalposts.
Otherwise, it can be construed as just another wish list or feature request, that main developers have no plans to implement.
Or, more generally, address all the issues raised in [1]. You're saying that comptime can fully replicate all the features that a proper generics system has, which is plainly false.
2. if you want to restrict the use of a function to comptime (why you would want to is beyond me) it is possible to do with @inComptime builtin.
the only tricky bit is that your function could try to call a function inaccessible to you because it's transitively restricted and you'd have a hard time noticing that from the code but it's not possible for that code to be compiled (barring errors by the zig team) so its more of an annoyance than a problem.
Now, I'm not saying that Zig's choices always dominate and that all languages would be better off with its approach; far from it. I am saying that it introduces a novel tradeoff that is especially compelling in cases where not only generics but also macros, conditional compilation, and constexprs are otherwise required. In a language like Java these extra features are not required, and so Zig-style comptime would not simplify the language nearly as much.
But even in cases where all these features are needed, I don't think everyone would take Zig's choices over C++'s or Rust's, or vice-versa. To those, like me, for whom language complexity is the biggest problem with C++ or Ada (I used Ada in the nineties), Zig is a revolutionary step forward. I don't think any low-level language has ever been this simple while also being this expressive.
That wasn't my argument.
> After all, you don't extend Rust the same courtesy
Given that my aesthetic issue with Rust is that it has too many complicated features, I don't see how that courtesy could be extended. There is, indeed, an asymmetry between adding features and removing them, but the aesthetic "points" I'm awarding Zig is not due to features it could add but due to features it hasn't while they've not yet been shown to be critical.
I think it's fairly obvious that any feature in any language was added to add some positive value. But every feature also has a negative value, as it makes the language more complicated, which in aggregate may mean fewer programs would be written in it. The challenge is balancing the value of features with their complexity. Even those who prefer Rust's aesthetics to Zig would admit that Zig's novel approach to power/simplicity balance is something we have not seen in programming language design in many years.
I disagree. Minimalism in systems language design has been done over and over: see Go for the most recent example. Comptime is something that C++ was already doing in the form of constexpr since 2011 and a space that D had explored for over a decade before Zig came around in the form of "static if" and so forth (in addition to lots of academic work, of course). Stripping out template metaprogramming in favor of leaning heavily on compile-time function evaluation isn't novel either. I think you find the set of features that Zig has to be personally appealing, which is fine. But the argument that it's anything novel is weak, except in the trivial sense that every language is novel because it includes some features and leaves others out (but if every language is novel, then the word "novel" has no meaning).
From my vantage point, Zig is essentially a skin on a subset of C++, one that is in practice less safe than C++ because of the relative immaturity of tooling.
Minimalism is also, of course, not a new idea, but unlike in Go, I wouldn't say minimalism is Zig's point. Expressive low-level languages have always been much more complex than similarly expressive high-level ones, something that many of us have seen as their primary problem, and Zig is the first one that isn't. In other words, the point isn't minimalism as a design aesthetic (I would say that explicitness is a design aesthetic of Zig's much more than minimalism) but rather reducing the complexity that some have seen as the biggest issue with expressive low-level languages.
What was so impressive to me is that we've always known how macros can add almost infinite expressivity to languages that could be considered minimalistic, but they carry their own set of severe complexity issues. Zig showed how comptime can be used to offer much of the power of macros with almost none of their cost. That, too, is revolutionary even without considering the low-level domain specifically (although high-level languages have other options).
Finally, if you want to talk about "safety in practice", considering more than just the language, I don't think we can know without empirical study, but the same claim could be made about Rust. Both Zig the language and Rust the language are safer than either C or C++ (the languages), and Rust the language is safer than Zig the language. But as to their relative safety (or correctness) "in practice" either now or in the future, only time and empirical study will tell. Clearly, languages that offer more soundness, like Idris or ATS, don't always work so well in practice. So I admit I don't know at this time whether Zig (the gestalt) offers more or less correctness in practice than C++ or which of Zig or Rust offers more correctness in practice, but neither do you.
Give it a rest please. Given your association with Rust, endlessly attacking competing languages is not a good look, regardless of whether your points are technically correct or not.
Also all the ones I mentioned, supported binary libraries, which apparently is not something the Zig folks are too keen in supporting, other than C like ABI.
For me any systems language that doesn't support binary library distribution isn't that relevant to me, and yes that is also something that I regularly complain about in Rust, and not only me. Microsoft has a talk on their Rust's adoption where this is mentioned as a problem, only relieved thanks to ubiquity of COM as mechanism to delivery binary libraries on Windows.
I think pcwalton's "generics" vs. "templates" distinction mostly boils down to parametric typechecking, which Zig's design just can't do. (Can it?)
Although, I vaguely remember some example showing that even Rust in some cases allows a type definition X<T> even when there exists a T such that X<T> would fail to typecheck.
- generics: comptime can implement some kind of polymorphism, but not at the type level. In other words it implements a templating system, not a polymorphic type system;
- interfaces/traits/concepts: comptime implements none of that, it is plain duck typing, just like "old" C++ templates. In fact C++ introduced concepts to improve its situation with templates, while Zig is still behind on that front!
- macros: comptime solves some of the usecases where macros are used, but it cannot produce arbitrary tokens and hence cannot fully replace macros.
I do agree that it can neatly replace conditional compilation and const functions/const expr, but let's not make it seem like comptime solves everything in the world.
you could probably cobble together an interface system with @comptimeError, but because of the time order of compilation stages, a failed method call will trigger the compiler error before your custom interface code, making it effectively useless for the 90% of cases you care about.
if I'm not mistaken in principle a small change to the compiler could amend this situation