why does the fact that the backing array of a string literal has a null terminator matter? If it matters to you, you can just use the array literal syntax. Adding more syntax just to say a string has a null terminator or not is unnecessarily complex in my opinion.
i did not say it matters to me, iām providing a clarification of the otherās posterās point.
if anything like this is implemented, it should default to nul-terminated strings with a possibility to create a non-terminated string explicitly. but i canāt imagine a situation where it would matter to me.
right, sorry, I didnāt realize youāre not the same person I was replying to.
It may not require more complex syntax, I could see the compiler finding the difference between these two lines enough to add or omit a null terminator.
const no_term: []const u8 = "Hello world!";
const with_term: [:0]const u8 = "Hello world!";
If you want to use C code then the latter will be needed any ways, and is compatible with zig slices. It seems odd to go out of the way requiring some comptime code just for removing the null byte; but Iām not fighting hard for this change, super low savings on size and low but non-zero chance to break some c-interop ease of use.
FWIW, you can get rid of the NUL terminator in status quo Zig by copying the literalās contents into a comptime array like so:
fn unterminate(comptime s: []const u8) []const u8 {
return &@as([s.len]u8, s[0..].*);
}
pub fn main() void {
std.debug.print("{s}", .{unterminate("Hello, world!\n")});
std.debug.print("{s}", .{unterminate("This is a test string thing\n")});
std.debug.print("{s}", .{unterminate("A third string\n")});
std.debug.print("{s}", .{unterminate("We should all be unterminated by NUL\n")});
std.debug.print("{s}", .{unterminate("(unless there is some padding)\n")});
}
const std = @import("std");
EDIT: A much shorter version of the unterminate function
what happens when both lines exist in a code base? The whole point of string literals is deduplicating strings, should the compiler duplicate the strings? or should it do what it is doing now?
I presume the compiler could de-duplicate the strings by only producing the null-terminated string and referencing it for both. I donāt see the non-terminated string as being unique because of itās lack of null at the end, and since null-terminating casts to normal slices itās already normal behavior.
// example of using one de-duplicated string from my previous example
const with_term: [:0]const u8 = "Hello world!";
const no_term: []const u8 = with_term; // what the compiler should do, but we can force in-code
anytype needs to go. ZLS has a really hard time analysing anytype arguments, and due to the Turing-completeness of comptime, the best an LSP can ever offer is first-order heuristics. anytype is also a poor substitute for expressing generic pointer attributes for method receivers. I was rather surprised to find out that the mutating methods of std.bit_set.IntegerBitSet canāt be used when the bit set is non-trivially embedded into another packed structure all because self is marked as *@This() instead of anytype. I have to use self: anytype if I want the return type to inherit the pointer attributes of the receiver (e.g. constness) as well.
In my opinion, removing anytype (or whatever else the concept ends up being called) would turn Zig into a much less interesting language. Itās what allows Zig to feel fairly high-level even though everything is extremely low-level, it makes it possible to design handy APIs. Just look at std.Io, io.concurrent(@TypeOf(func), func, .{arg1, arg2}) vs io.concurrent(func, .{arg1, arg2}). ZLS-wise, you are not gaining anything by replacing anytype with @TypeOf(), but the the API is more awkward. And if you remove it completely, you are back to C-style function pointers and *anyopaque type-erased parameters, e.g. io.concurrent(&func, &args), you lost type safety, you lost performance, the func now has to do @alignCast(@ptrCast()) and itās all just icky.
I donāt want genericity to be removed but anytype is just a poor substitute for declarative contracts. I understand Zig isnāt meant to be another Haskell, but duck-typing should be the absolute last resort in a type system. If anything, my past experience with LSP development has made it clear to me unhinged metaprogramming destroys static analysis.
I think that anytype is necessary to express the sorts of generic programming that in C, would be done with particularly cursed macros: things like slist(3) - Linux manual page but 10x worse. Zigās comptime is excellent by comparison, but still has the inevitable problems re. static analysis.
Forget static analysis, it also destroys human analysis. There is something about C++ in particular, where it just slides off the eyeballs.
Personally, I feel the same advice applies for generic programming in zig as does for C macros - donāt use them unless you absolutely have to.
To that end, I donāt think itās a good idea to add features to make generic programming easier - that only encourages people to turn their libraries into soup. Instead, make the ordinary programming better, so you can get more done without having to reach for metaprogramming tools.
And remember, not everything needs to be re-usable to the nth degree. Bespoke code is fine too! Arguably better: C++ FQA Lite: Operator overloading
Quote
Those guys living in the āreuse-orientedā worlds are very noble characters. Too bad weāre stuck on planet Earth, which didnāt seem to have any particular āorientationā last time I checked. On this planet, most classes you write are used exclusively by yourself, the majority of the rest is used by two or three people, and once in a while you get to write a class to be used by N people for N>3 - typically itās not an array class, but something with a little bit less trivial functionality. Here on Earth, this is considered good: the more interaction between people and components, the more errors there are likely to be.
It seems to me that what youāre referring to should be addressed through agreements and discipline, try is convenient when youāre developing something simpleāfor example, right now Iām developing a utility for working with tables in the CLI, and I donāt actually need detailed error handling because errors are rare, but if I had to handle them all, it would be very tedious and inefficient work.
I think weāre mostly on the same page here, except that excessive metaprogramming is sometimes my guilty pleasure ![]()
Seriously though, anytype appears far too frequently for my liking, the type system should be enhanced to save us from falling into the kitchensink. (spelling out explicitly the type of the receiver of a mutating method of a nested packed structure isnāt for the faint of heart, and itās not even about generic reusability
)
I agree that anytype can make working with static (or human) analysis difficult, and should be used with caution, I am more forgiving of itās use when it comes to comptime metaprogramming, as if things are wrong they generate compile errors. Annoying for sure, but if the structure required is well documented, can be dealt with without making problems at runtime.
anytype is not ideal, but still much much better than the solutions in other languages I know (Rust, Delphi, C#). So I can live with it.
I think itās perhaps most useful to think of anytype as Zig providing you direct access to compile-time monomorphization, rather than as an escape hatch from a type system.
anytype is the single most powerful zig feature, I hope any replacement will be up to it.
I agree. This is the type of feature that sounds cool at first but yields little ROI in the end. I have no problem reading all files in the same casing rules. I also donāt think that file-structs are worth it.
We can keep the syntax cleaner if there is only one way to define a struct: to define with one more indentation level.
Maybe inside the compiler it is intuitive to reuse the code for explicit structs and file namespaces?
This is just convention. There is nothing in the compiler that states that a file that is capitalized becomes a struct. Indeed the idea is that all files are structs. Itās just that not all files have āinstance fieldsā.
anytype is about 1000x simpler than any of the alternatives so I hope it stays