News for hackers. Stuff that matters.
Re:When Zig is safer and faster than Rust by ilrwbwrkhv on Tuesday March 07, 2023 @01:33PM (#35059168)
On top of that Rust might be the ugliest modern language.
Re:When Zig is safer and faster than Rust by coliveira on Tuesday March 07, 2023 @01:39PM (#35059254)
Agreed, using Rust is like switching a monster (C++) for another even worse. And notice that Rust is not even a mature language, it will get much worse. I will stay with C, thank you.
Re:When Zig is safer and faster than Rust by ok123456 on Tuesday March 07, 2023 @01:57PM (#35059536)
'constexpr' and 'auto' in modern C++ can eliminate a large portion of the ugliness. In some cases it can be much more ergonomic than the equivalent Rust.
Re:When Zig is safer and faster than Rust by pjmlp on Tuesday March 07, 2023 @02:19PM (#35059854)
Indeed, one gets to write macro like code on the same language.
Re:When Zig is safer and faster than Rust by spoiler on Tuesday March 07, 2023 @02:44PM (#35060166)
You can write Rust macros in Rust if you wish to do so, but it's a bit more involved (https://doc.rust-lang.org/reference/procedural-macros.html), btw

Rust also has const generics (but they are still a bit shabby in places last time I used them).

I for one never liked the constexpr semantic and syntax. Always felt like a... Little pebble in my shoe. Didn't quite annoy me enough not to use it since it was useful, but it was never a comfortable experience.

Re:When Zig is safer and faster than Rust by DeathArrow on Tuesday March 07, 2023 @02:09PM (#35059722)
At least C++ is enormous and you can find a sane subset that you enjoy using. And C++ can be pretty safe with smart pointers.
Re:When Zig is safer and faster than Rust by pjmlp on Tuesday March 07, 2023 @02:18PM (#35059850)
Unfortunately there is always that clever one than can't let go of writing C style code, regardless of what kind of pointers are being used.

It is one of my favourite languages, but I also acknowledge that C compatibility is a big pain point for security.

Re:When Zig is safer and faster than Rust by vore on Tuesday March 07, 2023 @02:43PM (#35060157)
This almost works until you have to integrate with other people's C++ code and find out they picked a different subset to you.
Re:When Zig is safer and faster than Rust by kaba0 on Tuesday March 07, 2023 @04:10PM (#35061273)
Can you write a performant, generic vector data structure in C? Until then it is useless in my book.
Re:When Zig is safer and faster than Rust by coliveira on Tuesday March 07, 2023 @11:20PM (#35065210)
So useless that Linux, gcc, and all UNIX system commands is written in C. But you're probably doing much more important things, right?
Re:When Zig is safer and faster than Rust by heldrida on Wednesday March 08, 2023 @04:25AM (#35066925)
We should definitely appreciate the craftsmanship. This comment says everything, regardless of how trendy Rust might be, let’s respect the craft, your favourite language doesn’t make you more important. Legends!
Re:When Zig is safer and faster than Rust by kaba0 on Wednesday March 08, 2023 @04:55AM (#35067122)
Rust is not my favorite language and I didn’t mean to speak anything negative about projects written in C, but I do think that those that become great did so in spite of C, not because of it.

No access to performant generic data structures is a major reason why truly performance oriented programs rather choose C++ over C.

Re:When Zig is safer and faster than Rust by stouset on Tuesday March 07, 2023 @01:56PM (#35059528)
People keep saying this and I just do not get it. It's just… not that bad?
Re:When Zig is safer and faster than Rust by pie_flavor on Tuesday March 07, 2023 @02:21PM (#35059879)
It's not about actual ugliness, it's just something that is hard to articulate as something other than ugliness. https://matklad.github.io/2023/01/26/rusts-ugly-syntax.html
Re:When Zig is safer and faster than Rust by DonaldPShimoda on Tuesday March 07, 2023 @02:30PM (#35060002)
It's amusing to me that many of the people who complain about the aesthetics of Rust's syntax are quick to also say bad things about, like, Haskell, or Lisps, or other languages with comparatively low syntactic overhead.

I think the thing people don't like about Rust is that it looks vaguely C-like but is clearly not C. People might like it better if it was further removed (aesthetically) from C's syntax. But then they would also complain.

I think there was no way for Rust to meet all its semantic goals and also make people happy about the syntax.

Re:When Zig is safer and faster than Rust by flohofwoe on Tuesday March 07, 2023 @03:36PM (#35060836)
Typescript and Zig are two other languages that look vaguely C-like (even though they are on two opposite ends of "C like"), but both are a whole lot easier on the eyes than most Rust code.

C++ on the other hand also is vaguely C like, but can look equally messy as typical Rust code.

OTH I find Makepad's Rust style very readable, but I can't quite put my finger on it what's different from other Rust code bases:

https://github.com/makepad/makepad

Re:When Zig is safer and faster than Rust by throwawaymaths on Tuesday March 07, 2023 @05:05PM (#35061937)
Languages on the two ends of the spectrum are "not that great", IMO. Lisp is awful because even though there are very few greeblies, it introduces a TON of cognitive overhead, because you need to be constantly thinking about what something is, because the layout is TOO uniform. Rust on the other hand has a lot of greeblies and you have to remember what it is and what they do. For example macro attributes (and all their hidden effects) as well as the turbofish. Even some things like -> for the function body are simply unnecessary.
Re:When Zig is safer and faster than Rust by foldr on Tuesday March 07, 2023 @02:44PM (#35060167)
One random thing that bugs me about Rust's syntax is array initialization. In Go I can initialize an array (or strictly speaking a slice) of structs like this:

    var foo []my_struct = {{"foo", 1, "bar"}, {"foo", 1, "bar}, ...}
This is often useful in tests (where each struct value represents a test case). Rust doesn't seem to offer any similarly compact initialization syntax for arrays or Vecs. You have to write some abomination like this:

    let foo = [MyStruct{a: "foo", b: 1, c: "amp"}, MyStruct{a: "bar", b: 1, c: "fff"}, MyStruct{a: "amp", b: 1, c: "aaa"} ];
Sure, it's more explicit. But even if I add a type annotation to 'foo' specifying the array type, I still have to repeat MyStruct for every member.
Re:When Zig is safer and faster than Rust by rom-antics on Tuesday March 07, 2023 @02:54PM (#35060305)
If you want compact, use an array of tuples:

  const foos = [("foo", 1, "bar"), ("foo", 1, "bar"), ...];
  for (str1, num, str2) in &foos {
      // ...
  }
For a proper struct you have to name the fields, because otherwise refactoring the fields could cause struct instances to silently get out of sync with the definition.
Re:When Zig is safer and faster than Rust by foldr on Tuesday March 07, 2023 @04:57PM (#35061845)
>otherwise refactoring the fields could cause struct instances to silently get out of sync with the definition.

Having to name the fields is only part of the pain. You also have to redundantly repeat the struct name. I don't see any fundamental reason why something like this shouldn't be valid:

    let foo: [MyStruct; _] = [{a: "foo", b: 1, c: "amp"}, {a: "bar", b: 1, c: "fff"}, {a: "amp", b: 1, c: "aaa"} ];
I can see the logic for insisting on field names. However, the builtin 'go vet' tool has a nice behavior where it will flag the use of unkeyed literals for public structs only. This strikes me as a good compromise between concision and safety.
Re:When Zig is safer and faster than Rust by tialaramex on Tuesday March 07, 2023 @08:02PM (#35063783)
You can use map() to turn an array of tuples into an array of structures. Unfortunately at time of writing the optimiser doesn't do a great job on this, so if you're making an array of several thousand of something, or an array of things which are themselves very large, this might have unacceptable performance, but in cases where I have say a modest N values and I want N structures based on those values...

  fn make_struct(x: (&str, u8, &str)) -> MyStruct {
     MyStruct { a: x.0, b: x.1, c: x.2 }
  }

  let foo = [("foo", 1, "amp"), ("bar", 1, "fff"), ("amp", 1, "aaa")]
    .map(make_struct);
[I have not actually compiled this code, but it should do roughly what you meant]
Re:When Zig is safer and faster than Rust by guipsp on Tuesday March 07, 2023 @02:50PM (#35060257)
Do you mean the vec! macro?
Re:When Zig is safer and faster than Rust by foldr on Tuesday March 07, 2023 @04:54PM (#35061811)
It doesn't let you drop redundant struct tags, as far as I can tell.
Re:When Zig is safer and faster than Rust by tialaramex on Tuesday March 07, 2023 @08:17PM (#35063895)
I think you're right, although mentioning a macro does suggest another option here, you could write a macro which transforms [{foo1, "bar1", baz1}, {foo2, "bar2", baz2}] into the named structure version.

Since it's a macro there's no impact on runtime performance, but on the other hand it's more work to debug it. Learning declarative macros in Rust is much nicer and safer than learning C macros, but nowhere near as powerful as Rust's horribly unsafe proc macros.

Re:When Zig is safer and faster than Rust by alpaca128 on Tuesday March 07, 2023 @03:46PM (#35060971)
Dropping field names from definitions like Go would make the syntax inconsistent with destructuring and pattern matching. It's always possible to define a constructor function that takes unnamed values if you care about code verbosity in test cases. Or use `type M = MyStruct` to have an abbreviated type name within the test function.

Rust is more on the verbose/explicit side and I agree that can sometimes be annoying, but as autocompletion exists I can live with it.

Re:When Zig is safer and faster than Rust by foldr on Tuesday March 07, 2023 @05:14PM (#35062024)
>Dropping field names from definitions like Go would make the syntax inconsistent with destructuring and pattern matching

There's no reason you couldn't match on struct fields positionally as well. It would actually be quite convenient for cases like struct Point { x: f64, y: f64 }.

Re:When Zig is safer and faster than Rust by alpaca128 on Wednesday March 08, 2023 @05:19AM (#35067264)
It might be convenient at first but could become a frustrating bug if you change the struct fields and also less readable in some cases. It has its upsides but I personally think making the syntax more complex for this one detail isn't worth it.

Side note: matching f64 by value isn't a good idea either way, is deprecated and will become an error in the future.

Re:When Zig is safer and faster than Rust by foldr on Wednesday March 08, 2023 @05:33AM (#35067357)
>matching f64 by value

I wasn't thinking about matching floats by value, just destructuring a Point to obtain the coordinates as separate variables. Come to think of it though, as Rust already allows

    let Point{x, y} = pl
there would be little benefit to allowing positional matching (and in fact it would create a nasty ambiguity). So yeah, you'd have to reserve the positional syntax for initialisation.

My overall point here isn't that Rust has made bad design decisions. It's just that the end result of a bunch of sensible design decisions is that initialising arrays of structs is clunky. It might well be that this problem isn't fixable without creating other, worse, problems. Nonetheless, it annoys me quite a lot. I also think it's a problem that's emblematic of what the OP was talking about. We have here a language that's so concerned with solving difficult problems in clever ways that it's ended up backed into a corner when it comes to something as ridiculously simple as initialising an array of structs.

Re:When Zig is safer and faster than Rust by alpaca128 on Wednesday March 08, 2023 @07:20AM (#35068127)
> It's just that the end result of a bunch of sensible design decisions is that initialising arrays of structs is clunky.

Yes, though at least the language gives you tools to make it more convenient. In the previous examples that would be constructors, and macros can help too (`println`, `vec` etc. exist for that reason).

I myself like to create tiny macros to shorten things like `UnicodeSegmentation::graphemes(s, true).count()` when I have to properly handle unicode. Sure I would prefer to have it be shorter from the start, though that wouldn't make it as obvious how expensive the operation is compared to just getting the size in bytes.

Re:When Zig is safer and faster than Rust by no_wizard on Tuesday March 07, 2023 @03:51PM (#35061028)
you'll have to forgive me, but isn't this why there should be a `::new()` callable attached to the struct?

I'm really new at Rust, but that was my takeaway, e.g. `String` has `String::new()`

Re:When Zig is safer and faster than Rust by tialaramex on Tuesday March 07, 2023 @08:12PM (#35063862)
The convention of providing a new() function isn't relevant here, that name isn't magic, the Rust compiler doesn't care whether it exists, and it won't cause Rust to do anything special with tuples (or any other data structure) that happen to have a similar shape.

String::new() just makes you an empty String, which, since an empty String doesn't own any storage and doesn't contain anything, is very cheap (and indeed constant evaluable), likewise Vec::new() makes an empty Vec.

What your parent commenter wants is for Rust to make the appropriate MyStruct, but without them needing to say MyStruct each time, which would have worked in e.g. C or Go.

Re:When Zig is safer and faster than Rust by jasonjmcghee on Tuesday March 07, 2023 @02:50PM (#35060252)
I'm going to assume, based on when he said "As a slightly more serious and useful exercise" and then proceeds to remove each piece of the code that's intentionally there for performance and safety, that the whole post is satire?
Re:When Zig is safer and faster than Rust by munificent on Tuesday March 07, 2023 @03:30PM (#35060757)
The second sentence of the post is the thesis: "I think that most of the time when people think they have an issue with Rust’s syntax, they actually object to Rust’s semantics."

By removing the ugly "syntax" (and thus also removing important semantics), they're showing that the reason Rust has a lot going on syntactically is because the code is actually expressing important semantics. You can't have a nicer Rust syntax without losing semantics in the process.

Re:When Zig is safer and faster than Rust by ok123456 on Tuesday March 07, 2023 @02:01PM (#35059601)
The core language is fine, but when you actually start building things you need to introduce lifetimes, all the traits that you polluted your interface with and then add on async, it gets out-of-hand quickly.
Re:When Zig is safer and faster than Rust by dimitrios1 on Tuesday March 07, 2023 @02:23PM (#35059913)
The top comment gave a perfect example: #![feature(strict_provenance)]

These feature enablement blocks drive me crazy. You could go from codebase to codebase and it's almost like you are working in a different language depending on how many of these are enabled or not. I've been trying rust on and off since it's release, and I still have yet to feel like I have a grasp on some "core" subset of the language I can fall back on to solve most of my problems. I always have to scour documentation for the hot new thing to turn on or do, and this isn't to scorn innovation and change, but it does get exhausting at some point.

(Please release a spec)

Re:When Zig is safer and faster than Rust by satvikpendem on Tuesday March 07, 2023 @02:30PM (#35060004)
Those feature blocks exist only for nightly/unstable Rust. You don't have those on stable Rust. The most you might have are derive blocks but those just automate what you'd write by hand anyway.
Re:When Zig is safer and faster than Rust by maxbond on Tuesday March 07, 2023 @03:11PM (#35060512)
The tooling helps a lot. If you do use something that's behind a feature gate, you'll find out in real time in your IDE, and from there you can either automatically insert the feature or you can immediately choose to use a different method. You won't have to deal with it an hour later when you've already used it in 6 places, or something like that. I haven't found it to be a big problem, personally.

The API documentation of the central data types (Option, Result, Vec, etc) is more of less your toolkit, and they're pretty cohesive (eg they all have a `map()` method, Result and Option both have an `or()` method, etc).

Spec would be excellent, of course.

Re:When Zig is safer and faster than Rust by Rusky on Tuesday March 07, 2023 @03:32PM (#35060799)
A spec is not a replacement for #![feature] attributes. It's rather the opposite: #![feature] indicates that you are stepping out of the stable, specified core language and into an area that is still a work in progress and thus cannot have a committed specification yet. You shouldn't need it at all unless you are actively experimenting with some unfinished proposal.
Re:When Zig is safer and faster than Rust by kaba0 on Tuesday March 07, 2023 @04:09PM (#35061251)
I think it is just inherent complexity in the low-level space.

(Though I do agree that Rust definitely moves fast, which is sort of understandable as a relatively newish language)

Re:When Zig is safer and faster than Rust by malcolmstill on Tuesday March 07, 2023 @02:58PM (#35060360)
There are a number of sources of noise in rust, but the one I find most annoying (because it's also so common) is the double colon. My current theory is that it's because the colon is the same height as lowercase letters.

If you end up with a long::run::of::module::names, I find it all just blurs into one.

Re:When Zig is safer and faster than Rust by bxparks on Tuesday March 07, 2023 @03:30PM (#35060769)
That is a very interesting observation. I am starting to have a similar distaste for the visual noise caused by the ':' in my fully type-annotated Python code. This is particularly noticeable after spending a few weeks writing Golang, then going back to my Python code. The Go code feels far cleaner syntactically and visually.
Re:When Zig is safer and faster than Rust by Tarq0n on Tuesday March 07, 2023 @07:52PM (#35063718)
I wonder if this could be ameliorated through font choice and highlighting.
Re:When Zig is safer and faster than Rust by coderedart on Tuesday March 07, 2023 @03:12PM (#35060529)
can you please point out a few more annoyances in rust syntax? I am a newbie playing with language design and could use some perspective :)
Re:When Zig is safer and faster than Rust by malcolmstill on Tuesday March 07, 2023 @04:08PM (#35061236)
To be honest that's the major one for me. Someone else has mentioned lifetime annotations, but those uncommon enough that I don't find it much of an issue.

If I was to think about it: comparing rust to zig, zig benefits a lot from error and optional types having their own syntax rather than being treated like any other type. For example a return type of:

    Result<Option<usize>, Error>>
in rust is rendered (mostly) equivalently in zig as

    !?usize
Note: there are some options in rust for cleaning up errors such as the anyhow library.

Disclaimer: I'm a zig fan and contribute monetarily so please weight anything I say on zig vs rust with that in mind. (I do write rust at work though)

Re:When Zig is safer and faster than Rust by dureuill on Tuesday March 07, 2023 @04:37PM (#35061611)
i'm curious, how do you specify the error type in the zig version?
Re:When Zig is safer and faster than Rust by malcolmstill on Tuesday March 07, 2023 @05:00PM (#35061891)
So usually you don't have to specify the error type. The Zig compiler works out what errors are returned from the function by looking at any errors returned directly or errors returned from other functions called within the body of the function. That set of errors forms an enum that is the actual error type, you just don't have to write that out explicitly. An example might be:

    fn someFunction(a: usize) !usize {
        if (a < 10) return error.LessThanTen;
    
        const b = try anotherFunction(a);
    
        return 2 * b;
    }
    
    fn anotherFunction(x: usize) !usize {
        if (x < 20) return error.LessThanTwenty;
    
        return x * 3;
    }
The compiler infers the error type of `someFunction` as:

    error {
        LessThanTen,
        LessThanTwenty
    }
When you then `switch` on an error type, the compiler will exhaustively check that you have handled all the cases.

Note the "(mostly) equivalently" was a reference to the fact that Zig errors can't (currently) contain any other information, whereas an error in rust can carry other information.

Also note that the compiler can't infer the error type in all case, for example in the case of a recursive function. In that case you do need to explicitly write out the error set.

Re:When Zig is safer and faster than Rust by dureuill on Tuesday March 07, 2023 @05:07PM (#35061961)
Ah interesting approach, thx for the answer.

1. Doesn't that risk introducing accidental breaking changes by adding a new error to the set in the implementation, since the set of errors is inferred from the implementation? Having a compile error in this case in Rust is often the last barrier standing between me and an accidental major semver bump (since callers have to exhaustively match on the error conditions) 2. Can you have data in the variants of the error enumeration?

Re:When Zig is safer and faster than Rust by malcolmstill on Tuesday March 07, 2023 @05:34PM (#35062260)
> Doesn't that risk introducing accidental breaking changes by adding a new error to the set in the implementation, since the set of errors is inferred from the implementation?

Do you have an illustrative example? (I'm not implying it's not possible, just trying to think of a good example so I can give a good answer)

> since callers have to exhaustively match on the error conditions

If it's exhaustiveness that you're referring to, zig will make you handle all the possible errors (you can still do a catch all type thing when handling errors, which has the potential to "hide" an error that you otherwise wanted to handle explicitly).

> Can you have data in the variants of the error enumeration

No, they compile to just integers. Essentially it compiles to the same as C function that returns an `int` representing the error (with your actual return type passed in as a pointer, say).

Another limitation of zig error values is I think they're globally scoped, so you potentially could have two libraries have clashing error names that you then can't differentiate (I don't know if there are any plans to try and resolve that).

I will say that this automatic error set inference gives writing zig code this lovely "flow", where I do some error checks at the top of the function and early return some errors (which I just invent the names of there and then) and then move onto the happy path of the function, happy in the knowledge that the error handling is already "correct" (in that if the error isn't handled it'll (typically) bubble all the way up to main and exit the program). Any refinement on how a specific error is handled, I can go back to an appropriate place in the call stack and handle it. I always feel like it's helping me write correct code.

Re:When Zig is safer and faster than Rust by dureuill on Tuesday March 07, 2023 @06:03PM (#35062593)
> Do you have an illustrative example?

Illustrative, I don't know, but I'll try to give more context.

When writing a library, it is important that public items (like functions and enum) don't change between minor versions so that client code doesn't need to update their calls to the library.

Sometimes when refactoring code you end up modifying how a library function is implemented. Maybe it will now depend on some file being present on the system, while previously it wouldn't, meaning that the absence of that file adds a new error variant to this function.

In today's Rust, since the Error type of a Result is an explicit part of a function's signature, such a change is very noisy to the library's maintainer: it entails either modifying the signature of the public function to return a different error type, or modifying the Error type itself, which is also public.

When this happens, the change needs to be reconsidered: either you can defer it to later, provide an additional function with that new implementation and error variant, try to make it work with the error types you already have, or decide in that it actually warrants a major version bump, in conscience.

By contrast, if the set of errors of a function is inferred rather than part of its explicit signature, it means that modifying the implementation you can add a new variant without even realising it (for instance, by mixing the variant name with a variant returned by a sibling function that you thought was already used by this function) and break semver in a much more silent way.

I guess it also makes life harder for tooling, since it has to parse the implementation of a function (and all its subfunctions) to rebuild the set of errors, as opposed to simply parse the signature of the top-level function.

> Essentially it compiles to the same as C function that returns an `int` representing the error

That feels very limiting, I often use error types to e.g., attach data about the error. Is there a more general mechanism for sum types for when this shorthand doesn't apply?

Re:When Zig is safer and faster than Rust by malcolmstill on Tuesday March 07, 2023 @06:50PM (#35063140)
I see you what you mean. Yeah, I suppose if you are writing a library you might want to be more deliberate in the error set. Maybe explicitly writing out the error set is what you want in that situation. Rewriting the example:

    fn someFunction(a: usize) MyError!usize {
        if (a < 10) return error.LessThanTen;
    
        const b = try anotherFunction(a);
    
        return 2 * b;
    }
    
    fn anotherFunction(x: usize) MyError!usize {
        if (x < 20) return error.LessThanTwenty;
    
        return x * 3;
    }

    const MyError = error {
        LessThanTen,
        LessThanTwenty
    }
> That feels very limiting, I often use error types to e.g., attach data about the error. Is there a more general mechanism for sum types for when this shorthand doesn't apply?

I agree it's limiting. It obviously is going to depend on your application, but I have largely done without annotating errors with extra information (that maybe speaks more to the seriousness of my zig projects than to that approach to error handling as being sufficient!).

One pattern I have used (in e.g. a parser) is additionally passing in a pointer to a sum type:

    fn parse(allocator: *mem.Allocator, tokens: Tokens, parse_error: *ParseError) !AST
The `parse_error` can be set if an error condition occurs. I concede that that's a little clumsy
Re:When Zig is safer and faster than Rust by tialaramex on Tuesday March 07, 2023 @09:10PM (#35064315)
> In today's Rust, since the Error type of a Result is an explicit part of a function's signature, such a change is very noisy to the library's maintainer: it entails either modifying the signature of the public function to return a different error type, or modifying the Error type itself, which is also public.

For what it's worth, if you expect this might happen, you should give the enum the [[non_exhaustive]] attribute. This attribute says I, the implementer, know how many of these there are, and in my code I can exhaustively enumerate them e.g. in a pattern match, however, you the 3rd party programmer using this crate, must assume you can't know how many there are, and therefore must write a default match to handle others, even if there seem to be no others when you write it.

Once you do this, you don't cause a compatibility break by adding a new item.

Re:When Zig is safer and faster than Rust by xcdzvyn on Tuesday March 07, 2023 @08:00PM (#35063777)
ErrorType!usize
Re:When Zig is safer and faster than Rust by stouset on Tuesday March 07, 2023 @03:58PM (#35061113)
Okay but who is writing code like this instead of using `use`?

Also this is an no-win situation. C++, Ruby, Perl, and others have used `::` as module-scoping syntax for decades. If Rust does something novel, it's penalized for being unfamiliar. If Rust uses syntax for which there's ample prior art, it's apparently line noise. If rust used a `.` as a separator, it's unclear if you're descending into modules or calling a function chain.

There's literally no way to win.

Re:When Zig is safer and faster than Rust by coderedart on Tuesday March 07, 2023 @04:11PM (#35061283)
If an import is used rarely, then i prefer qualifying paths instead of importing them.

This is especially true when there's similarly named items from different paths. Best example is `Result`/`Error` types. eg: std::io::Result vs normal default Result vs other crate's Result type. Another example would be math types like Vec2 between game engine and egui. String in mlua vs std rust etc..

Usually you can get around this by importing it with a different name like `use mlua::String as LuaString`. but it is still something that you need to actively do.

Re:When Zig is safer and faster than Rust by malcolmstill on Tuesday March 07, 2023 @06:03PM (#35062586)
I did use the example of long run of module names, and I do take your point about `use` (though I have to sometimes read the very top of a file too!)...but the same applies to a lesser extent to the "last mile" module (e.g. `String::from`, `Vec::new`) which will be seen throughout any rust code.

> If rust used a `.` as a separator, it's unclear if you're descending into modules or calling a function chain

Interestingly, from the zig documentation:

    Zig source files are implicitly structs, with a name equal to the file's basename with the extension truncated. @import returns the struct type corresponding to the file.
This means that there isn't really any difference between accessing a struct field and accessing something in module...the module is also a kind of struct (and rust, as in zig, differentiating struct field access vs function invocation is possible because of the parens in the latter).
Re:When Zig is safer and faster than Rust by lloydatkinson on Wednesday March 08, 2023 @03:33AM (#35066654)
> There's literally no way to win.

Yes there is? Follow what C#, F#, Java, TypeScript, etc. do

Re:When Zig is safer and faster than Rust by jcranmer on Tuesday March 07, 2023 @04:17PM (#35061363)
I suspect the things that people are reacting to are a mixture of the following:

* Types in Rust use prefixing to create derived types whereas C family languages generally use postfixing. A pointer is i32, not int; an array [i32; 5], not int[5], etc. This makes special characters appear more heavily at the beginning of the scan line, and probably makes them slightly more noticeable as a result.

* Lifetimes have the form 'a, and that single quote is likely to bother a lot of people (I know it bothers me).

* Unqualified name lookup in Rust is a bit weaker than other languages, which makes the scope operator (::) more common.

* Passing in explicit generic type arguments for a function requires an extra :: for seemingly no reason.

* Similarly, macros require an explicit ! in the name to invoke. Given that println! (and formatting in general) is a macro and not a function, this means you get a lot of extra uses of ! that's unexpected for C family code.

* Again, the try operator (also decently common) is another random special character.

* Attributes also use #[] syntax, or sometimes #![]. While C++11 did use [[]] to designate its attributes, it's also something that always felt a bit ugly to me personally (I find the @Decorator() pattern from Java or Python to be a visually cleaner way to do attributes).

In short, Rust generally has a higher density of special characters than other C family languages, and I think that contributes to a sense of ugliness.

Re:When Zig is safer and faster than Rust by q3k on Tuesday March 07, 2023 @05:07PM (#35061963)
> * Passing in explicit generic type arguments for a function requires an extra :: for seemingly no reason.

There is a very good reason for this. Behold, the Bastion of the Turbofish.

https://github.com/rust-lang/rust/blob/master/tests/ui/parse...

Re:When Zig is safer and faster than Rust by loeg on Wednesday March 08, 2023 @02:02PM (#35073288)
That is not a good reason as far as end users are concerned.
Re:When Zig is safer and faster than Rust by Asooka on Tuesday March 07, 2023 @04:36PM (#35061592)
My biggest peeve is types on the right. I would say that C is "humanistic" in its type declarations, while Rust and the rest of Pascal's lineage are "mechanistic". Concretely, look at this:

    int foo(int a, float b);
vs

    fn foo(a: i32, b: f32) -> i32;
In Rust's case you're specifying to the machine what the thing is, i.e. "I am declaring a function called foo. The function has a first parameter called a, of type i32, ... The function returns an int". Whereas in C you have a "declaration follows usage" idiom, such that what you're saying is "typing foo(a, b) produces an int on the left side, within foo a produces an int lvalue, ...". The function arguments flow from right to left and the result emerges on the left with the given type. The order of tokens in declaring foo matches the order of tokens when calling foo. It also matches the order of importance - first is the return type, then the function name, then each parameter type followed (optionally) by the parameter name.

Or look at an array declaration:

    int arr[5];
"You get an int when you type arr[N] where N is less than 5".

This kind of argument of course goes all the way back to AT&T vs Intel assembly syntax and I am firmly on Intel's side.

Re:When Zig is safer and faster than Rust by __jem on Tuesday March 07, 2023 @05:52PM (#35062453)
This isn’t a Rust thing. Lot’s of new language have the type declaration after the variable because of type inference which makes such declarations optional.
Re:When Zig is safer and faster than Rust by todd8 on Tuesday March 07, 2023 @05:57PM (#35062518)
Algol 60, Algol W, and Algol 68 were influential in the historical development of subsequent programming languages. C gets its type on the left order from the Algol family.

Pascal, Modula, and Ada are all type on the right languages and were also very influential in the historical development of programming languages. I happen to prefer types on the right for complex declarations. Note that Pascal and Modula were designed by Niklaus Wirth after he created Algol W; it seems he preferred types on the right.

Re:When Zig is safer and faster than Rust by stouset on Tuesday March 07, 2023 @08:43PM (#35064087)
I'll simply say that you are the first person I've seen come to the defense of C's inside-out variable syntax.
Re:When Zig is safer and faster than Rust by alphanullmeric on Tuesday March 07, 2023 @07:44PM (#35063660)
No arrow operator, no default args, no named parameters, no structure defaults and instead the incredibly verbose ..Default::default() + a trait impl as a substitute, no variadics, overall weak generics compared to C++ and a huge reliance on macros, etc etc. Rust programmers address this by calling everything rust does poorly an antipattern, ie. the “why would you do that” card.
Re:When Zig is safer and faster than Rust by tialaramex on Tuesday March 07, 2023 @08:58PM (#35064210)
The arrow operator is just a terrible idea, and it's weird that people defend it. It makes sense that C did this, it was a long time ago and compilers weren't very smart so C needs to make up for that, in C++ it's just carried over from C.

The absence of default args is a deliberate choice, notice that Rust does have default type arguments in polymorphism, the absence of defaults for function parameters -- which would be technically easy to implement -- reflects a belief which I've come to agree with that overloading is a bad idea, and defaults most often in practice mean you're overloading.

For example, C++ std::ranges::binary_search uses defaults to present what are in effect at least two distinct features, as a single function, suiting C++ sensibilities, whereas Rust reflect almost the same capabilities as three functions []::binary_search []::binary_search_by and []::binary_search_by_key

For a very simple binary search, things seem pretty similar. In Rust we have a single parameter, for our searched-for element, and in C++ we can stop after that parameter, leaving the comparison function and projection as default for similar effect.

However for binary_search_by the C++ is contorted by this API shape. Instead of a callable to decide whether our search found what it was looking for, and if not where it is relative to the searched-for element, the C++ is obliged to carry that element (because it was an earlier parameter) even if it's unused - and then a comparison function which takes the element, and only then optionally a projection which you may or may not use.

And for binary_search_by_key the C++ is even more awkward, we have a good reason to use a value here, but we're obliged to specify the comparison function even though we only want to write a callable to make suitable keys (ie a projection), because of the order of the parameters.

These would be better served, as in Rust, by three distinct functions, with only the appropriate parameters for each function - even if you choose to actually implement the simplest in terms of the others, because of the documentation and the API shape afforded if you think about it as three things not one with defaults carefully tailored to allow all three uses.

Variadics is a genuinely useful feature, but to do it properly is very difficult, C++ 98 doesn't have anything better than Rust [C compatibility, with no real type checking], C++ 11 does have the outline of what you'd actually want, and C++ 17 has much closer to what I'd want to see in Rust some day.

Much of what you're thinking of in "weak generics" is probably deliberate constraints to only allow coherent things, in C++ they don't care if you want to make a Foo<NaN> even though that's nonsense, IFNDR gives them the ultimate out, your program has no defined meaning, so too bad.

There are some obvious things Rust wants to have but doesn't yet in this space, including broader const Generics (e.g. my OnewayEqual ought to be Oneway<Ordering::Equal>) but it's not going to pursue the irrational C++ exuberance because it's so quickly unsound. C++ doesn't care about that while Rust does.

Re:When Zig is safer and faster than Rust by pjmlp on Wednesday March 08, 2023 @02:54AM (#35066413)
C compilers weren't smart.
Re:When Zig is safer and faster than Rust by jstimpfle on Wednesday March 08, 2023 @06:44AM (#35067847)
Why do you think the arrow operator is a terrible idea? I that it costs very little of my time, and that it's so much easier to intuit what's going on from an expression like Foo->Bar.Baz->Quux compared to having only dots on there.
Re:When Zig is safer and faster than Rust by alphanullmeric on Wednesday March 08, 2023 @07:29AM (#35068205)
The arrow operator is far better than what you currently have to deal with in unsafe rust when trying to access a pointer member of a pointer to a struct. Rust’s way is more verbose and less clear.

I don’t really care for your examples of defaults being abused in C++, because all of rust’s workarounds like builder pattern and the default trait have the same potential to be misused while also impeding performance. They also suck for ergonomics, see bevy and polars. Rust already has a huge function colouring problem with async and mut and the lack of defaults only makes it worse.

Similarly for generics. Templates are simply better. Don’t use the power if you’re scared if it, that’s the great thing about freedom, you won’t be forced to. C++ can always do something the Rust way, nullifying everything you’ve said, but the other way around is not true. Rust sacrifices the complex case to make the simple case a little simpler and just leans on macros to do everything else. “Rust just allows coherent things” is a typical example of the bullshit rust programmers spew when they don’t have an actual response but want to say something anyways because it’s completely wrong. Plenty of useful template functionality is impossible to replicate in rust. For example:

https://youtu.be/gOdcNko2xc8

Re:When Zig is safer and faster than Rust by edflsafoiewq on Tuesday March 07, 2023 @02:50PM (#35060247)
IMO Zig isn't exactly a beauty either.
Re:When Zig is safer and faster than Rust by zamalek on Tuesday March 07, 2023 @02:53PM (#35060297)
That is extremely subjective. I find the syntax extremely easy to read, and there are significantly fewer edge cases than nearly all other mainstream languages:

* Why does C# require a break; under switch?

* What about the "Most Vexing Parse"?

* Why does Zig change capitalization of @import and @TypeOf?

Rust is an extremely "guessable" language. It's highly likely that experimenting with syntax will succeed in Rust, which is a syntax feature that I have seen nowhere else.

Re:When Zig is safer and faster than Rust by somethingor on Tuesday March 07, 2023 @03:31PM (#35060786)
Re:When Zig is safer and faster than Rust by edflsafoiewq on Tuesday March 07, 2023 @03:28PM (#35060737)
> Why does Zig change capitalization of @import and @TypeOf?

TypeOf returns a type. Corresponding to how type names are uppercase.

Re:When Zig is safer and faster than Rust by Narishma on Tuesday March 07, 2023 @07:30PM (#35063524)
That's entirely subjective. I personally find Zig, Nim and even Go much uglier than Rust.