Since I'm taking a few weeks vacation, I've decided to seriously try to learn rust. My method in this case is to ask ChatGPT to guide me (but not write for me!) a library ("crate") that I've always wanted to write and never got around to.

Of course, I get a lot of feedback on appropriate rust styling, but some of it veers into things I feel are deeper constraints. In this case, I had an open function, which took a struct containing some flags, such as "writeable", "create if didn't exist".

It didn't like the fact that I asserted if you set create and didn't set writeable. Here is my response:

---

Re: assert!(). I dislike APIs which allow misuse. Callers of a library should not rely on such checks in the library, in fact the concept of adding an InvalidOptions error type is offensive. A recoverable error is strictly a worse api than an unignorable error. But a compile time error is better.

We should use an enum READONLY, WRITE_MUST_EXIST, WRITE_MAY_CREATE.

---

Of course, it's a waste of time for me to lecture it on style, but I can't help myself!!

Reply to this note

Please Login to reply.

Discussion

it's not a waste if you add it to the system prompt

Not wasted of you feed it back in to the prompt/system context

I assume this is to open a file?

Personally, I took the approach of splitting into 3 separate functions; openRead, openWrite, openReadWrite.

This allows for different return types which inherit from a single common one, and makes clear the contract for which that thing (interface) can and cannot do. Eliminates nearly all API confusion and/or misuse.

openRead doesn't need to take parameters as it must always exist.

openWrite and openReadWrite take an exclusivity enum MaybeCreate, MustCreate, MustExist. This also allows a mode to be expressed for applying appropriate permissions immediately on creation when MaybyCreate and MustCreate are expressed.

openWrite also takes an append boolean parameter, constraining appending/truncation behavior to that function only.

I spent a lot of time playing with my API, bumping into and figuring out workarounds for several platform specific limitations (such as pwrite with O_APPEND being broken on Linux/FreeBSD).

https://github.com/05nelsonm/kmp-file/blob/master/library/file/src/commonMain/kotlin/io/matthewnelson/kmp/file/OpenExcl.kt

https://github.com/05nelsonm/kmp-file/blob/master/library/file/src/commonMain/kotlin/io/matthewnelson/kmp/file/FileStream.kt

I love this pattern: excellent advice. I asked ChatGPT how to do this in Rust, and it suggested a template using a phantom type was idiomatic Rust:

pub struct ReadOnly;

pub struct Writable;

pub struct Store {

file: File,

_mode: PhantomData,

}

Then implement write() only in the writable specialization.

I've deferred this change for now, but congratulations: you are responsible for my first refactoring (once the implementation is complete!) 🧡

Honestly preferring an enum and avoiding the assert is incredibly Rust-y.

Leaning into the type system is one of the distinctive traits of my C code, too (and something which I really miss in Python, with its tacked-on type annotations). But Rust certainly lends itself well to this style!