Hacker News new | past | comments | ask | show | jobs | submit login

Rust has a concept of null, though there are way more nulls in regular Java code than in regular Rust code: https://doc.rust-lang.org/std/ptr/fn.null.html. If the issue is representing non-existence, Kotlin, C# and TypeScript (configured properly) all have nullable types. There's a good chance you'll be more productive with those instead of Rust for regular backends. Of course using Rust still makes sense when you need great performance and/or great safety for a specific service.



> Rust has a concept of null, though there are way more nulls in regular Java code than in regular Rust code: https://doc.rust-lang.org/std/ptr/fn.null.html.

I've used Rust for about 6 years now, and I don't think I've ever used ptr::null(), mainly because I don't really write low-level wrappers around C libraries. I'd argue Rust does not have null as a concept or language feature - ptr::null() is just a convenience function for creating a pointer with the value of zero. The point of not having null is that in most languages null can appear basically in any variable or value, while in Rust null pointers can only exist when writing very low level potentially memory unsafe code.

> If the issue is representing non-existence, Kotlin, C# and TypeScript (configured properly) all have nullable types.

They do indeed have nullable types, but at least in in C# and TypeScript (and probably in Kotlin because of JVM interop) non-nullability is basically a lint with zero runtime guarantees. That is often good enough, but it's still a far cry from an absolute 100% percent guarantee provided by not having nulls even as a concept. Having nulls is a problem you can't fix by adding features - you have to design the language and/or the runtime from scratch without them.

> There's a good chance you'll be more productive with those instead of Rust for regular backends

I'm not arguing against the productivity of these languages or demanding anyone writes anything in Rust. I mostly write TypeScript in my day job, and it is a practical and productive choice for the work we do (web frontends, backends and serverless services). I just want to inform people about the capabilities of Rust and correct misunderstandings.


> non-nullability is basically a lint with zero runtime guarantees

Heh? What else is it in Rust or any other language? Like, the only way I could imagine a null pointer exception leak into C#/JVM-language program that got statically analysed to not contain null is through some Reflection-based unsafe operation - at which point we can also talk about unsafe operations in Rust that just as well can cause “null-pointer exceptions”, except those will be hard memory failings (undefined behavior basically), potentially corrupting the whole execution.


In C# you can explicitly, in the language, basically say "Don't worry this won't be null" and the compiler takes your word for it and lets you do stuff that definitely isn't OK if it's null.

The language has to do this for two reasons. Firstly, this is a retro-fit, so if you don't have this you need to throw away all the old C# code, why not call the new language something else ? Secondly though, and perhaps more important to the C# ethos is you must allow null everywhere to be compatible with the Common Language Runtime. C# has to accept anything the CLR does at any function boundary. This means what can be promised is the lowest common denominator of all CLR languages which exist or are going to exist.

Suppose your C# code checks a string value called username is actually some string, by calling IsNullOrEmpty(). It'd be annoying if after doing that C# just insists username might be null anyway - you just checked! So, that function marks the string reference you called it on as definitely-not-null after having checked. However, you can just make a new function LOLWhatIsSafety() which just always returns 69 and marks the reference as definitely-not-null. In both cases the compiler just takes their work for it.


> In C# you can explicitly, in the language, basically say "Don't worry this won't be null" and the compiler takes your word for it and lets you do stuff that definitely isn't OK if it's null.

You can do this in Rust too. Unsafe Rust is still Rust.


You can, although they're pretty keen on discouraging you from pointing this particular gun at your feet, e.g. ptr.with_addr() can't achieve this on its own because it wants a NonZeroUsize, so first you need to make a NonZeroUsize that's actually zero. But yes, you can write that in unsafe Rust and now your program has Undefined Behaviour.

In contrast all the routes I suggested for C# aren't unsafe, aren't even flagged as "Be super careful here, dragons ahead" because the C# attitude is that every single C# function is responsible for explicitly doing its own null checks if they're needed.


You're right, idiomatic C# will have usually way more nulls than idiomatic Rust.


C#'s null safety is not sound. There are situations where even a fully annotated program without reflection, code generation, unsafe or other tricks will crash of a null pointer exception:

https://docs.microsoft.com/en-us/dotnet/csharp/nullable-refe...


I’m not familiar with C#, so I probably should not have included it. But Kotlin, Scala 3 (with a compiler flag) and even Java with static analysis should be sound, if I’m not mistaken.


Rust has null pointers (which is why it has a function to make a null pointer). But Rust's references, which you use all the time in safe Rust, cannot be "null". As a result Option<&Thing> is the same size as a pointer to Thing, because under the hood the all-zeroes address value is None, other values are Some(address of Thing) but as the programmer you don't need to care how this works, the type system has your back.

You can't do much with a pointer unless you use unsafe Rust. So this provides an easy to see red line for inexperienced developers. "Huh, this is unsafe, I need a grown up".

The affordances for Option<Thing> are - in my biased but experienced opinion after similar time with both languages - superior to those on a nullable type like Thing? in C#. Partly that's historical, Rust has always had Option<Thing> while C# originally had nothing like this, grew nullable value types in a subsequent version and then much more recently got nullable reference types.

The technical mechanism is also much weaker in C#. Suppose a junior dev pastes a Stack Overflow answer in to fix the weird compile error they have. In Rust, if the pasted code is doing something awful with pointer mangling that's unsafe and hopefully your review is like "WTF is this code unsafe?" but in C# maybe there's a null-forgiving operator smuggled in somewhere or some tricks with casting, and now your "Never use null parameters" function is being called with a null parameter. If you complain, Microsoft's C# support will comfort you by explaining that all C# functions are responsible for null checking, even if their signature explicitly says they don't accept null parameters, they need to actually write the checks explicitly, yes this costs at runtime as well as making the code messier with redundant checks everywhere, too bad.

Maybe Kotlin is better? But my guess is that in the JVM ecosystem it's not able to actually deliver better.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: