Live data from Hacker News

Failing to Learn Zig via Advent of Code

forrestthewoods.com

281–290 of 338 posts

Re: Failing to Learn Zig via Advent of Code

#281
post #171

Earlier quoted context omitted.

It's an open question [1] along with other safety checks both comptime and runtime [2]. The issue here is a balance of keeping language complexity low while providing safety at the same time and not depriving users of control when they know better than the type checker/lifetime analysis. [1]: https://github.com/ziglang/zig/issues/782 [2]: https://github.com/ziglang/zig/issues/2301

This is such a squishy value proposition, which is why people aren't taking Zig seriously. Rust's value proposition is simple: no GC and no undefined behavior. Period. Nothing else has that.

Rust has plenty of undefined behavior: https://doc.rust-lang.org/reference/behavior-considered-unde...

Re: Failing to Learn Zig via Advent of Code

#282

Earlier quoted context omitted.

I feel like Nim is a much closer comparison than Rust. All three could be described as "grassroots projects on a holy mission to replace C and/or C++," but Nim and Zig are more similar in terms of operating budget/team size/adoption rate. I may be a bit biased, but many of the problems mentioned in the post are the sorts of things I haven't dealt with in Nim for probably 2 years. Nim's error messages are still hit-or…

Rust isn't on a holy mission; it's simply the only memory-safe language without a garbage collector. It's really that simple. There is no international conspiracy behind Rust's popularity. It's the only thing that can do what it does in that respect.

Depends, I consider that Rust might succeed where Modula-2, Object Pascal and Ada failed, for anything else other than being a new generation of developers having a go at it.

Re: Failing to Learn Zig via Advent of Code

#283

Earlier quoted context omitted.

There is nothing fundamental about ownership-based resource management, memory-safety can be achieved in other ways. Zig is C, it's not meant to abstract away memory management. You can do whatever in Zig, write a specialized allocator that's verified to be correct, even for a microcontroller with 2 KiB memory. Zig is a machine-oriented language, which means no hidden control flow, no hidden allocation. You can write…

> nothing fundamental about ownership-based resource management, memory-safety can be achieved in other ways. Not other way s . One other way. Just one. Garbage collection.

You're mistaken.

https://en.wikipedia.org/wiki/Memory_safety#Approaches

Re: Failing to Learn Zig via Advent of Code

#284
post #259

Earlier quoted context omitted.

I still can't figure out how Zig proposes to prevent undefined behavior without a borrow checker (aka MLKit regions) or GC. AFAICT the answer is "inject as many runtime checks as needed" although the docs seem to go way out of their way to avoid making this explicit.... or deal with the fact that these checks are now runtime failures rather than compile-time failures, and therefore need code to handle them. It seems…

Zig doesn't propose to prevent UB (in fact the docs say that it takes aggressive advantage of it for optimization). (Neither does Rust.)

safe Rust doesn't have any Undefined Behaviour.

Your unsafe Rust is supposed to provide suitable constraint/ guarantees that you, the programmer, conclude it does not have any Undefined Behaviour. The language can't force you to do this, and at some point it becomes a social contract not a programming language feature.

I wrote the misfortunate crate to explore Rust's promise here. The crate provides legal but obviously inappropriate implementations of lots of safe Rust traits, and sure enough nothing blows up, there is no undefined behaviour.

The defined behaviour can be undesirable for example if you insist on putting a bunch of misfortunate::Maxwells in a HashSet you're going to have a bad time. Rust doesn't promise this is a good idea, it might cause infinite loops, memory leaks, all sorts of defined trouble, but it won't be Undefined Behaviour.

Re: Failing to Learn Zig via Advent of Code

#285
post #259

Earlier quoted context omitted.

Zig doesn't propose to prevent UB (in fact the docs say that it takes aggressive advantage of it for optimization). (Neither does Rust.)

safe Rust doesn't have any Undefined Behaviour. Your unsafe Rust is supposed to provide suitable constraint/ guarantees that you, the programmer, conclude it does not have any Undefined Behaviour. The language can't force you to do this, and at some point it becomes a social contract not a programming language feature. I wrote the misfortunate crate to explore Rust's promise here. The crate provides legal but obvious…

Not "you, the programmer", any programmer. The Rust standard library can and sometimes does have UB, and that's even more true for other libraries.

Re: Failing to Learn Zig via Advent of Code

#286
post #279
post #251

Earlier quoted context omitted.

Rust's purpose, its whole reason to exist, is to displace C. Rust will unavoidably fail in that, because anybody still using C is not willing to learn anything else: anybody willing to move on from C already did, long ago. Rust is already approaching C++ in complexity, surpassing it in some places; and also in expressive power, but not surpassing it anywhere yet. If Rust does not end up fizzling (which is still very…

Even if the only success story for Rust would be mainstream adoption of lifetime checkers across languages to some extent, that would already be a victory as it managed to change the baseline of language design across the industry. A subject that now has become even regular presence at C++ conferences and considered a must have in static analysers roadmap by all major vendors. Rust might fizzle out in a decade, and s…

I have not heard of a lifetime checker in any other language, except maybe Midori.

Re: Failing to Learn Zig via Advent of Code

#288
post #133

Earlier quoted context omitted.

> `a+b` will have the same value as `b+a` No, as IEEE754 doesn't even guarantee that `a + b` == `a + b`. You always need to compare the absolute difference of two values against an ε. So a == b |a - b| But for sensible comparison of floats, the addition is commutative.

> No, as IEEE754 doesn't even guarantee that `a + b` == `a + b` What? I'm pretty sure that is plain incorrect. Can you back that claim up with references?

The rounding can depend 'where' (e.g. the width of the register) the float is stored in the CPU ('destination' in IEEE 754 speak). So, if you compare the result stored in two different 'destinations' (because one has been computed in another register or at a GPU or ....), they can differ even in the same program with the same optimizations.

See for example:

   int main() {
       double  q;

       q = 3.0/7.0;
       if (q == 3.0/7.0) printf("Equal\n");
       else printf("Not Equal\n");
       return 0;
   }

   On an extended-based system, even though the expression 3.0/7.0 has 
   type double, the quotient will be computed in a register in extended 
   double format, and thus in the default mode, it will be rounded to 
   extended double precision. When the resulting value is assigned to the 
   variable q, however, it may then be stored in memory, and since q is 
   declared double, the value will be rounded to double precision. In the 
   next line, the expression 3.0/7.0 may again be evaluated in extended 
   precision yielding a result that differs from the double precision 
   value stored in q, causing the program to print "Not Equal". Of course, 
   other outcomes are possible, too: the compiler could decide to store 
   and thus round the value of the expression 3.0/7.0 in the second line 
   before comparing it with q, or it could keep q in a register in 
   extended precision without storing it. An optimizing compiler might 
   evaluate the expression 3.0/7.0 at compile time, perhaps in double 
   precision or perhaps in extended double precision. (With one x86 
   compiler, the program prints "Equal" when compiled with optimization 
   and "Not Equal" when compiled for debugging.) Finally, some compilers 
   for extended-based systems automatically change the rounding precision 
   mode to cause operations producing results in registers to round those 
   results to single or double precision, albeit possibly with a wider 
   range. Thus, on these systems, we can't predict the behavior of the 
   program simply by reading its source code and applying a basic 
   understanding of IEEE 754 arithmetic. 
The relevant conclusion:

   Neither can we accuse the hardware or the compiler of failing to 
   provide an IEEE 754 compliant environment; the hardware has delivered a correctly rounded result to 
   each destination, as it is required to do, and the compiler has 
   assigned some intermediate results to destinations that are beyond the 
   user's control, as it is allowed to do.
https://grouper.ieee.org/groups/msc/ANSI_IEEE-Std-754-2019/b...

Re: Failing to Learn Zig via Advent of Code

#289
post #253

Earlier quoted context omitted.

I still can't figure out how Zig proposes to prevent undefined behavior without a borrow checker (aka MLKit regions) or GC. AFAICT the answer is "inject as many runtime checks as needed" although the docs seem to go way out of their way to avoid making this explicit.... or deal with the fact that these checks are now runtime failures rather than compile-time failures, and therefore need code to handle them. It seems…

You're conflating undefined behavior with spatial/temporal memory safety, the latter of which is what is 100% prevented by Rust's borrow checker, provided you're not interfacing with hardware, in which case I believe that things change more in binary fashion. However, Zig treats memory safety not as an extreme-at-all-costs but as a spectrum (there are reasons for wanting to think like this, at least when writing low-…

If dealing with potentially hostile data, Zig certainly isn't more appropriate than Rust in my opinion, try maybe WUFFS.

Suppose we have been given a 32KB data structure with some "step" bytes - in a conforming input these should always sum to less then 32768 and thus the total will easily fit in a 16-bit unsigned integer, so that's what our naive program does. Unfortunately attackers provided a structure whose step bytes sum to more than 65535...

Zig will panic here if using default arithmetic with default release builds. If the attacker wanted to cause a Denial of Service, job done already.

Rust will panic if explicitly told to enable checked arithmetic on release but it also provides explicit checked, wrapping, saturating and so on variants of the arithmetic operators if you want them for this part of your software (perhaps anticipating the risk) you can just have that without touching the behaviour of all other arithmetic in the program. 65530u16.checked_add(255u16) is None even in a default release build of Rust, what you do with that None (silently abandon this input? log the error?) is up to you and of course may not be adequately tested.

However, in WUFFS we simply can't write the erroneous program. It doesn't compile because WUFFS can't see why it's safe. Because it isn't safe. WUFFS requires the programmer to spell out what's going on, and so either you have to realise what might happen ("Oh, it can overflow, I should handle that") or choose a strategy that can't suffer the problem, ("Let's not sum up those steps, I see a different way to handle valid input").

Re: Failing to Learn Zig via Advent of Code

#290
post #286
post #279

Earlier quoted context omitted.

Even if the only success story for Rust would be mainstream adoption of lifetime checkers across languages to some extent, that would already be a victory as it managed to change the baseline of language design across the industry. A subject that now has become even regular presence at C++ conferences and considered a must have in static analysers roadmap by all major vendors. Rust might fizzle out in a decade, and s…

I have not heard of a lifetime checker in any other language, except maybe Midori.

So here is a sample,

Chapel, HPC language mostly sponsored by Intel and HPC

https://chapel-lang.org/

D programming language,

https://dlang.org/blog/2019/07/15/ownership-and-borrowing-in...

Ada/SPARK,

https://docs.adacore.com/spark2014-docs/html/ug/en/source/la...

Swift,

https://github.com/apple/swift/blob/main/docs/OwnershipManif...

ParaSail

http://www.parasail-lang.org/

Project Verona from Microsoft Research

https://www.microsoft.com/en-us/research/project/project-ver...

Project Snowflake from Microsoft Research

https://www.microsoft.com/en-us/research/publication/project...

And finally your favourite C++

"Implementing the C++ Core Guidelines’ Lifetime Safety Profile in Clang"

https://llvm.org/devmtg/2019-04/slides/TechTalk-Horvath-Impl...

Also the "Clang Static Analyzer - A Tryst with Smart Pointers" talk at 2021 LLVM Developers Meeting.

For the Visual C++ part of the story

https://devblogs.microsoft.com/cppblog/lifetime-profile-upda...

And GCC as well, although they are late to the party

https://gcc.gnu.org/wiki/DavidMalcolm/StaticAnalyzer

Finally a couple of CppCon 2021 talks that touch on the subject in various ways,

Type-and-resource safety in modern C++

Code Analysis++

Static Analysis and Program Safety in C++: Making it Real

Finding Bugs Using Path-Sensitive Static Analysis

Post reply on HN