Most active commenters
  • pron(11)
  • 59nadir(7)
  • mr_00ff00(6)
  • throwawaymaths(6)
  • helen___keller(6)
  • (6)
  • flohofwoe(5)
  • pjmlp(5)
  • eatonphil(5)
  • whateveracct(5)

Zig is hard but worth it

(ratfactor.com)
401 points signa11 | 305 comments | | HN request time: 2.994s | source | bottom
1. mgkimsal ◴[] No.36150143[source]
https://archive.is/cMm11
2. thadt ◴[] No.36150211[source]
> Crucially, there is basically no documentation for the standard library except for the source code itself.

From the viewpoint of someone learning about a new language, I find the accessibility of the standard libraries goes a long way toward helping me understand how things fit together. It is a first stop to see how experts in the language use it. Browsing through the standard libraries of languages like Zig, Go, and Python - they're usually well-documented and readable enough to be a tutorial, even before you've dug into learning it. Others (Rust, C++) are a bit more, ah, technical for the novice.

replies(3): >>36150393 #>>36150476 #>>36150587 #
3. pron ◴[] No.36150237[source]
> there’s not a direct correlation between the slimness of a language’s syntax and ease of learning

That's absolutely true, but (the standard library aside) the "syntax" -- or, rather the syntax and core semantics -- of a programming language are arbitrary axiomatic rules, while everything else is derivable from those axioms. So while it is true that a small language can lead to a not-necessarily-easy-to-learn overall programming experience, it is the only arbitrary part, and so the only part you need to memorise (or consult the documentation for when dealing with some subtlety you may have forgotten). So a smaller language reduces the need for "language lawyering" after you learn it.

Some languages (e.g. lisps) are deceptively small by relying on macros that form a "second-order" language that interacts with the "first-order" language, but Zig doesn't have that. It has only one language level, which is small and easy to memorise.

But yes, Zig is a bigger language than C, but a far smaller language than C++. What's amazing, though, is that C++ is strictly more expressive than C (i.e. there are programs that could grow exponentially faster in C than in C++, at least without the help of C macros), but Zig is as expressive as C++ (i.e. program sizes may differ by no more than a small constant factor) while being much closer to C in size, and it achieves that without the use of macros.

replies(4): >>36150398 #>>36150954 #>>36151058 #>>36153690 #
4. cies ◴[] No.36150352[source]
From the article:

> Easy is subjective. But simple things are simple because they do not complicate; they have fewer concepts. Simple is objective.

I'd argue both are subjective, or with a better word: relative.

I'd say Zig is easier and simpler than C in almost all regards. The article does not specify what Zig is compared to in order to make these statements. Probably the author had C in mind, but that was not explicitly mentioned.

5. bakuninsbart ◴[] No.36150356[source]
Where do you guys see good use cases for Zig? I'm intrigued by the language but don't really have any good ideas on where to try it out.

I thought about trying it out in as small data engineering project, but I'm not sure if language support is sufficient for the kind of tooling I would need eg. Database adapters.

replies(4): >>36150532 #>>36150616 #>>36150833 #>>36151486 #
6. jsheard ◴[] No.36150389[source]
I get what Zig is going for in making all operations as explicit as possible, but I fear that it's going to turn away fields like graphics and game development where it would be a good fit except for the lack of operator overloading forcing you to go back to C-style math function spaghetti. It's all fun and games until what should be a straightforward math expression turns into 8 nested function calls.
replies(8): >>36150475 #>>36150541 #>>36150795 #>>36150946 #>>36151013 #>>36151746 #>>36151792 #>>36152172 #
7. Vecr ◴[] No.36150393[source]
Rust has the standard library documentation at https://doc.rust-lang.org/std/ or on your local computer, if there's really nothing like that for Zig I think that's a problem. Are you sure there's no `info zig` or something like that?
replies(1): >>36150816 #
8. helen___keller ◴[] No.36150396[source]
My main issue with Zig is that I’m scared to invest time in writing something nontrivial to see the community/adoption flounder then regret not using Rust or C++ later

The language itself is fun. The explicit-ness of choosing how allocation is done feels novel, and comptime is a clean solution for problems that are ugly in most languages.

Aside from lack of community I’d say the biggest nuisance is error handling in nearly everything including allocations. I get that allocation can fail but the vast majority of programs I write, I just want to panic on an allocation failure (granted these aren’t production programs…)

Edit: in retrospect, allocator error handling verbosity is probably necessary due to the power the language gives you in choosing allocators. If I use the general purpose allocator then my edge case is PC out of memory; if I use a fixed buffer allocator, a failed allocation is a code bug or a common error case, so we might want to handle the failed allocation and recover

replies(5): >>36150507 #>>36150918 #>>36151708 #>>36155513 #>>36158163 #
9. the_duke ◴[] No.36150398[source]
I'm not a Zig expert, but I have a different take here.

Zig has comptime, which is essentially a compile time macro written in the main language and with type reflection capabilities.

They can introduce complex behaviour and fail in very cryptic and unexpected ways, which results in an experience very similar to macros or C++ template literals.

replies(1): >>36150717 #
10. bodge5000 ◴[] No.36150475[source]
I'm no expert on zig, but the one area I have seen it shooting up in popularity is game dev. Though I guess that is largely as a replacement for C, so "C-style" wouldnt be much of a concern
replies(3): >>36150560 #>>36150748 #>>36151102 #
11. tialaramex ◴[] No.36150476[source]
I certainly wouldn't recommend trying to figure out C++ by reading either of the three major C++ standard libraries.
12. kuroguro ◴[] No.36150507[source]
I suppose you could write a few line wrapper that panics :)

But yeah, most of the time I don't even want to think which allocator to use let alone handle it's errors.

replies(2): >>36150581 #>>36153145 #
13. jgalt212 ◴[] No.36150532[source]
I've been thinking about using it for Python hot paths. I'm not smart enough to write rust (at least without limitless supplies of aspirin). And I'd like to avoid C for all the obvious reasons.
replies(1): >>36150773 #
14. TwentyPosts ◴[] No.36150541[source]
I am not much of a Zig-head, but the best compromise I can think of is having a few operators which purely and solely exist for this purpose. In other words, there is no operator overloading, but you can define, say, "#+" for any two structs, or something like that.

So if you want to encode matrix multiplication, then you'll always have to write `mat1 #* mat2`. This feels like a hack, and isn't all that elegant, but it'd be clear that every usage of such an operator is a disguised function call. (And according to what Andrew Kelley said, it's all about not hiding function calls or complex operations in seemingly innocent 'overloaded' symbols.)

If you want to take this one step further you'd probably have to allow users to define infix functions, which would be its own can of worms.

Honestly, I am not particularly happy with any of these ideas, but I can't think of anything better either!

replies(3): >>36150784 #>>36153058 #>>36153273 #
15. jsheard ◴[] No.36150560{3}[source]
Zig looks like a fine C replacement, but C isn't what people are using to make games in the vast majority of cases. It's all C++, and operator overloading is part of the "sane subset" that everyone uses even if they hate the excesses of modern C++ as a whole.
replies(1): >>36150721 #
16. nickelcitymario ◴[] No.36150574[source]
> [...] easy things seem easy primarily because they are familiar. Easy is subjective. But simple things are simple because they do not complicate; they have fewer concepts. Simple is objective.

This should be printed out as a large poster in every office.

replies(1): >>36154489 #
17. eatonphil ◴[] No.36150581{3}[source]
This is basically what I've come to do in the Zig scripts I write at work.

It took a bit of getting used to when I joined but we agreed as a team to have all meaningful scripts written in Zig not bash (for one, bash doesn't work on Windows without WSL and we need to support Windows builds/testing/etc.).

It makes about as much sense as any other cross-platform scripting option once I got used to it!

Some examples:

Docs generation: https://github.com/tigerbeetledb/tigerbeetle/blob/main/src/c...

Integration testing sample code: https://github.com/tigerbeetledb/tigerbeetle/blob/main/src/c...

Running a command wrapped in a TigerBeetle server run: https://github.com/tigerbeetledb/tigerbeetle/blob/main/src/c...

replies(1): >>36151035 #
18. TwentyPosts ◴[] No.36150587[source]
Afaik Zig has the issue that basically everything happens on the Discord server, where it can't be indexed via search engines, or found by anyone who wants to have a quick question answered. This would be "fine" if the standard library and language were much better documented, but it isn't, and it's still ripe with bugs.

In other words, you're forced to use the Zig Discord server if you want to find answers to any simple questions, and this is (sadly) not obvious at all to newcomers to the language.

replies(2): >>36152039 #>>36152584 #
19. chjj ◴[] No.36150616[source]
Do you maintain any C projects? Personally, I tried using zig for its build system (which can also compile C and whose build files are written in zig). One of the benefits of this was easy cross-compilation to all major platforms.

It might not be a _real_ use-case or anything, but writing a `build.zig` file for an existing C project might be a good way to at least dip your toe in the water.

20. ldelossa ◴[] No.36150624[source]
I'm surprised that the reason I'm mostly interested in Zig is not mentioned.

This is C interop.

I work with C quite a bit and I enjoy it, however writing a large project in C can be tiresome.

Having an option like Zig which can import C headers and call C functions without bindings is pretty attractive, especially when you want to write something a big larger but still stay in C world.

replies(6): >>36151152 #>>36151354 #>>36151700 #>>36153013 #>>36153780 #>>36158610 #
21. latch ◴[] No.36150665[source]
I've now written a lot of zig code (http.zig, websocket.zig, log.zig, zuckdb.zig, etc.) I think Zig falls into an "easy to learn, average/hard to master" category.

Some insiders underestimate the effort required for newcomers to build non-trivial things. I think this is because some of that complexity has to do with things like poor documentation, inconsistent stdlib, incompatible releases, slow release cycle, lack of package manager, etc. For an insider living and breathing Zig, not only aren't these huge challenges, they aren't really "Zig" - they are just transient growing pains. For someone getting started though, the current state of Zig is Zig.

I wish Zig had a polished package manager (there's one in the current development branch, but you don't as much use it as fight it). They could then move some of the less polished code into official experimental packages, helping to set expectations and maybe focus the development efforts.

replies(7): >>36151206 #>>36152145 #>>36153037 #>>36153777 #>>36159350 #>>36159799 #>>36178599 #
22. frankjr ◴[] No.36150672[source]
I've been playing with it and so far but I'm more impressed with their build system rather than the language itself (it seems to be way more flexible and simpler than alternatives which is pretty rare). They did however get the module system right. You can just organize the file structure in any way you like. I hate Rust's "everything is a single module" system with passion.
replies(1): >>36155014 #
23. pron ◴[] No.36150717{3}[source]
The objects that are manipulatable by comptime are ordinary program objects and types -- not ASTs. That means that while it's true you can get compile-time errors in similar situations to macros, the errors themselves are like ordinary runtime errors in an untyped language -- while occurring at compile-time, they look like runtime error in Python or JS -- rather than errors due to some "second-order" manipulation of symbols like templates or macros, and so are easier to diagnose (you get a regular stack trace for one).

There is also another interesting difference, albeit a theoretical one. Zig's comptime is what's known in formal languages to be referentially transparent (it basically means that you cannot distinguish between two otherwise identical objects that differ only in their reference name) while macros are not. Because referential transparency is strictly less expressive than "opacity" (but it's also simpler!), it's surprising that so many practical use cases for macros can be addressed with the less powerful (but simpler and much easier to debug) comptime. That's quite a discovery in language design. While other languages also have comptime-like constructs, they also have other complex features that have made it hard to see just how powerful something like comptime alone can be.

replies(3): >>36151303 #>>36151943 #>>36156263 #
24. felixgallo ◴[] No.36150721{4}[source]
as a long time game dev, I actively don't want operator overloading. That's some spooky action at a distance nonsense. I'm not sure I have seen a codebase that involved operator overloading, either, and I've worked in or near a good quantity of well-known titles.
replies(3): >>36150843 #>>36151267 #>>36160066 #
25. pjmlp ◴[] No.36150748{3}[source]
Not really, it is mostly around communities like Handmade, most studios couldn't care less and it doesn't fit most engines that they are using.
replies(2): >>36161455 #>>36161478 #
26. Dowwie ◴[] No.36150773{3}[source]
Try Elixir.
27. ljlolel ◴[] No.36150784{3}[source]
Idea: allow some weird Unicode operators like Julia does. Then it’ll be clear the weird operator is doing something weird and new. And this already works in other languages. There are lots of Unicode
replies(1): >>36151239 #
28. audunw ◴[] No.36150795[source]
I like Zigs justification for not having general purpose operator overloading (no hidden function calls and loops)

But I wish they added:

1. Ability to declare completely pure functions that have no loops except those which can be evaluated at compile time. Something with similar constraints as eBPF in other words. These could be useful in many contexts. 2. Ability to explicitly import overloaded operators, that can only be implemented using these pure guaranteed-to-finish-in-a-fixed-number-of-cycles functions.

Then you'd get operator overloading that can be used to implement any kind of mathematical function, but not all kinds of crazy DSL-like stuff which is outside the scope of Zig (I have nothing against that, I've done crazy stuff in Ruby myself, but it's not suitable for Zig)

29. sciolistse ◴[] No.36150816{3}[source]
There is https://ziglang.org/documentation/master/std but it's not always been correct, and the descriptions are lacking. The new one should hopefully fix that.

Personally I've never had an issue reading through the source for zig std, and if your editor supports it you can just 'go to implementation' on most things. Hopefully the code remains relatively readable since I find it preferable to see the actual code + some basic tests rather than trying to navigate those documentation sites.

30. pjmlp ◴[] No.36150833[source]
In what concerns userspace, I don't see any good case, if I want a better C, without much features, I rather stick to Go even if I dislike some of the design decisions.

Or D, Nim, Swift, OCaml, Haskell, AOT C#, AOT Java,...

If any kind of automatic memory isn't possible/allowed, I would be reaching out for Rust, not a language that still allows for use-after-free errors.

Maybe it is a good language for those that would like to have Modula-2 with a C like syntax, and metaprogramming capabilities, and are ex-Objective-C developers.

replies(1): >>36151027 #
31. jeroenhd ◴[] No.36150840[source]
I like Zig as a concept, but every time I've tried it, the toolchain lacked good IDE and debugger support. I've tried some plugins half a year ago but they either didn't work reliably or they missed important features. I'm personally sticking with Rust until the day comes that I can just add a VSCode/Clion plugin that'll give me an interactive debugger with full autocomplete support without fiddling around too much.

There's a lot to like with Zig, despite its unconvential syntax and some language decisions I personally disagree with. The language is still in development but it's very promising and I'll definitely try to learn it before it reaches that magical 1.0 release.

replies(1): >>36150871 #
32. jsheard ◴[] No.36150843{5}[source]
There's no accounting for taste, but the two major publicly available engines (Unreal and Unity) both use operator overloading in their standard math types.
33. jcalabro ◴[] No.36150871[source]
I've definitely had a good experience writing Zig in VS Code with the CodeLLDB extension on Linux [0] and the Microsoft C++ [1] one on Windows. It's also got the Zig extension which comes with the Zig language server [2].

[0] https://marketplace.visualstudio.com/items?itemName=vadimcn.... [1] https://marketplace.visualstudio.com/items?itemName=ms-vscod... [2] https://marketplace.visualstudio.com/items?itemName=ziglang....

34. thih9 ◴[] No.36150885[source]
> "I learned Zig in a weekend! … Six hours! … 6µs!" say the blissful lizards.

I don’t get it; is this a reference? Could someone explain?

replies(1): >>36151054 #
35. distcs ◴[] No.36150918[source]
> If I use the general purpose allocator then my edge case is PC out of memory

What does PC mean in this context?

replies(3): >>36150984 #>>36151014 #>>36154342 #
36. rayiner ◴[] No.36150933[source]
Alternative languages are cool, but I struggle to see the point of a systems programming language that doesn't offer static memory safety in 2023. Rust isn't necessarily the best and final answer--it seems like there is a broad design space to explore for memory-safe systems programming languages. But Zig seems to occupy the same local maximum as C--a relatively simple, non-safe systems language--and doesn't have a killer feature that justifies not just using C.
replies(3): >>36151428 #>>36152916 #>>36155063 #
37. pron ◴[] No.36150946[source]
As someone who works on another language that is relatively reluctant to add language features (Java) we regularly face such dilemmas. A user shows up with a problem that could be helped by the language. The problem is real and a language feature would work, but there are many such problems, and adding features to solve all of them will make the language much bigger, overall causing greater harm (even those who don't themselves use the feature need to learn it to be able to read code). What we try to ascertain is how big of a problem it is, how many programs or lines of code it affects, and is there possibly a single feature that could solve multiple problems at once.

So I would ask you this: what portion of your program suffers from a lack of user-defined infix operators and how big of a problem is it overall? Even if it turns out that the problem is worth fixing in the language, it often makes sense to wait some years and then prioritise the various problems that have been reported. Zig's simplicity and its no-overload (not just operator overloads!) single-dispatch is among its greatest features, and meant to be one of its greatest draws.

replies(2): >>36153538 #>>36161441 #
38. distcs ◴[] No.36150954[source]
> Some languages (e.g. lisps) are deceptively small by relying on macros that form a "second-order" language that interacts with the "first-order" language, but Zig doesn't have that.

What are some other examples of such languages that rely on second-order languages? You mentioned Lisps. Would Forth be another example? Are there more examples?

replies(2): >>36151021 #>>36151189 #
39. nativecoinc ◴[] No.36150984{3}[source]
Maybe "the whole computer is out of memory" (general purpose allocator). Contrast with a custom allocator which might only be able to work with a few kilobytes (for example).
40. sigsev_251 ◴[] No.36151013[source]
To be fair, there is an operator overloading proposal for C2y/C3a and there is at least one compiler that offers operator overloading as an extension.
41. helen___keller ◴[] No.36151014{3}[source]
Personal computer
42. pron ◴[] No.36151021{3}[source]
C++ templates. Also the rich type-level language in languages like Idris (these are qualitatively different, but I'd say they're another example of a second-language-within-a-language that operates at a different level of objects).
replies(1): >>36151214 #
43. distcs ◴[] No.36151027{3}[source]
> If any kind of automatic memory isn't possible/allowed, I would be reaching out for Rust

I have come to the same conclusion but then I also fear that Rust will continue to expand in scope and become a monster language like C++. Do you or anyone fear that? Is that a possibility?

replies(2): >>36151271 #>>36151346 #
44. rowls66 ◴[] No.36151035{4}[source]
I am truly puzzled by this. I understood Zig to be a very low level language like 'C'. Why would you write scripts in it?
replies(1): >>36151084 #
45. tylerscott ◴[] No.36151054[source]
IIRC the mascot is a lizard so here the comment is portraying a Zig enthusiast keen on promoting the ease of learning Zig as a lizard. That was my take.
46. ImprobableTruth ◴[] No.36151058[source]
You still have to memorize the "design patterns" that replace 'missing' features. Especially annoying for something like interfaces where there's a bunch of variants and people often use implementations with awful error reporting reminiscent of C++ templates.

Now, it's definitely neat that you can do reasoning from first principles on it, but I'm not sure how much of a gain that is.

47. cynicalsecurity ◴[] No.36151071[source]
Wait, it's a real language? I thought it was a sarcastic article about an imaginary language called zig making fun of hipster languages desperately trying to replace C/C++.
48. eatonphil ◴[] No.36151084{5}[source]
It's significantly nicer to write than C (my opinion obviously). I see it as a general purpose language.

But mostly the team decided to do this because we wanted to unify on one language and double down on the investment in Zig.

I'm not a fanboy (nothing wrong if anyone is, just clarifying about myself); I think this choice was right.

replies(4): >>36151224 #>>36151600 #>>36152429 #>>36155338 #
49. mr_00ff00 ◴[] No.36151102{3}[source]
Would love to see zig in game dev. I’ve tried some rust and while I love rust in general, I find game dev in it a bit of a mess.
replies(2): >>36152719 #>>36158754 #
50. workethics ◴[] No.36151152[source]
Not only that, but zig makes linking against old glibc versions easy. For example, to make an x86_64 linux build linked against glibc 2.9 when using zig build all you have to do is pass:

  -Dtarget=x86_64-linux-gnu.2.9
replies(3): >>36152369 #>>36158596 #>>36184449 #
51. TaupeRanger ◴[] No.36151179[source]
Maybe a few years ago it would've been "worth it". But with LLMs coming to swallow up all coding tasks and turning programmers into prompt engineers within a few years time, I can't see it being "worth it" any more.
replies(2): >>36151207 #>>36152363 #
52. spenczar5 ◴[] No.36151189{3}[source]
I think Ruby is sometimes used in a way that looks second-order. It allows so much metaprogramming that you can really make a full DSL. For example, RSpec:

   describe "order" do
     it "is marked as complete" do
       expect(@order).to be_complete
     end

     it "is not yet shipped" do
       expect(@order).not_to be_shipped
     end
   end
53. sarchertech ◴[] No.36151194[source]
I tried Zig for a few weeks but ended up choosing Odin for a game dev side project I’m working on. Odin feels a lot more high level, but still gives you low level control when you need it.
replies(1): >>36151810 #
54. zoogeny ◴[] No.36151206[source]
I've lately thought that a package manager is as essential to a new language as a standard library. I would also add a LSP and standard code formatter to that list.

It is a bit unfortunate because all of the above is a pretty tall order. We're getting to the point that new languages are expected to boil the ocean by the time they reach 1.0

replies(8): >>36151679 #>>36152038 #>>36152323 #>>36152773 #>>36153966 #>>36154058 #>>36155307 #>>36159420 #
55. Taywee ◴[] No.36151207[source]
You still need to understand the code you are generating, testing, and debugging. LLMs don't replace a need for more expressive programming languages.
56. ImprobableTruth ◴[] No.36151214{4}[source]
If type level functions are a "second language", then so is Zig's comptime.
replies(1): >>36152421 #
57. vaughan ◴[] No.36151224{6}[source]
I'm moving all my scripting to TypeScript using Bun (JS runtime written in Zig).

For scripting its a way better choice. `bun:ffi` also makes it trivial to run C or Zig code when you need to.

58. spenczar5 ◴[] No.36151239{4}[source]
Writing greek symbols is sufficiently annoying that I always kind of resent code that does this. It’s not just about the first time you are writing code, but also when you are reviewing it, or trying to share a snippet with a coworker, or lots more scenarios. Maybe it’s just me, but writing ‘z = x ∇ d’ is really tedious.
replies(2): >>36153390 #>>36156259 #
59. Taywee ◴[] No.36151267{5}[source]
You'd rather use explicit function calls for all linear algebra and geometry operations? I don't think adding two vectors using an overloaded + is that spooky or distant.
replies(1): >>36152896 #
60. vilunov ◴[] No.36151271{4}[source]
Rust hasn't grown in scope very much since its release, but in places where it has grown, particularly async and unpin, I find that there features interact very badly with lifetimes and borrowing. I am often forced to ditch borrowing across async method calls and to put everything in Arcs, even when the lifetime is well-defined and it could be easily used if it had been scoped threads instead of futures. I fear that newer features will be incompatible with older ones in a similar way, but fortunately there are no such features on the horizon.

Considering all that, I still see Rust as the most sane choice for writing native programs. I don't really want a "better C", I want to write memory-safe software with confidence, and that means static analysis or a thick safe runtime, whatever is more suitable for the use case.

replies(1): >>36154236 #
61. stared ◴[] No.36151295[source]
What are the use-cases in which it might be worth switching from Rust to Zig?
replies(2): >>36151409 #>>36151637 #
62. auggierose ◴[] No.36151303{4}[source]
It's not really surprising that purely functional programming is expressive. Indeed, it is as expressive as "opaque" programming.
replies(1): >>36151398 #
63. TwentyPosts ◴[] No.36151346{4}[source]
Will Rust keep growing? Yes, I think so.

Will it turn into a C++-like monster? I don't know. Maybe, but when it comes to C++ it always feels like its "monster" status is largely a result of previous mistakes or early design decisions piling up, and causing trouble (eg. C-style arrays, exceptions, implicit conversions, fiddly sum types rather than first class support, no pattern matching etc.).

Rust will grow large, and probably complicated, but the real issue with C++ are all these past mistakes and a shaky foundation, and Rust is doing much, much better in that regard. Time will tell if we'll eventually look back some of Rust's design decisions as bad or unwieldy (probably).

replies(1): >>36152157 #
64. ziml77 ◴[] No.36151354[source]
The thing that's espcially nice about that interop is that Zig includes its own C compiler. That eliminates the pain of having a build script locate an installed C compiler and figure out what options should be passed to it.
replies(1): >>36156867 #
65. pron ◴[] No.36151398{5}[source]
There's nothing pure functional here (perhaps the term "referential transparency", which some FP fans have come to misunderstand and perpetuate its misunderstanding is what may have given you that impression). Referential transparency is very much less expressive than referential opacity, as there are certain statements that simply cannot be expressed if your language is referentially transparent. For example, in programming, a referentially opaque expression can refer to the name of the variable holding some value. In programming, languages like Zig and Java are more referentially transparent than languages like C and Haskell because the latter have macros.
replies(2): >>36151778 #>>36151826 #
66. logicchains ◴[] No.36151409[source]
When you need to be very careful about memory allocation and use various custom allocators for stuff, and you don't care too much about memory safety. Rust makes working with custom allocators somewhat painful, in exchange for safety, so if you don't need the safety, no point going through that pain.
replies(1): >>36156714 #
67. helen___keller ◴[] No.36151428[source]
If we’re comparing C to Zig I’m not sure what memory safety even needs to be mentioned for.

For C to Zig there’s plenty of reasons one might prefer Zig. For memory safety obviously you might opt to choose neither.

replies(2): >>36151840 #>>36160740 #
68. jasfi ◴[] No.36151469[source]
Nim isn't hard, it just has a small community.
replies(1): >>36152592 #
69. mcdonje ◴[] No.36151486[source]
>Use Zig as a zero-dependency, drop-in C/C++ compiler that supports cross-compilation out-of-the-box.

- ziglang.org homepage

70. 59nadir ◴[] No.36151600{6}[source]
For what it's worth I think this is an excellent choice. Back in 2019 I was deciding whether I wanted to pursue Zig full-time and one of the upsides that I determined was that once you reach critical mass writing all of your code for tools and things in Zig you end up with things that are really exactly what you need and with a very high baseline for speed, flexibility, and so on.

Right now I'm considering the same thing but with Odin and for many of the same reasons that I had for Zig; it's an excellent language to write foundational code in and once you do, you end up being able to build significantly more understandable, reliable, stable and consistent things.

This, but on a company level, is a real multiplier. Once you adopt a couple of Python scripts and that's OK, you give up the possibility of wielding this sharp spear.

Edit:

I think "How I program C" by Eskil Steenberg is an interesting window into what you can get if you laser focus on a language and environment and allow yourself to build up a mountain of code that you dogfood: https://www.youtube.com/watch?v=443UNeGrFoM

At some point I will likely soft-retire and at that point it's exceedingly unlikely that I'll bother with using other people's libraries except a few key ones that I think are decent, and at that point there really is no reason I'd sit down and write these fundamentals in anything but a lower-level language. Odin, Zig or something like it would pretty much be the only thing on the table.

replies(1): >>36161190 #
71. epage ◴[] No.36151637[source]
matklad, of rust-analyzer fame among many other things, wrote up their thoughts on Zig: https://matklad.github.io/2023/03/26/zig-and-rust.html

I've seen some put it as "zig is good when `unsafe` heavy code".

Personally, even when writing life-or-death software, allocation errors were too much of a pain to deal with and much prefer Rust's approach for 99% of software. The question is if another language like zig provides enough value to justify existing for that 1% of use cases (all numbers made up :) ).

72. arp242 ◴[] No.36151679{3}[source]
Zig has a pretty decent LSP.

I'm not so sure a package manager is really all that essential; it can certainly be convenient but especially in the space Zig is looking at it's pretty workable without one (without complex deep dependency trees you can use git submodules or just copy a directory). Or let me put it this way: I never really missed a package manager in Zig.

replies(2): >>36151940 #>>36156168 #
73. Fiahil ◴[] No.36151700[source]
C interop is not as much a "killer feature" as it used to be. When you deal with data science, web and other similar domains, reading and writing JSON ergonomically is much more important than being able to call a C function directly. It's just a nice-to-have.
replies(1): >>36152631 #
74. loeg ◴[] No.36151708[source]
> Aside from lack of community I’d say the biggest nuisance is error handling in nearly everything including allocations. I get that allocation can fail but the vast majority of programs I write, I just want to panic on an allocation failure (granted these aren’t production programs…)

The C strategy for this was just to wrap malloc() with something called xmalloc or malloc_nofail or whatever:

  void *malloc_nofail(...) {
    void *res = malloc(...);
    if (res == NULL) {
      abort();
    }
    return res;
  }
(Or whatever.) The same would work in Zig, I think.
replies(1): >>36152405 #
75. tuhats ◴[] No.36151746[source]
I have played around with using @Vector for linear algebra.

This removes the need for operator overloading for a vector type, which covers most use cases of operator overloading and I often in fact think is the only legitimate use case.

I don't get to use `*` for matrix multiplication, but I have found I do not mind using a function for this.

I have only been playing with this in small toy programs that don't to much serious linear algebra and I haven't looked at the asm I am generating with this approach, but I have been enjoying it so far!

76. whateveracct ◴[] No.36151778{6}[source]
Can you give me an example of a Haskell expression which isn't reverentially transparent (without unsafePerformIO)?

> An expression is called referentially transparent if it can be replaced with its corresponding value (and vice-versa) without changing the program's behavior.

^ that is the definition of referential transparency I am aware of.

You seem to be implying that FPers have bastardized the term through their misunderstanding.

But the bog standard FP definition is a real and useful concept. Maybe it stole something else's name? But I don't think it's due to being mistaken. Because the FP concept itself is pretty rigorous.

replies(1): >>36153339 #
77. kapperchino ◴[] No.36151792[source]
For the math stuff you can do things like a builder pattern where you can flatten the nested functions. But operator overloading is definitely preferred
78. 59nadir ◴[] No.36151810[source]
I've settled on Odin as well and I think it's currently way ahead for game development than Zig is. Even for other things I'm currently more likely to write it in Odin, despite writing Zig from 2019 to 2022. The reasons really come down to error handling being better in Odin overall with payloads being attachable to errors as well as the context system and zero values making it relatively painless to really only talk about the things that need talking about and letting the rest be unsaid.

There are also several similarities: Custom allocators as part of the ecosystem and language, no RAII, easy ways to propagate and handle errors the right way, tagged unions with table stakes like exhaustiveness checking.

I think Odin and Zig have some fundamental differences (and plenty of similarities) and when trying Odin out I was surprised to find that I preferred the Odin way overall.

For gamedev stuff Odin wins due to a few things; swizzling on a code level is super nice, array programming built-in to the language, vendor libraries shipped with the language that allow you to just get going almost no matter what you're doing, and so on.

replies(1): >>36152362 #
79. auggierose ◴[] No.36151826{6}[source]
Referentially transparent means that you can replace an expression with its value without changing the meaning of the program. If everything you can do must be referentially transparent, then that's purely functional programming, because applying functions without side-effects is pretty much the only thing you can do then. Of course, there are some other techniques like rewriting, which strictly speaking are different from purely functional programming, but I consider these two things to be pretty much the same thing.
replies(1): >>36152488 #
80. rayiner ◴[] No.36151840{3}[source]
In a vacuum, one might prefer Zig. But given that everyone already knows C and the ecosystem is so highly developed, it takes a gamechanging feature like Rust's memory safety to make an alternative language attractive (beyond a "this is cool" project--which I totally support).
replies(2): >>36152648 #>>36152940 #
81. ReleaseCandidat ◴[] No.36151940{4}[source]
> I'm not so sure a package manager is really all that essential;

For open source software (libraries or programs, that depend on other libraries or programs), it is essential (if you're not distributing single functions like with Unison). For closed source it doesn't matter that much.

replies(1): >>36152075 #
82. Symmetry ◴[] No.36151943{4}[source]
I haven't had a chance to play with comptime in Zig yet but I'm sort of curious how it compares to Nim's compile time facilities. You can declare variables with 'var' for true variables, 'let' for things that are runtime constant within a scope, or 'const' for compile time constants whose values can come from functions or whatever as long as it can be resolved by the compiler. And then you've got 'when' as a compile time equivalent of 'if'.
replies(1): >>36152901 #
83. michaelcampbell ◴[] No.36151998[source]
I don't know Zig so I can't comment much on the content, but the author's writing style I enjoyed immensely; enough to make me want to pick up Zig for fun. I do have some C background, albeit decades ago, so maybe I'm in the right spot for it.
84. adamrezich ◴[] No.36152038{3}[source]
package managers are relatively easy to put together and release with your language—provided that you want your new package manager and surrounding ecosystem to work exactly the same as other, popular ones, without putting any effort into improving the status quo. doing better than other languages' package managers takes significant effort, because it's both a computer engineering problem and a social engineering problem.

it's nice when a new language has a package manager right out of the gate, but I would like to see more new languages take a more measured approach and aim to significantly improve upon past efforts, instead of merely replicating them out of some sense of obligation.

85. girvo ◴[] No.36152039{3}[source]
This is true for Nim as well, in that most of the discussion is on the Discord/Matrix server. I’m not a fan personally, at least IRC was easily archived and searchable in practice.

I really dislike how Discord has become “forums in the 2020s”

replies(1): >>36183376 #
86. ok123456 ◴[] No.36152055[source]
One annoying thing I ran into when trying zig is they don't distribute debs any more for Debian distributions. They just tell you to use a snap. I don't have snap, and don't want it.

Compiling it requires the latest llvm toolchian (16), which is only realistically going to be available as a package if you're on a bleeding edge distribution.

replies(4): >>36152162 #>>36152563 #>>36154601 #>>36158861 #
87. arp242 ◴[] No.36152075{5}[source]
"cp -r ~/some-lib ~/my-project/" works well enough if some-lib doesn't have dependencies on its own. Or git submodules if you want something a bit more fancy. I sometimes do this even for languages with package managers, as it avoids a world of complexity.

Obviously a package manager is useful, but Zig is relatively low-level and long dependency chains are much less common than in e.g. Python, Ruby, and of course NodeJS. So I'd argue it's not essential. All the other things mentioned in the to top comment are far bigger issues IMO.

replies(1): >>36152410 #
88. askkk ◴[] No.36152113[source]
In new last version 0.10.1 it seems that for is not working with two arguments?

  const std = @import("std");
  const expect = std.testing.expect;

  test "for basics"  {
    const items = [_]i32 {4,5,3,4,0};
    var sum: i32 = 0;
    for(items, 0.. ) |value,_| {
      sum += value;
     }
     try expect(sum == 16);
  }

  ubuntu 22.04, snap zig version 0.10.1 , 
  zig test 1.zig produces:

  1.zig:7:12: error: expected ')', found ','
  for(items, 0.. ) |value,_| {
           ^
Edited: To update, I tried snap, but using snap install --classic --beta zig is a security risk because it can change the system and is not sandboxed.
replies(1): >>36153140 #
89. JC770 ◴[] No.36152145[source]
I just start to learn Zig,any suggest to beginners?Bro
replies(2): >>36152443 #>>36165230 #
90. riceart ◴[] No.36152157{5}[source]
> Time will tell if we'll eventually look back some of Rust's design decisions as bad or unwieldy (probably).

I think time has already told for things like async and lifetimes.

replies(2): >>36152689 #>>36155616 #
91. pacaro ◴[] No.36152162[source]
I understand this, but haven't found this to be an issue personally. I just download the pre built tarball, expand it, make sure that /opt/zig-latest symlinks to the right folder, and setup path

That's more work than apt-get install for sure, but not so much more

replies(1): >>36154333 #
92. flohofwoe ◴[] No.36152172[source]
Zig has a builtin @Vector type that might come in handy for most cases where in C++ a math library with operator overloading would be used:

https://www.godbolt.org/z/7zbxnncv6

...maybe one day there will also be a @Matrix builtin.

replies(3): >>36152928 #>>36153017 #>>36154505 #
93. chrsig ◴[] No.36152323{3}[source]
> I've lately thought that a package manager is as essential to a new language as a standard library. I would also add a LSP and standard code formatter to that list.

Agreed. Especially on a formatter. The number of code review comments it cuts out is incredibly time and energy saving.

> It is a bit unfortunate because all of the above is a pretty tall order. We're getting to the point that new languages are expected to boil the ocean by the time they reach 1.0

In order to get into production? yes. there are minimum requirements that must be met. those are higher now than in the past, because of lessons learned the hard way. those problems have been solved (for some value of solved) in existing ecosystems -- a new language wont change the need for them to be solved.

it shatters the dream of hacking up something on a weekend and having it turn into a hit success, but it also removes the case of hacking up something in 10 days and suffering the consequences for the next 30 years.

Until they have what you mentioned, the languages aren't ready for large scale use -- they need to grow into it. They can be useful prior to that -- enthusiasts and early adopters can reap what benefits are provided. That adoption is what fuels the development of things like a standard code formatter.

edit: fixed omission of a unit of time after '30'

replies(4): >>36154051 #>>36156226 #>>36158675 #>>36162098 #
94. truckerbill ◴[] No.36152362{3}[source]
I want to invest in Odin but I see the velocity and growing mindshare that Zig has and I wonder if it's not better to settle for that. Also how do you find the compile times?
replies(3): >>36152942 #>>36154264 #>>36158510 #
95. mr_00ff00 ◴[] No.36152363[source]
I don’t want to make assumptions, but have you tried systems programming with LLMs?

A few years and everyone will be prompt engineers is laughable. I hope I can actually use it productively for more than unit tests in a few years.

96. GordonS ◴[] No.36152369{3}[source]
Damn, that's a magnificent feature! Maybe I should have another look at Zig...
97. helen___keller ◴[] No.36152405{3}[source]
Yes you can easily make a one liner allocation function in zig that takes an allocator as input with a comptime type and panics if allocation fails and returns the unwrapped allocation

I just say nuisance because zig code often looks like Go code in that almost every return type becomes an error union as allocation error handling (and maybe other errors) trickle up

replies(1): >>36152431 #
98. pron ◴[] No.36152421{5}[source]
It's not. comptime reifies types as regular objects (pretty much like maps), so you're not working at the type level; it's no more of a second language than reflection in Java. Of course, you cannot express things like the famous vector concatenation that's expressible with dependent types (https://gist.github.com/cbiffle/82d15e015ab1191b73c3) (unless the vector sizes are known at compile time, obviously).
99. hoosieree ◴[] No.36152429{6}[source]
Binary executables are a nice feature, especially for distributing to users.

It's much easier for most people to download a standalone "mac" or "windows" binary than to know if they already have the right version of Python or Perl or Clang (and all the transitive dependencies your project adds).

replies(1): >>36152503 #
100. TylerE ◴[] No.36152431{4}[source]
From my experience with Zig (limited but not zero) it seems like an ok solution to a problem I don't have, and don't forsee having.
101. hiccuphippo ◴[] No.36152443{3}[source]
Other than the main documentation, check ziglearn.org and ziglings.org. Also read the std code, specially the tests when you want to know how to use something.
102. pron ◴[] No.36152488{7}[source]
> Referentially transparent means that you can replace an expression with its value without changing the meaning of the program.

Not quite. A referentially transparent expression (E) is one where you can replace any of its subexpressions (A) with another (B) that has the same meaning (not value!!!!) as (A) without changing the meaning (not value!!!) of E. However, in purely functional languages, the meaning of any expression is a value, but that's the important thing about them, not the fact that they're referentially transparent as imperative languages equally are. We often use the word "semantics" or "denotation" instead of "meaning" in the above, and we say that a pure functional one is one that has "value semantics", i.e. one where the meaning of an expression is a value.

Most programming languages are referentially transparent when not using macros (that was the whole point of talking about referential transparency in programming in the first place), and that's important because it demonstrates both the expressive power and the complexity of macros.

replies(2): >>36153708 #>>36154329 #
103. eatonphil ◴[] No.36152503{7}[source]
We don't host the built binaries of these scripts (we could!), but we bootstrap the local environment through a single bash script or batch script (Windows) that pulls down the Zig compiler. Then everything else in the repo depends only on that until we get until client-language specific bits which of course depend on other languages.

But yeah it is quite simple still.

104. netule ◴[] No.36152563[source]
Zig's in the process of getting added to the mainline Debian repositories: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=995670

Hopefully, this process will continue soon as the bug seems to be getting a bit stale.

105. scns ◴[] No.36152584{3}[source]
The new Zulip version can make chats accessible from the outside. In the thread about it someone wrote OSS Projects should switch to it.
106. anta40 ◴[] No.36152592[source]
I haven't done any production-level stuff with Nim (still learning it), I think overall it's a nice language (I also like Python & Pascal).

If your goal is applying for job, Go is obviously a better pick.

107. tuckerpo ◴[] No.36152608{7}[source]
Why? A submodule can be frozen at a given commit. They're trivially updated or rolled-back, too.
108. afdbcreid ◴[] No.36152631{3}[source]
Yeah, but when you're doing systems programming (which Zig aims at if I understand correctly), easy interop with C is much more important than easy JSON marshalling.
109. helen___keller ◴[] No.36152648{4}[source]
That is probably why Zig has such a focus on seamless C interop. There’s a good thread in these comments talking about this.

Regardless, point taken. You’re more or less describing the internal fear I have (mentioned in another thread) that if I dedicate time to a nontrivial Zig project I will regret it if/when there’s no Zig community in N years

110. pjmlp ◴[] No.36152689{6}[source]
async, yeah it could be better, given the pains. However note that adding async to .NET and C++ hasn't been a panacea either, to the point that there is a prototype of adding Go/Java green threading to .NET, done by the .NET team. While with the C++ standard library there isn't an executor runtime in the box.

Lifetimes are painful, and a other languages are exploring better ergonomics or combining automatic memory management with affine/linear types, yet it was Rust's adoption that pushed other language designers to actually look into this. So from that point of view, quite a success, even if Rust vanishes tomorrow.

111. adastra22 ◴[] No.36152719{4}[source]
Have you tried bevy? I’m starting with bevy for a non-game project, but I’m blown away by how simple it is to use once you get used to the magic.
replies(2): >>36153938 #>>36154063 #
112. johnnyjeans ◴[] No.36152773{3}[source]
I disagree. I actively avoid languages that rely on package managers simply because they only give the illusion of being beneficial. It ends up being more boilerplate I have to learn to use an ecosystem, because they don't actually solve dependency hell and now there's a whole additional complicated tool with its own DSL I have to contend with in order to fix what's broken (or even diagnose issues.)

The more peripheral crap I have to deal with to use your language, the less I'm likely to use it in the first place. I don't need, want or care to learn yet another idiosyncratic fragile system. Finding source tarballs is a complete non-issue, and inevitably I'm going to have to manually build things anyways to figure out what erroneous assumption a library is making about the underlying system which is causing the build to fail or the runtime to crash, so the package manager just ends up being extra steps. Without fail, that has always been my experience with language package managers.

In the pursuit of making things simpler, we're really just making them harder.

replies(6): >>36153099 #>>36153117 #>>36153992 #>>36154251 #>>36155105 #>>36172876 #
113. flohofwoe ◴[] No.36152896{6}[source]
FWIW Zig can do that without operator overloading: https://www.godbolt.org/z/7zbxnncv6
replies(2): >>36154682 #>>36154931 #
114. ◴[] No.36152901{5}[source]
115. LispSporks22 ◴[] No.36152905[source]
> Only time will tell if comptime is the "greatest thing since sliced bread" or not.

Common Lisp user here. Am I missing anything that Zig has in the compile time department?

edit: Also, does the code in the comptime block have to be valid Zig?

replies(2): >>36153755 #>>36154118 #
116. haberman ◴[] No.36152916[source]
The killer feature of Zig IMO is comptime. C++ has spent over a decade now marching towards making more and more of the language available at compile time, but in an awkward and complicated way (constexpr, consteval, constinit). Zig comes out of the gate with a unified and coherent compile-time evaluation feature that effectively obsoletes not only constexpr/consteval/constinit, but C++ templates too. This is "doing more with less" in a way that I find really compelling.
replies(1): >>36154539 #
117. jsheard ◴[] No.36152928{3}[source]
That still breaks if you layer any abstractions on top, for example if you wanted to build an AoSoA packet of Vec3s you'd have to define an addition of those in terms of a function.

https://www.godbolt.org/z/v8Ta8hEbv

Zig is exactly the kind of language where you'd want to build a performance-oriented primitive like that, but AFAICT the language doesn't let you do it ergonomically.

replies(1): >>36153332 #
118. Decabytes ◴[] No.36152937[source]
Zig is not my favorite language to program in, but I think it's focusing on a lot of the right stuff.

1. Easy Build System 2. Drop in Replacement for c/c++ compiler (zig cc) 3. Easy cross compliation 4. Single executable compiler 5. Package manager 6. Debugabillity

It's the sort of developer focus that has a huge impact especially when you are doing it for more than just a hobby. Crystal, another language I love, is weak in this area. No tree sitter, No tier1 windows support, Major libraries like the Lucky Framework that don't build on Windows, a buggy LSP etc. Don't get me wrong I love the language, and I will continue to work in it, and all of these things are in various states of progress, but it's already at 1.8 and some of these issues haven't been ironed out yet. I'm not just armchair complaining, I know these are hard, and I will contribute once I am more familiar with the language

119. alwaysbeconsing ◴[] No.36152940{4}[source]
I haven't tried Zig, but "all the things you like about C plus better versions of most/all of the awkward bits" seems like a reasonable value proposition. Especially since the compiler can apparently let you use C painlessly alongside your Zig -- enabling incremental rewriting.
replies(1): >>36153323 #
120. 59nadir ◴[] No.36152942{4}[source]
I think by the time I have a massive project where compile times could actually hurt the newest endeavor with compiling to an intermediate form, etc., will already be released so it's likely that I'll dodge that entirely.

For what it's worth I haven't found any language constructs that seem to make the compile time grow considerably, so I think the risk of adding a library and suddenly being faced with massive compile times is fairly low in comparison to some languages. With that said, I'm only using the core lib and vendor libraries.

JangaFX by way of GingerBill reports that their 200kloc EmberGen[0] project takes 5 seconds to compile:

> On my old machine, it took 5 seconds, and now it takes 2.2 seconds on my new machine.

Before some paths in the compiler had multithreading added to them that number was 15 seconds for the same project. As far as I know both of these numbers are for unoptimized builds, i.e. development builds.

121. jksmith ◴[] No.36152965[source]
Is this a writeup about Zig, or any Wirth language written 50 years ago? Asking for some Modula2 OG.
122. esjeon ◴[] No.36153013[source]
C-interop is pretty perfect for most usecases. The only trouble I had was that, since command line arguments are converted to slices in Zig, I have to convert them back to null-terminated strings whenever I call C functions using any of the arguments. Nothing difficult but slightly painful.
123. throwawaymaths ◴[] No.36153017{3}[source]
Probably not. @Vector is not a mathematical vector, it's SIMD. it makes sense because there are times when those live in registers and a poly fill for stack memory isn't burdensome.

@Matrix makes less sense because when it gets big, where are you getting memory from?

replies(1): >>36153241 #
124. VyseofArcadia ◴[] No.36153037[source]
I used Zig for a weekend project and loved it, but I am resolved to not use it for anything else until it hits 1.0. I don't have time to write and re-write and re-re-write my code as the language and stlib stabilize.
replies(1): >>36158319 #
125. renox ◴[] No.36153058{3}[source]
> I am not much of a Zig-head, but the best compromise I can think of is having a few operators which purely and solely exist for this purpose. In other words, there is no operator overloading, but you can define, say, "#+" for any two structs, or something like that.

And those operators wouldn't have any precedence.

> If you want to take this one step further you'd probably have to allow users to define infix functions, which would be its own can of worms.

As long as these infix function are preceded by a recognizable operator ("#" in your example), I think that this would be fine.

126. zoogeny ◴[] No.36153099{4}[source]
I'm not sure I understand this issue. The existence of a standard package manager doesn't prevent you from manually vendoring dependencies if you want to. I have personal experience working on node.js projects where several dependencies were just `cp` into a directory and treated like local modules, no npm involved at all.

It's like `apt` or `brew` for system dependency management. It is there if you want it but you can just as well download a tar and config/make/install yourself if you want.

In many ways, it is like a standard lib. No one forces you to use it. If you prefer the simplicity of your own implementations then I see no reason why you can't just write your own.

But when you want the advantages of a package manager, and there are advantages that you may not appreciate but others do, then having a standard one built into the language feels preferable to having a dozen non-standard independently competing variations that the community cobbles together.

replies(1): >>36161988 #
127. fauigerzigerk ◴[] No.36153117{4}[source]
The cynic in me would say that including a standard package manager is absolutely necessary to stop several of them popping up every year :)
128. EscapeFromNY ◴[] No.36153140[source]
For loop syntax was changed since 0.10.1.

Zig 0.10.1:

    for(items) |value| {}
    for(items) |value, index| {}
Zig 0.11-dev:

    for(items) |value| {}
    for(items, 0..) |value, index| {}
    for(as, bs, cs, ds, 0..) |a, b, c, d, index| {}
129. chrsig ◴[] No.36153145{3}[source]
I think for the problem space zig is trying to fit in, it's pretty essential to have custom allocator support thoroughly baked in.

It's the sort of thing that lets a data structure be used on both a gpu and cpu, allocation out of shared memory, or ensure that no dynamic allocations are happening at all.

Most programs don't have those concerns - so zig may not be the best choice for them. For the programs that do have those concerns, forethought about allocators is pretty important. Right tool for the job, and all that.

130. flohofwoe ◴[] No.36153241{4}[source]
For 'game-ey' math code, a matrix is at most 4x4 floats (64 bytes), that's fine for a value type that might live on the stack.

vec2..4 and matching matrix types up to 4x4 is basically also what's provided in GPU shading languages as primitive types, and personally I would prefer such a set of "SIMD-y" primitive types for Zig (maybe a bit more luxurious than @Vector, e.g. with things like component swizzling syntax - basically what this Clang extension offers: https://clang.llvm.org/docs/LanguageExtensions.html#vectors-...).

replies(2): >>36154544 #>>36159575 #
131. thechao ◴[] No.36153273{3}[source]
Maybe an operator-overloading region?

    #{
       m3 = m1 * m2 + m3;
       m3 += m4;
    }
Basically, pure syntactic sugar to help the author express intent without having to add a bunch of line-chatter.

Speaking of operator-overloading, I really wish C++ (anyone!) had a `.` prefix for operator-overloading which basically says "this is more arguments for the highest-precedence operator in the current expression:

    a := b * c .+ d;
Which translates to:

    a := fma(b, c, d)
replies(1): >>36154201 #
132. j-james ◴[] No.36153323{5}[source]
Can you use Zig painlessly alongside C? Does `zig cc` or an equivalent provide for writing Zig libraries that then can be called by a main C function?
replies(2): >>36154394 #>>36154464 #
133. flohofwoe ◴[] No.36153332{4}[source]
That's true, but OTH that's already getting into territory where operator overloading might start to become detrimental because it hides important implementation details which might not be expected from a simple '+'.
134. pron ◴[] No.36153339{7}[source]
> Can you give me an example of a Haskell expression which isn't reverentially transparent (without unsafePerformIO)?

Yes: https://github.com/ncaq/debug-trace-var The trick, however, is not unsafePerformIO (destructive mutability has nothing to do with referential transparency in general, although it breaks it in Haskell specifically) but with TemplateHaskell, as quoting has everything to do with referential transparency.

> But the bog standard FP definition is a real and useful concept.

Actually, it's rather tautological. It defines FP circularly (see my comment here: https://news.ycombinator.com/item?id=36152488). It says nothing more than the far more useful explanation: "the meaning of every expression is a value".

replies(1): >>36153671 #
135. kps ◴[] No.36153390{5}[source]
∇ is near-worst-case since it's not even Greek. I think domain-specific keyboard layouts are as much of a good idea as language-specific layouts, but they're a nuisance to install on *nix (trivial on OS X). Using .XCompose is the most practical *nix approach, in the absence of program-specific methods like Julia's tab-completable backslash names.
replies(2): >>36154436 #>>36156298 #
136. markisus ◴[] No.36153538{3}[source]
In robotics, numerical linear algebra expressions comprise a large part of the code base. If not by line count, then definitely by the amount of time spent writing, reading, and debugging such code. This makes Zig unusable for these applications, at least not without additional tooling. You can get a feel for how unergonomic this is by avoiding the use of all arithmetic operators in your code and instead forcing yourself to use user defined plus(a,b), minus(a,b), assign(a,b), etc, or programming directly with the C blas api.
replies(3): >>36154016 #>>36154155 #>>36159570 #
137. whateveracct ◴[] No.36153671{8}[source]
hm okay so basically anything that doesn't use TH or unsafePerformIO is gonna be referentially transparent. And TH is even deferentially transparent at TH-time. It only "breaks it" when evaluating the whole program. But each "stage" maintains the property.

I'm assuming any pure language with macros is also r.t. at each stage and only pedantically breaks r.t. when combined. But I don't think that especially hurts the ability to do fast and loose reasoning so long as the core language is pure.

It definitely doesn't seem correct to say Java is more referentially transparent than Haskell here. You don't have to go into such niches in Java to lose that property.

replies(1): >>36154194 #
138. mannykannot ◴[] No.36153690[source]
On the other hand, Brainfuck.
139. norir ◴[] No.36153708{8}[source]
Do you have sources for your definition? The original definition that I'm finding from Quine seems to broadly support the interpretation that an expression is referentially transparent if it can be replaced by its value without altering program semantics, as others have stated. Regardless, it isn't clear to me how macros are any more or less referentially transparent than function calls in an impure language.
replies(2): >>36153732 #>>36154447 #
140. whateveracct ◴[] No.36153732{9}[source]
I'm very sure the commenter is being a little pedantic

But even pedantry can't argue that Java is a fundamentally more referentially transparent language than Haskell lol. That threw me for a loop.

replies(1): >>36154477 #
141. kps ◴[] No.36153755[source]
It only has to be syntactically valid (parseable).
142. parasense ◴[] No.36153766[source]
The main take away is:

> Something that makes Zig harder to learn up front, but easier in the long run is lack of undefined behavior.

Reminds me of the old discussions of Fortran Vs C, and specifically in the early times before C had a standard library. What we call "undefined behaviour" was just an idiom of the language where the "behaviour" was sometimes on purpose, but recognised might not be portable. And so the point here is the idea of undefined behaviour is tied to portability on some levels, and isn't just some purely academic idea about the compiler or abstract syntax trees.

So I'm concerned about the potential over-zealous prejudice against undefined behaviour, but I think we can all agree deterministic software is better than otherwise. The catch is that sometimes UB is deterministic, and yet dares to not be idiomatic.

replies(3): >>36153812 #>>36153952 #>>36154133 #
143. cassepipe ◴[] No.36153777[source]
To get an idea, what is your programming background ? Are you a C or C++ programmer ?
144. billfruit ◴[] No.36153780[source]
What about c++ interop?
replies(1): >>36154376 #
145. badrabbit ◴[] No.36153791[source]
Everything is hard when you first learn it. If you find it easy, that's only because you don't have to learn part of it because you learned the concept in a different language. Even learning to count was hard when we were small children.

A better measure IMO is how long it might take you specifically. For example, Rust is much easier for me to learn than Haskell because I have never coded in a functional language before. Golang was very easy to pick up on. I never took time to learn python and powershell, I just kept referencing existing code and googling for examples because they were both mostly familiar languages with a different syntax.

146. Symmetry ◴[] No.36153812[source]
Assuming that bytes are 8 bits long or that negative numbers are represented with two's complement is a lot less dangerous these days than it was when C came along.
147. the__alchemist ◴[] No.36153938{5}[source]
Bevy isn't on the same level as tools like UE and Godot.
replies(3): >>36154350 #>>36155653 #>>36176465 #
148. pklausler ◴[] No.36153952[source]
Ironically, C is now way more portable than modern Fortran is. The Venn diagram of feature portability across the 6 or 7 actively-maintained Fortran compilers is very messy.
149. savolai ◴[] No.36153966{3}[source]
Would love to understand better what exactly is language specific about package managers? You would think a winner would emerge in this space like one has in version control to be used with all languages, just separate repos for different ecosystems?
replies(2): >>36154490 #>>36154491 #
150. galaxyLogic ◴[] No.36153985[source]
Love the picture. People often say how easy something was for them. They are saying they are a very capable, smart person. Would you rather hire someone for whom everything is easy, or someone for whom things seem difficult?

In other words saying they learned something fast or that something is easy for them, is at least partially self-promotion. So claims of how easy something was for them it have to be taken with a grain of salt.

The interesting thing for the rest of us is WHY something is easy, or difficult. That would be helpful for others to know. This article is just that, it tells us why Zig can be difficult. What to look out for.

151. gen220 ◴[] No.36153992{4}[source]
Just curious, not snide: what language fits this criteria?

C/C++? Using Python 3.7+ in a way that completely ignores Pip, because the stdlib is now quite expansive?

replies(3): >>36154078 #>>36154752 #>>36155431 #
152. hellcow ◴[] No.36154016{4}[source]
Using plus(a,b) for complex types sounds fine to me… I have to imagine if I were working with a huge file of these for a while it would start to feel normal, just like every language has a different syntax but you eventually feel comfortable using.
replies(1): >>36157498 #
153. clessg ◴[] No.36154051{4}[source]
> but it also removes the case of hacking up something in 10 days and suffering the consequences for the next 30 years

Ha, I thought this sounded distressingly familiar!

"In September 1995, a Netscape programmer named Brandan Eich developed a new scripting language in just 10 days. It was originally named Mocha, but quickly became known as LiveScript and, later, JavaScript."

replies(1): >>36162085 #
154. paulddraper ◴[] No.36154058{3}[source]
> new languages are expected to boil the ocean by the time they reach 1.0

The reason is that there are existing high-quality languages/ecosystems.

(Which is a good thing!)

155. mr_00ff00 ◴[] No.36154063{5}[source]
Maybe I need to give bevy a second go. My big issue is I felt I was learning to speak “bevy” instead of using rust. A lot of functions I wrote required queries of components, but the queries were built and called behind a magically wall.

I don’t have much game dev experience though outside of simple games using libraries like raylib to just move and draw stuff. Maybe once things get complicated enough they are all like bevy.

replies(1): >>36156019 #
156. paulddraper ◴[] No.36154078{5}[source]
Must be C/C++.
replies(1): >>36162805 #
157. kllrnohj ◴[] No.36154118[source]
Personally I think comptime is a questionably design and is something both Rust & C++ did much better.

In C++ branches that don't have to "compile" are explicitly marked as such with `if constexpr`. In Rust you've got macros that are also explicit with required `!`. In Zig any branch can be a ticking code rot time bomb, just like it was with C #ifdefs. It's better in Zig in that it at least has to parse and so you've got fewer blatant problems, but the category of problems of "I flipped DEBUG from `false` to `true` and now I have dozens of build errors to go fix" is still there. And you really don't have any warning signs other than "this is branching on something that might be known at compile time"

But honestly that's also my general impression of Zig as a whole. It's very definitely a "better C", not something that's necessarily good/competitive with the broader state of the ecosystem. It's like a love letter to C, completely with many of the same general problems that C is known to have and that other languages have addressed.

158. kps ◴[] No.36154133[source]
C89's ‘undefined behavior’ was a failed attempt to say “you get what the hardware gives you”.
replies(2): >>36154438 #>>36157133 #
159. erichocean ◴[] No.36154155{4}[source]
> You can get a feel for how unergonomic this is by avoiding the use of all arithmetic operators in your code and instead forcing yourself to use user defined plus(a,b), minus(a,b), assign(a,b), etc, or programming directly with the C blas api.

You've dramatically overstated your case, since that's true of every Lisp-like language.

Lisp is a perfectly suitable language for developing mathematics in, see SICM [0] for details.

If you want to see SICM in action, the Emmy Computer Algebra System [1] [2] [3] [4] is a Clojure project that ported SICM to both Clojure and Clerk notebooks (like Jupyter notebooks, but better for programmers).

[0] https://mitpress.mit.edu/9780262028967/structure-and-interpr...

[1] Emmy project: https://emmy.mentat.org/

[2] Emmy source code: https://github.com/mentat-collective/emmy

[3] Emmy implementation talk (2017): "Physics in Clojure" https://www.youtube.com/watch?v=7PoajCqNKpg

[4] Emmy notebooks talk (2023): "Emmy: Moldable Physics and Lispy Microworlds": https://www.youtube.com/watch?v=B9kqD8vBuwU

replies(1): >>36157461 #
160. pron ◴[] No.36154194{9}[source]
> You don't have to go into such niches in Java to lose that property.

It's not so easy. You'd have to examine debugging information in stack traces and use reflection. You can't write such a "trace" operator in Java or in Zig. Of course, without macros, C is almost perfectly referentially transparent and Haskell is, too (except for unsafePerformIO).

replies(1): >>36156947 #
161. MH15 ◴[] No.36154201{4}[source]
Huh I've never seen this approach. Very interesting solution, could be adapted to the JavaScript matrix libraries I bet.
replies(3): >>36154476 #>>36154965 #>>36157284 #
162. mr_00ff00 ◴[] No.36154236{5}[source]
Technically though, isn’t memory safety not necessary in some cases?

For example, single player video games. You can exploit your own machine if you want, but that’s not an issue.

I like rust, but if I ran into async issues and annoying stuff, I could see a world where I grab a non-memory safe language to make games easily.

replies(3): >>36154903 #>>36155619 #>>36156300 #
163. JohnFen ◴[] No.36154251{4}[source]
I agree entirely. Relying on a package manager in order for a language to be useful indicates to me that there's a deficiency in the language.
replies(1): >>36155497 #
164. mr_00ff00 ◴[] No.36154264{4}[source]
Just looked at Odin and I really like the syntax, but I feel the same way. I feel like the community and ecosystem is the key elements and zig seems to be headed in the direction to grab that.
replies(1): >>36154844 #
165. auggierose ◴[] No.36154329{8}[source]
Do you have a pointer to a paper where "referentially transparent" is defined in your sense? I grant you that values of a programming language should be distinguished from the meaning of an expression, which will be a value of some sort in the logic. In that sense, any language with a denotational semantics will be referentially transparent. So maybe what you are really saying is: macros usually don't have a denotational semantics. Not sure that it is helpful to call this referential transparency, because it differs from the meaning most people associate with it.
166. hellcow ◴[] No.36154333{3}[source]
You can also use something like zigup to make fetching the latest master/managing multiple versions easier.
167. kubanczyk ◴[] No.36154342{3}[source]
player character
168. Ygg2 ◴[] No.36154350{6}[source]
To be fair Godot isn't on same level as UE.
169. Conscat ◴[] No.36154376{3}[source]
You can call internal and external linkage C++ functions from Zig, but you can't do anything interesting like specialize templates or evaluate constexpr functions.
170. ◴[] No.36154394{6}[source]
171. Conscat ◴[] No.36154436{6}[source]
I interpret this as meaning that ibus is difficult to set up. FWIW, Emacs and Kitty let you input unicode without it.
172. jsmith45 ◴[] No.36154438{3}[source]
Yeah. In hindsight for a fair bit of it, it could have been sensibly changed to implementation defined behavior, or to constrained unspecified behavior. (Constrained such that people know what the possibilities are, but the compiler need not document its choice, and might not make the same choice in all circumstances. The latter could allow for scenarios where letting an optimizer do the faster thing when detectable, and what the hardware natively does otherwise, for example. Obviously still a potential footgun, but less of one than full undefined behavior).
173. pron ◴[] No.36154447{9}[source]
The thing that is preserved is "meaning" or "referent" -- the term Quine uses (hence, "reference transparency") -- not "value". The distinction between referent/meaning and value is the most important aspect of distinguishing between pure FP programming languages and others, and yet that's the thing that is so commonly confused by FPers using the terminology, which makes it quite pointless.

In most programming languages the reference or meaning of a term is not a value; in pure functional languages the meaning is a value and that's what makes them special, not their referential transparency which they share with imperative languages.

Here's an example from C:

    int global_x = 0;

    void f() { x++; }
    void g() { x++; }
f and g have the same meaning in C (but the function `void h() { x += 2; }` does not) yet `m(f)` and `m(g)` will not have the same meaning if M is defined as:

    #define m(x) #x
However, f and g are interchangeable anywhere else (this is not actually true because their addresses can be obtained and compared; showing that a C-like language retains its referential transparency despite the existence of so-called l-values was the point of what I think is the first paper to introduce the notion referential transparency to the study of programming languages: https://github.com/papers-we-love/papers-we-love/blob/main/l... You may be surprised to see that Strachey also uses the word "value" but his point later is that value is not what you think it is)
replies(1): >>36156120 #
174. helen___keller ◴[] No.36154464{6}[source]
Yes probably as painlessly as a nonC language can get. First class support for C calling conventions, struct layouts, and so on

https://ziglearn.org/chapter-4/ See here

replies(1): >>36156173 #
175. thechao ◴[] No.36154476{5}[source]
This is how TeX handles math — the "$" operator is an "inline" version of the same.
176. pron ◴[] No.36154477{10}[source]
Right, the incorrect and quite pointless common use of "referential transparency" in FP fan circles tends to throw people off when they first see and understand the actual meaning of the term.
replies(1): >>36156125 #
177. erichocean ◴[] No.36154489[source]
Rich Hickey has done more to popularize that idea in recent years than perhaps anyone else. [0]

In a lot of ways, Zig is to the systems programming space what Clojure is to the information processing space.

If you have 5+ years experience, you want simple, not easy. Both languages deliver real advances on that promise in their respective domains.

----

Back to the article, perhaps not coincidentally, the product my startup is developing is written primarily in Zig (language runtime), Clojure, and an in-house Forth/Factor/Joy derivative for user-level scripting. I guess I really do care about simplicity…

[0] Simple Made Easy: https://www.youtube.com/watch?v=SxdOUGdseq4

178. anon84873628 ◴[] No.36154490{4}[source]
I was also wondering this. Why does every language need to reinvent the wheel?
179. vineyardmike ◴[] No.36154491{4}[source]
Different languages do imports differently. There are different constructs for “exports” and modules and namespaces that prevent a common single directory structure.

Pip used to store packages in a global location, now most of python used a Virtual Environment per project.

Node uses a “vendor” directory within the project structure. This is probably the easiest case.

Go used to store everything globally in the “go path” but now with go modules it does something else.

Java doesn’t need source code, just single JAR files, but it needs it within the classpath.

C/++ is very flexible, but varied depending on how you build and set up your project.

Swift/ObjC requires doing whatever apple wants and dealing with their tooling.

Everything is different. If you want “one winner” the closest you get it is the system package manager (of which multiple exist) and pointing your project to its package cache. But not all system package managers handle multiple concurrent versions of the same package.

Maybe one day people will standardize against Nix which seems to be the closest?

180. Conscat ◴[] No.36154505{3}[source]
It's a LOT worse than C++ SIMD libraries.

In C++ (EVE, Vc, Highway, xsimd, stdlib), you can specify the ABI of a vector, which allows you to make platform specific optimizations in multifunctions. Or you can write vector code of a lowest-common-denominator width (like 16 bytes, rather than specifying the number of lanes), which runs the same on NEON and SSE2. Or you can write SIMD that is automatically natively optimized for just a single platform. These features are available on every notable C++ SIMD library, and they're basically indispensable for serious performance code.

181. Conscat ◴[] No.36154539{3}[source]
Zig does not have anything analogous to constinit, because Zig does not have object lifetimes or constructors. Comptime is also a massive pain to use for generating new data types (you have to return a type from a comptime function), and it cannot express anything analogous to CRTP.
replies(1): >>36159353 #
182. cmbothwell ◴[] No.36154544{5}[source]
You might like Odin, it has a similar philosophy to Zig and supports swizzling:

https://odin-lang.org/docs/overview/#swizzle-operations

Matrix types are also built in:

https://odin-lang.org/docs/overview/#matrix-type

I’ve thought for a little while that Odin could be a secret weapon for game dev and similar pieces of software.

replies(1): >>36155740 #
183. eatonphil ◴[] No.36154601[source]
What's wrong with downloading the binary? curl + mv + chown should do it?
184. kprotty ◴[] No.36154682{7}[source]
Vectors in Zig are SIMD types. Vectors in games are probably algebraic types. Using SIMD for the latter may not be that useful if 1) specific elements are accessed frequently 2) transformations involve a different operation happen on each element.
185. codedokode ◴[] No.36154726[source]
I don't know anything about Zig except that it is a low-level language. Can someone please explain how it is better than Rust?
186. seba_dos1 ◴[] No.36154752{5}[source]
Python is quite often being used without pip, as the modules are often packaged by distros already (and in many distros they have to be packaged this way in order to include the application that uses them in the repos).
187. sarchertech ◴[] No.36154844{5}[source]
They’re very different languages despite having some similar capabilities.

I also found the game dev libraries in Odin far easier to use then the ones in zig.

replies(1): >>36155064 #
188. nequo ◴[] No.36154903{6}[source]
Crashing the program during runtime and having to debug it then is still a worse experience than knowing before running it that it cannot crash (due to memory errors).

This certainty comes at a cost, either by negotiating with the Rust compiler or by putting up with a GC. But depending on your calculus, that cost might be worth paying.

189. cyber_kinetist ◴[] No.36154931{7}[source]
First of all that only works with vectors, but I want operator overloading to also work on things like matrices or custom types (for example quaterions, or a symmat3 struct that represents a symmetric 3x3 matrix using only 6 floats).

Additionally, for efficient math code you often want vector / matrix types in AOSOA fasion: for example Vec3<Float8> to store an AVX lane for each X/Y/Z component. I want vector/matrix operations to work on SIMD lanes, not just for scalar types, and Zig currently can't support math operators on these kinds of types.

replies(1): >>36155544 #
190. estebank ◴[] No.36154965{5}[source]
In Rust you could use a proc macro that parsed the block and translates the token to a new token stream that uses method calls with the appropriate operator precedence, for arbitrary operations you could want to define. You're effectively writing a compiler plugin and language extension at that point. For targeted niche domains, this might be worthwhile.
191. mike_hearn ◴[] No.36155014[source]
How do you find it simpler? From taking a quick look it appears to just be an API for invoking build steps, and the build script is itself a Zig program.

I ask if it's really simple, because the JVM space went in the same direction with Gradle (build script = program) and by the time it gets more sophisticated that can turn out to be pretty painful. In particular, IDEs struggle to get the information they need, scripts can become highly complex, and there are various other problems.

replies(1): >>36156216 #
192. krupan ◴[] No.36155063[source]
Honest question here (that I have every time I see someone talk about memory safety in 2023), are you aware of Ada/Spark?
replies(1): >>36160731 #
193. mr_00ff00 ◴[] No.36155064{6}[source]
Yeah I did briefly look for zig game libraries and couldn’t find much.

I see the basic differences, but I’ll have to dig deeper.

194. jeroenhd ◴[] No.36155105{4}[source]
The problem with source tarballs is that you need to then manually watch out for updates and bugfixes for every dependency you pull in. You also need to deal with the bespoke build system of your packages of choice or manually build something compatible with your project. You can also choose not to and skip vulnerable, buggy code for a few years like some companies do, but that's hardly an advantage. You also need to ship (and possibly license) all of your dependencies.

Alternatively, you can let the system package manager do all the hard work for you. That works great, as long as you only target one OS or put in the work to maintain compatibility with multiple OS releases.

My experience with languages without package managers is that large, maintained projects all invent their own package manager (remote git repos? shell scripts downloading files? a two-stage build process written in the language itself?) in combination with some sort of Makefile generating hell script that breaks for a while when a new OS release comes out.

This approach works if you're the entire system. SerenityOS can do this, because it's basically an entire operating system and userland all inside one repository. ChromeOS can probably do it as well, since the app portion isn't running OS-native code anyway. For everyone else, it's just making someone else do the work of the package manager manually.

195. iskander ◴[] No.36155258[source]
Is there anything akin to Maturin for Zig?

I would love to use it as an extension language for Python.

196. latchkey ◴[] No.36155307{3}[source]
> I've lately thought that a package manager is as essential to a new language as a standard library.

This was the approach Ceylon took. Sadly, despite a lot of effort, the language never took off.

197. rowls66 ◴[] No.36155338{6}[source]
I guess I don't see C as programming language for writing scripts in either. In my view any language that requires a separate complication step is not a scripting language, and therefore not a language in which one writes scripts. In C or Zig you write programs.

Maybe I am just being too pedantic.

replies(3): >>36155537 #>>36159946 #>>36162472 #
198. Alifatisk ◴[] No.36155393[source]
May I ask what the hype is with Zig? What makes it so attractive?

Is it the performance? The easy interop with C? The ease of controlling the memory allocation?

199. thegeekpirate ◴[] No.36155431{5}[source]
Odin
200. pornel ◴[] No.36155497{5}[source]
Is every language supposed to come with HTTP and TLS stack, clients for every database, de/serializers for every format, every image and video codec, every de/compressor, GUI toolkits, 3D rendering, Bluetooth… where do you stop?

And then how do you maintain all of this bloat to a competitive level, so that users don't need to reach for faster/newer alternative packages anyway?

And how do you maintain portability and backward compatibility of a language with such a vast API surface?

In modern development there's just too much stuff to keep everyone happy with batteries included. Sooner or later users will need something that isn't built in, and that will cause pain and crappy workarounds if the language doesn't have first-class support for dependencies.

replies(2): >>36156115 #>>36157059 #
201. faitswulff ◴[] No.36155513[source]
My impression of the Zig language as a total outsider is that it seems like it has the underpinnings of success: it has a niche, it has a governance model, and it has real commercial users. It just has to not blunder very hard on the way to some level of promised stability.
202. eatonphil ◴[] No.36155537{7}[source]
I didn't call it a scripting language. Nor do I think C would be great to write scripts in either. :) I only said we write scripts in Zig. But if you'd like to call these files programs instead of scripts then that's ok too!
203. felixgallo ◴[] No.36155544{8}[source]
I have a marvelous proof that you can solve that with comptime but unfortunately the margins of this website are too small to contain it.
replies(3): >>36156503 #>>36161875 #>>36165689 #
204. TwentyPosts ◴[] No.36155616{6}[source]
Can't say much about async, since I really lack the experience to say whether async in Rust could feasibly and realistically be much better than it currently is. Some people say that it'd be great if it worked as effortlessly as in Go, but I assume that you don't get to have that without performance tradeoffs.

As for lifetimes, what's the issue? Do you have any reason to believe lifetimes are frustrating because they were badly designed, rather than the fact that they're making complexity explicit which was previously hidden?

205. pjmlp ◴[] No.36155619{6}[source]
It is an issue if it also allows players to work around DLC and other goodies.

Or if having the game on the system can be used by another malicious application as jumping point into root access, starting it as subprocess and injecting the exploit.

Example, Windows attacks via Notepad.

206. adastra22 ◴[] No.36155653{6}[source]
Depends on what you're doing. I'm writing a non-game app that requires a scenegraph, raycast mouse selection tool, and other tools of the sort typically required by games and provided by a game engine. But there's a lot of game stuff I don't need, and I need to make major customizations to the rendering engine. It ended up being easier to implement in bevy, due to its modularity, than it would have been in UE4 or Godot.
207. flohofwoe ◴[] No.36155740{6}[source]
I'm actually dabbling with Odin a bit in the scope of language bindings for the sokol headers:

https://github.com/floooh/sokol-odin

It's a very enjoyable language!

208. adastra22 ◴[] No.36156019{6}[source]
This is true on both fronts, I think. Bevy magics away the interface between you and the engine via the ECS macros, in a way that is very unusual for a systems programming language like Rust. But that's more or less how all game engines are these days from what I understand.
209. JohnFen ◴[] No.36156115{6}[source]
I suppose that I just never had a problem maintaining any dependencies in code I write. Package managers have long been a bit of a pain for me as a developer, and with some languages (like Python), they are a huge PITA for me as a normal user of applications.

So overall I don't view them in a very positive light. They're something I have to put up with.

No matter, it is what it is. Carry on. :)

replies(1): >>36158409 #
210. norir ◴[] No.36156120{10}[source]
Thank you. That response was clarifying. I understand now what you mean. Funnily enough though, the paper you cited begins:

"Any discussion on the foundations of computing runs into severe problems right at the start. The difficulty is that although we all use words such as ‘name’, ‘value’, ‘program’, ‘expression’ or ‘command’ which we think we understand, it often turns out on closer investigation that in point of fact we all mean different things by these words, so that communication is at best precarious."

Rather than debating the semantics of the colloquial usage of referential transparency, I'm more interested in the question: what can I tell at the call site of a function without knowing the definition of the function? In an impure language, I cannot tell whether the call has side effects without looking at the definition. This is true whether I am using a macro or simply a regular function call.

Now, even if my language of choice is impure, referential transparency of expressions is still a useful concept that can inform how I write my program. I can use naming, for example, to suggest whether a function call may have side effects even if the language compiler can't verify the property. Not perfect, but better than nothing. And if I'm really confused by a bug, I can always just assume that the name is misleading and the function may have unintentional side effects. In other words, I can use the concept of referential transparency to implement a metaprogramming system in my head.

211. whateveracct ◴[] No.36156125{11}[source]
Well it's not pointless. The term as used in FP has a pretty well-defined meaning [1] and it is a quality only some programs have. And a program having that quality enhances (fast-and-loose) equational reasoning.

[1] I can point at most Java code and prove how it fails the definition. It's not especially hand-wavey.

212. BaculumMeumEst ◴[] No.36156168{4}[source]
> I'm not so sure a package manager is really all that essential

I agree with you, but this is subjective. Not having a package manager will probably turn off many from the language. But it’s OK for the Zig folks to make a call that a lot of people won’t agree with if it doesn’t fit their vision of the language.

213. j-james ◴[] No.36156173{7}[source]
Yeah, I read through that: unless I'm missing something I think what I'm curious about is "calling C code from Zig and vice versa" in the to-be-written section.

Nim also has support for `ctypes` and compiles to C as its main target: yet though its interop is powerful it lacks in ergonomics, formerly you had to manually wrap every function you wished to use and this was only recently fixed by a macro-heavy external library.

I'm wondering what Zig does because IMO even if you have an excellent technical solution getting people to actually use it alongside C is hard, it has to be seamlessly seamless. Nim's C interop is rarely used outside of wrappers and it even more rarely is used to produce C libraries (though perhaps that's more a fault of incompatible type systems)

replies(1): >>36156461 #
214. pjmlp ◴[] No.36156216{3}[source]
Gradle is Ant reinvented, by those that didn't learn why we moved into Maven.
215. 6keZbCECT2uB ◴[] No.36156226{4}[source]
Not sure about lsp, but I think if you defined your language in tree sitter, you might be able to define a basic autoformatter generically on tree sitter to accelerate bootstrapping your language.

You could also use an existing language agnostic package manager like nix, guix, or conda to bootstrap your language package manager.

Lsp is something I don't know of a way to make that easy without overly constraining the design space.

216. ◴[] No.36156259{5}[source]
217. norir ◴[] No.36156263{4}[source]
> Zig's comptime is what's known in formal languages to be referentially transparent (it basically means that you cannot distinguish between two otherwise identical objects that differ only in their reference name) while macros are not.

In general this is true, but it is possible to write a hygienic macro engine that is referentially transparent. Many (likely most) macro engines are indeed unhygienic though. I am not convinced that comptime is a better approach than a well designed hygienic macro system but it is an interesting research area.

218. lvass ◴[] No.36156298{6}[source]
Just use C-x 8 in Emacs and you'll get any symbol by name, with autocomplete.
219. yjftsjthsd-h ◴[] No.36156300{6}[source]
Memory safety isn't just a security thing, it's also a reliability thing. That is, even if my games have zero security sensitivity I'd still like them to not crash or corrupt data.
220. TUSF ◴[] No.36156461{8}[source]
With Zig, you just write something like:

  const c = @cImport({
      @cDefine("SOME_MACRO", "1");
      @cInclude("raylib.h");
  });
Which translates the header files directly into Zig and allows you to call into them under whatever namespace you assigned them under. You even get completions (assuming you're using the language server)
replies(1): >>36159904 #
221. lvass ◴[] No.36156503{9}[source]
Do us a pastebin, please.
222. notfed ◴[] No.36156714{3}[source]
What kinds of programs don't care about memory safety?
replies(1): >>36195713 #
223. WhereIsTheTruth ◴[] No.36156718[source]
The issues I have with Zig are similar to the ones I have with Rust, the syntax.. I will never get used to it, I find it tasteless and non-ergonomic

But, I manage to set it aside because it provides enough benefits, I mainly use Zig as a toolchain to crosscompile my libraries.. and write some helper externs

Hopefully they manage to improve and ease out the syntax by 1.0, I have hopes

replies(1): >>36156761 #
224. jadodev ◴[] No.36156761[source]
Have any examples of syntax you find tasteless? Things in Zig that feel ergonomic to me: comptime params > separate generic args; ptr.* > *ptr; optional pointers > possibly null normal pointers; separate syntax for slices, arrays, & pointers > 1 syntax for ptr & arrays.
replies(1): >>36157788 #
225. lost_tourist ◴[] No.36156867{3}[source]
Why would I use zig c compiler in place of gcc or clang? Mainly for zig interactivity or does it have some advantage other than that over the aforementioned compilers?
replies(1): >>36156986 #
226. whateveracct ◴[] No.36156947{10}[source]
You can also mutate a list that is passed in and suddenly you cannot do substitution to reason about your program.
227. TUSF ◴[] No.36156986{4}[source]
Zig's C/C++ compiler is just clang, but with header files for most major platforms included, and sane defaults, so there's no hassle getting it it to cross-compile. Some companies have been using Zig solely for an easier to use clang.
replies(1): >>36157078 #
228. pdntspa ◴[] No.36157059{6}[source]
You could manage it like .net did before chocolatey/winget -- pretty much a free-for-all, just add yourself to the COM list through whatever means you want and have at it

But that was a mess. I still have nightmares from dealing with windows assembly cache issues.

Honestly it reminds me of some of the shit I've had to deal with with pip (what do you mean you can't resolve this dependency???)

229. lost_tourist ◴[] No.36157078{5}[source]
Ah I see, thanks for your answer!
230. tialaramex ◴[] No.36157133{3}[source]
This makes no sense because C89 is defined for execution on a abstract machine, something which doesn't exist and thus has no hardware.

Such beliefs are however compatible with the inveterate C programmer excuse that their nonsense programs should be correct if only the standards committee, compiler vendors, OS designers, and everybody else in the known universe were not conspiring to defeat their clear intent.

replies(1): >>36157289 #
231. bakkoting ◴[] No.36157284{5}[source]
There's a not-very-active proposal to add operator overloading to JS which takes a similar scoped approach:

https://github.com/tc39/proposal-operator-overloading

232. kps ◴[] No.36157289{4}[source]
From the C89 Rationale, “The potential for efficient code generation is one of the most important strengths of C. To help ensure that no code explosion occurs for what appears to be a very simple operation, many operations are defined to be how the target machine’s hardware does it rather than by a general abstract rule. An example of this willingness to live with what the machine does can be seen in the rules that govern the widening of char objects for use in expressions: whether the values of char objects widen to signed or unsigned quantities typically depends on which byte operation is more efficient on the target machine.”
replies(1): >>36157960 #
233. KerrAvon ◴[] No.36157461{5}[source]
Why do you think this is true of Lisps? Emmy would not seem to be a good example because it actually does overload arithmetic operators to support extended data structures. Look at, for example:

https://cljdoc.org/d/org.mentat/emmy/0.30.0/doc/data-types/m...

replies(1): >>36157586 #
234. KerrAvon ◴[] No.36157498{5}[source]
Are you sure you would find this more ergonomically pleasing:

assign(x, plus(a, plus(b, plus(c, b))))

When you could have:

x = a + b + c + d;

Or:

(let x (+ a b c d))

?

replies(1): >>36161750 #
235. erichocean ◴[] No.36157586{6}[source]
> forcing yourself to use user defined plus(a,b), minus(a,b), assign(a,b)

This is the complaint I was responding to. Here is that code in Clojure (a Lisp):

    // What the GP claims is bad for doing math:
    plus(a,b)
    minus(a,b)
    assign(a,b) // <= I have no idea what this does, or has to do with math.
    
    // Let's actually use the original math operators, but with function notation:
    +(a,b)
    -(a,b)
    
    // And here's the Clojure/Lisp syntax for the same:
    (+ a b)
    (- a b)
Lisp doesn't have "operators", so it doesn't have "operator overloading." What it does have is multi-dispatch, so yeah, the implementation of `+` can depend on the (dynamic) types of both `a` and `b`. That's a good thing, it means that the `+` and `-` tokens aren't hard-coded to whatever the language designer decided they should be in year 0, with whatever precedence and evaluation rules they picked at the time.

The point I'm making is that you absolutely DO NOT need to have special-cased, infix math operators to "do math" in a reasonable, readable way. SICP is proof, and Emmy is a breeze to work with. And it turns out, there are a lot of advantages in NOT hard-coding your infix operators and precedence rules into the syntax of the language.

replies(1): >>36158723 #
236. WhereIsTheTruth ◴[] No.36157788{3}[source]

  var t: ?i32 = null;

  if (t) {

      t +=1;

  }

This for example doesn't work, you have to capture, many little things like that that stacks up and ends up creating a non-ergonomic syntax

No for loop, so you have to do multilines things like, and now you meet a new : construct, this pseudo for loop now looks confusing to look at

  var i: i32 = 0;

  while (i < 42) : (i+=1) {

  }

Then constant casting between integers, and also floats.. also no operator overload for the math types etc..

Also not a fan of the pointer difference between [] * [:0], too much different nitpicking that makes iterating slow and painful, I understand the benefits, but the way it's done is not enjoyable, at least to me

That's just whats on the top of my head, it's been a while I haven't wrote Zig code so I may be remembering wrong

237. tialaramex ◴[] No.36157960{5}[source]
> many operations are defined

My emphasis. Undefined Behaviour is not an example of operations being defined.

238. bsder ◴[] No.36158163[source]
> My main issue with Zig is that I’m scared to invest time in writing something nontrivial to see the community/adoption flounder then regret not using Rust or C++ later

This is 100% a real concern.

If I'm going to choose Zig, it's because it is SO much better on some axis that the community/adoption isn't an issue as I gain the benefits almost immediately. That means that C++ and Rust probably aren't in the scope of choice anyway.

I especially like the comment from elsewhere in thread where they are using it for scripting, of all things, because they can pop out code that builds and works on Windows and Linux. That's a good example--you gain the benefits immediately even if you later have to unwind that to something like Python.

239. Tozen ◴[] No.36158319{3}[source]
If that's the thinking, looks like it will be a long wait. Appears to be another 2 to 3 years before 1.0 hits. And it publicly came out in 2016, so add all those years up.
240. pornel ◴[] No.36158409{7}[source]
When Python was originally designed disk space was precious, and access to the Internet was rare, and its dependency management was designed for that world. Its multiple retrofitted package managers never fully fixed it.

However, better integrated package managers can work well. In case of Node.js and Cargo, the main argument against them is that it's too easy to add dependencies.

replies(1): >>36158952 #
241. Tozen ◴[] No.36158510{4}[source]
Part of "mindshare" are organizations pushing it on social media and marketing. Choose the language that solves your problems and that you like. Don't make a choice because a group is telling you what to like, is bullying others because they like something different, or are trying to shove something down your throat for their profit or benefit. Perfectly fine to have an independent mind, and make decisions best for you.
replies(1): >>36174577 #
242. beefcafe ◴[] No.36158596{3}[source]
This is a killer feature for CTFs/OSCP/etc and why I started using it.
243. bitshiffed ◴[] No.36158610[source]
I love this part about zig too. It definitely makes interop with, or gradual migration from, C, much easier.

It's also the source of my major problem with zig. It doesn't have its own ABI [1].

So, if for example, you want to write a library in zig, to be used by others from zig, they must build your library with their project. That may not be an issue for smaller things; but for a large library I'd really like consumers to be able to pull in a binary with just a definition (header) file. Since zig uses the C ABI, that would currently mean translating everything to and from C at the binary interface, and losing all ziggyness in the process.

[1] https://github.com/ziglang/zig/issues/3786

244. xormapmap ◴[] No.36158675{4}[source]
> Agreed. Especially on a formatter. The number of code review comments it cuts out is incredibly time and energy saving.

Are people realistically reviewing code formatting? As long as people aren't making egregious violations I generally don't care if someone leaves a brace on the same line or writes a one-line if statement. I tend to review the overall design and look for bugs and edge cases that might've been missed. If somebody told me they didn't like the way I formatted the code then they've got their own editor and are welcome to change it if they want to be petty.

replies(5): >>36158750 #>>36158795 #>>36158810 #>>36159451 #>>36159851 #
245. markisus ◴[] No.36158723{7}[source]
By assign(a,b) I meant to denote the copying of the matrix b into the matrix a. The ability to use arithmetic symbols `+` and `-` as function identifiers definitely aids in readability but I don't think this is possible in Zig.

I am not familiar with Emmy but I'm guessing that the usual work flow will involve an interactive shell with many calls to `render` to display expressions in infix notation so that you can better check if the expression you typed is actually what you meant to type.

The infix notation, although arbitrary and not as logically simple as other notations, is almost universal in the math-speaking world. Most mathematicians and engineers have have years of experience staring at infix expressions on blackboards, and disseminate new knowledge using this notation, and do new calculations in this notation.

In reading your reply, I think that maybe some tooling that could auto-insert corresponding infix-like comments above an AST-like syntax could be a solution for writing such code in Zig.

246. xxpor ◴[] No.36158750{5}[source]
Absolutely. Inconsistency is sloppy, increases cognitive burden while reading code, and can hide bugs.

Everyone should take the time to setup their editor to format their code consistent with the project style, it doesn't take long at all.

247. i_am_a_peasant ◴[] No.36158754{4}[source]
I gave it a go with openGL and Rust, was great until I needed some external C++ libraries.. Then I lost motivation and rewrote the whole thing in C++
replies(1): >>36158882 #
248. throwawaymaths ◴[] No.36158795{5}[source]
Nobody is reviewing it. They are rejecting malformatted code in CI step.
replies(1): >>36160435 #
249. hyperhopper ◴[] No.36158810{5}[source]
You're looking at it the wrong way

People review code. As soon as that happens, formatting is part of the conversation. Either consciously or subconsciously

250. AndyKelley ◴[] No.36158861[source]
let me clarify some facts.

1. we never distributed debs for debian distributions. I have, however, been patiently collaborating with Debian maintainers with regards to the zig ITP: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=995670

2. we don't tell you to "just use a snap.". Please see https://github.com/ziglang/zig/#installation

3. we tag releases soon after llvm tags releases for the convenience of package maintainers. Distributions with LLVM 14 can package Zig 0.9.1; distributions with LLVM 15 can package Zig 0.10.1, etc.

251. shrimp_emoji ◴[] No.36158882{5}[source]
Name checks out

<33

replies(1): >>36159160 #
252. throwawaymaths ◴[] No.36158952{8}[source]
Fundamentally the problem with python is that it's packages are global and every workaround except ~docker can't fix it except in a hacky way since the package resolution is specified in the language
replies(1): >>36172854 #
253. i_am_a_peasant ◴[] No.36159160{6}[source]
absolutely
254. 2h ◴[] No.36159350[source]
here is this persons GitHub. posting because its missing from their blog for some reason:

https://github.com/karlseguin

255. haberman ◴[] No.36159353{4}[source]
I personally find returning a type from a comptime function to be quite elegant. Template parameters and regular parameters are unified into a single concept.

Zig's comptime is analogous to constinit, because it lets you compute a value at compile time and ensure that it is linker-initialized into the final binary image.

The point about CTRP is interesting, I'd have to think about that some more.

replies(1): >>36169935 #
256. thayne ◴[] No.36159420{3}[source]
A lot of what a package manager does isn't really language dependent. It seems like it would be possible to build a generalized package manager that has hooks for a language specific plugin to control how the package is extracted, how to resolve transitive dependencies, and how to do any additional build steps. It would be sort of analogous to how instead of building a full IDE, you can implement an LSP server and get support from existing IDEs and editors.
replies(1): >>36159838 #
257. patmorgan23 ◴[] No.36159451{5}[source]
The point of the auto formatter is to get those slight differences out of the way so your Brian can focus on parsing and understanding the important parts
258. anonymoushn ◴[] No.36159570{4}[source]
You can use = for structs at least :)
259. throwawaymaths ◴[] No.36159575{5}[source]
Sure, but people are going to want to use operator overloading for, e.g. dl/ml
260. throwaway2037 ◴[] No.36159799[source]

    I think Zig falls into an "easy to learn, average/hard to master"
Thank you for sharing an insider's account. I naively assume that Zig is not your first language. Regarding "average/hard to master", can you think of any of languages where this is not true? Zero trolling, I promise. My point: No language is any less than average to master. Even VBA has some weird stuff in it that used to catch me off guard when I wrote Excel apps years ago. To be clear, I would classify VBA as similar, but I would classify Python as "easy to learn, very hard to master", and Perl as "average to learn, impossible to master"(!).
261. throwaway2037 ◴[] No.36159838{4}[source]
High level: I appreciate the point being made here. Challenge: If true, why does it not already exist? Idea: Apache Maven repositories use pom.xml to define dependency trees. Why don't these get used more for non-Java'ish languages? Mind you, I am not advocating to use Apache Maven as a build tool. I am noting that (remote) repos and their dependency metadata are a huge achievement in that ecosystem.
replies(1): >>36160335 #
262. brundolf ◴[] No.36159851{5}[source]
In addition to reviews, I've started to really enjoy format-on-save as a way to save keystrokes. Instead of manually formatting my code (even for myself), I can take the shortest editor path to the AST that I want and then have everything else snap into place
263. j-james ◴[] No.36159904{9}[source]
Right, but I'm curious about the calling-Zig-from-C interop, not the other way around.
replies(1): >>36196814 #
264. Kamq ◴[] No.36159946{7}[source]
A number of languages that would have been traditionally compiled (statically typed, produce a native binary by default, etc), have started adding a "run" command.

If your language compiles fast enough, it's about the same experience as running a python script.

265. chlorion ◴[] No.36160066{5}[source]
>That's some spooky action at a distance nonsense.

In pretty much all languages operators are just sugar for calling a method. There is no difference other than an easier to read syntax.

In rust for example, doing a + b is exactly the same as doing a.add(b).

In python it's exactly the same as doing a.__add__(b).

In C++, my understanding is that its sugar for a.operator+(b) or operator+(a, b).

I think there are some arguments against operator overloading but "spooky action at a distance" doesn't seem to be a very good one to me.

266. thayne ◴[] No.36160335{5}[source]
> If true, why does it not already exist?

Because no has put in the effort to build it and get it adopted. You could also ask why we didn't have something like LSP earlier. In order for such a project to become widely adopted it would need to work well for at least a few popular languages, and work at least approximately as well as the native package management solutions for those languages. And it would need to be easy to use. You can kind of use some existing tools, such as maven, bazel, even npm, for other languages, but it usually isn't as nice of an experience.

267. nickcox ◴[] No.36160435{6}[source]
That's not the workflow your GP is describing.
268. Gigachad ◴[] No.36160731{3}[source]
If Ada and Spark solve problems as well or better than Rust and have been around for longer, why have I never seen any program written in them?

I don’t know anything about ada/spark but it seems clear that something has gone terribly wrong for them to not have taken off like Rust has.

replies(1): >>36183051 #
269. Gigachad ◴[] No.36160740{3}[source]
If you are going to leave C, why take a half step when you could go the full way and end up with the better tool.
270. QQ00 ◴[] No.36161190{7}[source]
how your experience with Odin so far? How Odin differ from Zig in your opinion? What you likes/dislikes compared to Zig or other languages?
replies(1): >>36162056 #
271. QQ00 ◴[] No.36161441{3}[source]
>and adding features to solve all of them will make the language much bigger, overall causing greater harm (even those who don't themselves use the feature need to learn it to be able to read code).

I agree that adding too many features can make a language too large and bloated. However, I disagree that this is always the case. For example, adding features that make it easier to code math is not necessarily a bad thing. In fact, it is a good thing, as it can make programming more accessible to a wider range of people.

Additionally, math is often used in fields that require high speed, such as computer graphics and game development, Computer vision, Robotics, Machine learning, Natural language processing (NLP), Mathematical modeling, all kinds of scientific computing (Computational physics, Computational chemistry, Computational biology...) As a result, low-level programming languages are often used to implement the core code in these fields. As you see, Math is essential for many fields.

272. ◴[] No.36161455{4}[source]
273. ◴[] No.36161478{4}[source]
274. chrsig ◴[] No.36161750{6}[source]
is assign(x, plus(a, b, c, d)) not an option?
275. QQ00 ◴[] No.36161875{9}[source]
You can use pastebin, or even better, use github gist.
276. uranusjr ◴[] No.36161988{5}[source]
Furthermore, having a package manager indicates there are some kind of specifications behind so each package and repository has an expected format (not necessarily _a_ standard package manager; in many ecosystems multiple managers share one standard). This helps vendoring a lot since the standard specification makes the vendoring process very easy to automate and validate. Dependency managers in their essence is really just automated vendoring (or vendoring is just less automated dependency management); it helps because you can pick it apart and choose to automate only the parts you want, even if you don’t like the fully automated solution.
277. 59nadir ◴[] No.36162056{8}[source]
I think Odin is terrifically designed overall. There are design choices that I was initially very skeptical about but when I decided to use the language they actually made a lot of sense.

Some overall differences between Odin and Zig and how I relate to them are:

## Exhaustive field setting

Zig requires you to set every field in a struct. Everything everywhere has to be initialized to something, even if it's `undefined` (which means it's the same thing as missing initialization in C, etc.).

Odin instead takes the position that everything is zero-initialized by default. It then also takes the position that everything has a zero value and that zero value is a valid value to have. The libraries think so, the users of the language think so and what you get when everything works like this is code that overwhelmingly talks exactly only about the things that need talking about, i.e. we only set the fields right now that matter.

Exhaustive field setting does remove uncertainty and I was very skeptical about just leaving things to zero-initialization, but overall I would say I prefer it. It really does work out most of the time and I've had plenty of bugs in Zig caused by setting something to `undefined` and just moving on, so it's not really as if that exhaustiveness check for fields was some 100% solution.

## An implicit context vs. explicit parameters

Zig is more or less known for using parameters to pass around allocators, and so on. It's not a new concept in most lower-level languages but it's one of the first languages to be known for baking this into the core community and libraries.

Odin does the same thing except it uses an implicit parameter in all Odin functions that is called `context`. When you want to change the allocator for a scope, you only need to set `context.allocator` (or `context.temp_allocator`) and every function you call in that scope will use that allocator. We can also write functions that take an optional parameter that defaults to the current allocator:

    join :: proc(
      a: []string,
      sep: string,
      allocator := context.allocator,
    ) -> (
      res: string,
      err: mem.Allocator_Error,
    ) {
    }
This way we get the same behavior and flexibility of talking about allocators but we can also default to either the basic default or whatever the user currently has in scope. We *can* also be more explicit if we want. The ability to have this implicit again makes it so we only need to talk about the things that are special in the code.

The context is also used for logger information, by the way, and you also have a `user_data` field that can be used to hold other stuff but I haven't really needed it for anything so far.

## Error information

Zig is known for its error unions, i.e. a set of error codes that can be inferred and returned from a function based on the functions it calls. These are nice and undoubtedly error handling in Zig is very neat because of it. However, there is a major downside: You can't actually attach a payload to these errors, so these are just tags that you propagate upwards. Not a huge deal but it is annoying; you'll have to have a parameter that you fill in when an error has occurred and you need more info:

    // `expect_error` here is only filled in with something if we have an error
    pub fn expect(self: *Self, expected_token: TokenTag, expect_error: *ExpectError) !Token {
    }
Odin instead has a system that works much the same, we can return early by using what is effectively the same as `try` in Zig: `or_return`. This will check the last value in the return type of the called function to see if it's an error value and return that error value if it is.

The error values that we talk about in Odin are just its normal values and can be tagged unions if we so choose. If we have the following Zig definitions for the `ExpectError` example:

    pub const ExpectTokenError = struct {
        expectation: TokenTag,
        got: Token,
        location: utilities.Location,
    };
    
    pub const ExpectOneOfError = struct {
        expectations: []const TokenTag,
        got: Token,
        location: utilities.Location,
    };
    
    pub const ExpectError = union(enum) {
        token: ExpectTokenError,
        one_of: ExpectOneOfError,
    };
We could represent them as follows and just use them as the error return value without holding a slot as a parameter that we will fill in:

    ExpectTokenError :: struct {
      expectation: TokenTag,
      got: Token,
      location: Location,
    }
    
    ExpectOneOfError :: struct {
      expectations: []TokenTag,
      got: Token,
      location: Location,
    }
    
    ExpectError :: union {
      ExpectTokenError,
      ExpectOneOfError,
    }
    
    expect_token :: proc(iterator: ^TokenIterator, expected_token: TokenTag) ->
        (token: Token, error: ExpectError) {
    }
They are normal tagged unions and in contrast to Haskell/Rust unions we don't have to bother with having different constructors for these just because a type is part of several different unions either, which is a big plus. We still get exhaustiveness checks, something akin to pattern matching with `switch tag in value { ... }`[0] and so on. Checking for a certain type in a union also is consistent across every union that contains that type, which is actually surprisingly impactful in terms of design, IMO.

## Vectors are special

This isn't going to have a Zig equivalent because, well, Zig just doesn't.

Odin has certain names for the first, second, third, etc., positions in arrays. This is because it's specifically tailored to programmers that might deal with vectors. It also has vector and matrix arithmetic built in (yes, there is a matrix type).

    array_long := [?]f32{1, 2, 3, 4, 5}
    array_short := [?]f32{0, 1, 2}

    fmt.printf("xyzw: %v\n", array_long.xyzw)
    fmt.printf("rgba: %v\n", array_long.rgba)
    fmt.printf("xyz * 2: %v\n", array_long.xyz * 2)
    fmt.printf("zyx + 1: %v\n", array_long.zyx + 1)
    fmt.printf("zyx + short_array: %v\n", array_long.zyx + array_short)
This gives the following output:

    > odin run swizzling
    xyzw: [1.000, 2.000, 3.000, 4.000]
    rgba: [1.000, 2.000, 3.000, 4.000]
    xyz * 2: [2.000, 4.000, 6.000]
    zyx + 1: [4.000, 3.000, 2.000]
    zyx + short_array: [3.000, 3.000, 3.000]
It seems like a small thing but I would say that this has actually made a fair amount of my code easier to understand and write because I get to at least signal what things are.

## Bad experiences

### Debug info

The debug information is not always complete. I found a hole in it last week. It's been patched now, which is nice, but it was basically a missing piece of debug info that would've made it so that you couldn't know whether you had a bug or the debug info was just not there. That makes it so you can't trust the debugger. I would say overall, though, that the debug info situation seems much improved in comparison to 2022 when apparently it was much less complete (DWARF info, that is, PDB info seems to have been much better overall, historically).

0 - https://odin-lang.org/docs/overview/#type-switch-statement

replies(2): >>36163988 #>>36238976 #
278. erhaetherth ◴[] No.36162070[source]
> easy things seem easy primarily because they are familiar

This is also why I struggle to answer the question "is it hard". Is it hard to build a web-app? No. But I've been building web-apps for 20 years. Will you find it hard (if you've never programmed before)? I don't know, if you want to build one this weekend, sure. If you have the patience to spend a few years learning first, then no.

279. erhaetherth ◴[] No.36162085{5}[source]
I think JS was somehow salvaged after all that time. The event loop paradigm is lovely.
280. erhaetherth ◴[] No.36162098{4}[source]
Makes me so sad that I can't just code up a parser and have a useable language. I have a lot of ideas, but heck, just syntax highlighting is... I don't know where to begin. And auto-completions. I need a tool that does 90% of that like PegJS or other parser-generators do for the parsing part. Don't see why a parser-generator can't also spit out an LSP. And if it knows what tokens are valid next, it should be able to generate completion suggestions. And if you have an AST, you can probably format the code half decently. And then I imagine it's possible to have a semi-universal package manager, I don't know why we need one per language, really. Aren't they all "put some code in some predefined location, and resolve these dependencies with semver please"? Maybe some extra junk for precompiled deps but still.
replies(1): >>36175430 #
281. 59nadir ◴[] No.36162472{7}[source]
I think the idea here is that "small programs" = "scripts". Modern lower level languages are mostly terrific for writing small programs, which obviates the need for scripting languages.
282. ◴[] No.36162805{6}[source]
283. QQ00 ◴[] No.36163988{9}[source]
Thank you so much. It look like Odin is really a beautiful language to program with.

Did you encounter memory bugs? Essentially what memory safety feature Odin offer? (From what I read here, Zig and Rust offer some features to eliminate entire classes of bugs which remove the nightmare of hours of debugging)

Anything you dislike or wish Odin has that other languages offer?

>that the debug info situation seems much improved in comparison to 2022 when apparently it was much less complete (DWARF info, that is, PDB info seems to have been much better overall, historically).

I believe Odin was developed on windows and other system come later, probably that why PDB is much better.

replies(1): >>36167353 #
284. sskras ◴[] No.36165230{3}[source]
If you learning by doing, I would add these to the @hiccuphippo links:

https://zigbyexample.github.io/

https://zig-by-example.com/

Their coverage is not very broad (in comparison to eg. Go by Example), but might be enough to get yourself started.

285. another2another ◴[] No.36165689{9}[source]
I think you have briefly deluded yourself with an irretrievable idea.
286. 59nadir ◴[] No.36167353{10}[source]
> Did you encounter memory bugs? Essentially what memory safety feature Odin offer? (From what I read here, Zig and Rust offer some features to eliminate entire classes of bugs which remove the nightmare of hours of debugging)

Odin is essentially in the same ballpark as Zig in terms of general safety features. Slices make dealing with blocks of things very easy in comparison to C, etc., and this helps a lot. Custom allocators make it easy to segment your memory usage up in scopes and that's basically how I deal with most things; you very rarely should be thinking about individual allocations in Odin, in my opinion.

> Anything you dislike or wish Odin has that other languages offer?

I would say that in general you have to be at least somewhat concerned with potential compiler bugs in certain languages and Odin would be one of them. That's not to say that I've stumbled on any interesting compiler bugs yet, but the fact that they very likely do exist because the compiler is a lot younger than `clang` or `gcc` makes it something that just exists in the background. Multiply that by some variable amount when something is more experimental or less tried and true. The obvious example there is the aforementioned debug info where on Linux this has been tried less so it is more likely to be worse, and so on.

In an ideal (fantasy) world I'd love something like type classes (from Haskell) in Odin; constraints on generic types that allow you to write code that can only do exactly the things expressed by those constraints. This gives you the capability to write code that is exactly as generic as it can logically be but no more and no less. Traits in Rust are the same thing. With that said, I don't believe that neither Haskell nor Rust implements them in a way that doesn't ruin compile time. Specialization of type classes is an optimization pass that basically has to exist and even just the fact that you have to search all your compiled code for an instance of a type class is probably prohibitively costly. It's very nice for expression but unless Odin could add them in a way that was better than Haskell/Rust I don't think it's worth having.

I would like to see how uniform function call syntax would work in Odin but this is actually addressed in the FAQ here: https://odin-lang.org/docs/faq/#why-does-odin-not-have-unifo...

UFCS works really well in D but D also has ad-hoc function overloading whereas Odin has proc groups. I think UFCS only really works with exceptions as well, so I think it can become awkward really fast with the amount of places you want to return multiple values where your last one represents a possible error.

287. Conscat ◴[] No.36169935{5}[source]
I would consider that similar to a `inline constexpr` variable rather than a `constinit` variable. A `constinit` variable calls a constexpr constructor, but doesn't produce a constant.

EDIT: Oh, I think I see how it's like `constinit`. If you have a non-`comptime` variable that is initialized by a `comptime` function, then it's a non-constant constant-initialized variable.

288. zaphirplane ◴[] No.36172854{9}[source]
Tell us more, cause it’s not a problem I know
replies(1): >>36174462 #
289. zaphirplane ◴[] No.36172876{4}[source]
So you manually do what a package manager would do automagically and better. What do you think you are doing that is better than a program resolving dependencies, downloading h them and building them, putting them in the right location and tracking the versions used in a lock file
290. throwawaymaths ◴[] No.36174462{10}[source]
Try installing two pieces of software that depend on two different versions of tensorflow, then come back here.
replies(1): >>36175085 #
291. truckerbill ◴[] No.36174577{5}[source]
Yes I definitely agree with that sentiment. Some things unfortunately happen faster with community support. Platform integrations, toolchains etc that require a lot of busywork. But I think I'll cautiously move with Odin regardless as I like how it's designed. Probably will end up learning both.
replies(1): >>36174997 #
292. 59nadir ◴[] No.36174997{6}[source]
I think this is a great idea. I would suggest joining the Discord server if you want to talk to like-minded people and immerse yourself in the language: https://odin-lang.org/community/discord/
293. zaphirplane ◴[] No.36175085{11}[source]
I can install multiple python interpreters side by side each with independent packages and I can install different versions of the same python package for the same interpreter. I haven’t tried or had a need, by induction sounds possible :shrug:
replies(1): >>36190287 #
294. aldanor ◴[] No.36175430{5}[source]
Because LSP is not just "give me some semi-decent completions based on parsing tokens in this file". Proper LSP will treat code semantically, in case of e.g. Rust it may complete a method name from a trait method because you have the trait somewhere in scope, which comes from a third-party package which the LSP also parses, where it needs to expand some procedural macros to get to source code, etc etc.

We've been spoiled by good LSPs, perhaps. But again, it's not just "parse this file please".

295. nextaccountic ◴[] No.36176465{6}[source]
Zig gamedev libraries aren't either
296. cztomsik ◴[] No.36178599[source]
In my case, Zig was super-simple to pickup, I've been using rust for few years so I was already in the systems programming (as a hobby), and I also had to read some C/C++ during that time, that probably helped me too.

Other than that, I was and I am, mostly a frontend developer with ECMAScript and TypeScript experience. I think Zig is very close to both, because Zig has anytype, so you can do duck-typing like you do in JS, and it has programmable type system, just like TS. Not to mention that reflection is basically your daily bread in JS/TS.

TLDR: If you have some systems programming experience and you've done a bit of TS, I'd definitely recommend you to give Zig a try. One weekend should be enough. I did that literally single-handed, as I was recovering after wrist surgery.

297. krupan ◴[] No.36183051{4}[source]
That doesn't answer my question.

To attempt to answer your question, you might be surprised to learn just how much Ada/spark exists in the world if you go looking. Most of it is not open source. I'm not sure they haven't "taken off like Rust has" because Rust is still very niche, kinda like Ada is

298. Tiberium ◴[] No.36183376{4}[source]
This is not actually true for Nim - almost all Nim Discord channels are bridged to different IRC channels, see https://github.com/nim-lang/Nim/wiki#bridged-real-time-chats
replies(1): >>36192798 #
299. TDiblik ◴[] No.36184449{3}[source]
Hi, why is this feature interesting/important? (Coming from [uneducated] webdeveloper with interest for systems/embedded programming)
300. throwawaymaths ◴[] No.36190287{12}[source]
Tensorflow wheels are bound to cuda installation which is driver/sudo level. It's a nightmare.
301. girvo ◴[] No.36192798{5}[source]
Oh that's nice, I thought the IRC bridge had been left to languish. Good to know I was wrong!
302. nyberg ◴[] No.36195713{4}[source]
Compiler enforced memory safety*. Games in particular tend to have their own allocators and memory management schemes which don't play well with global allocators. Using memory pools, frame (arena) allocators, system specific memory management, and so on. Handling memory in a very systematic way (avoiding the "malloc everywhere" anti-pattern) where ownership is clearly tied to systems and handles (integers (maybe with metadata)) passed instead of pointers helps keep this all sane. That and you can still throw a GC/Ref counting at things which have non-linear lifetimes if needed but there's no need to do so globally.

One-shot programs also don't always need it as they're often fine with a less sophisticated scheme of arena allocation or reusing memory by resetting temporary buffers.

You also have the option to classify pointers if you absolutely must pass them with similar techniques as https://dinfuehr.github.io/blog/a-first-look-into-zgc.

303. kmz42 ◴[] No.36196814{10}[source]
I was curious as well so I made a simple example to see how easy it is[0]

The documentation, especially for the build system, was lacking. But the interop itself is pretty smooth. Only rough point is that I can't define a struct type in Zig and use it in C; you HAVE to define your structs in C if you plan to pass them between the languages (as far as I know anyways).

Zig has documentation on making your Zig structs match the layout of C structs[1] so I assume the intended use case is not as I have done (use the C type in Zig) but instead of define a matching Zig type and cast your C structs into Zig structs, or vice versa, at the boundary between languages.

Structs aside, for functions you just stick "export" on the Zig functions to make them available at link time (presumably) and use "callconv(.C)" so C can call them cleanly. Very easy.

[0] https://github.com/kmz42/zig_c_interop_test

[1] https://ziglearn.org/chapter-4/#extern-structs

304. Tozen ◴[] No.36238976{9}[source]
> Odin instead takes the position that everything is zero-initialized by default...

> Exhaustive field setting does remove uncertainty and I was very skeptical about just leaving things to zero-initialization, but overall I would say I prefer it. It really does work out most of the time...

Vlang does this as well (also influenced by Wirth/Pascal/Oberon/Go). Overall, this is an advantage and greater convenience for users.