It just seems really unconvincing to me. Just don’t do data modeling with entity pointers at all, and use patterns like RAII to guarantee that resources manage the lifetime of pointers they need. Or use pure functional programming if it matters that much in a given use case.
When the article says the compiler doesn’t know whether a given pointer is meant to be an entity pointer or not, but that you do as the programmer (and thus should use complex metaprogramming facilities to encode correctness of handling semantics of that pointer), it loses me completely. Those are code smells of bad program structure (especially creating the metaprogram to enforce a type of correctness chosen by the programmer, and highly susceptible to YAGNI premature abstraction).
In response to “boy it’s hard to guarantee keeping track of all these things” the bad response is to take on more code liability in the form of metaprogram “safety” enforcement. The good response is to ruthlessly remove entity-style pointer handling entirely and restructure the program to simply not need it.
> highly susceptible to YAGNI premature abstraction
I think in most cases this sentiment is correct but I think Blow's argument is that you are going to need it. In other talks he put forth some use cases where this has worked for him and his game dev studio.
The most abstract version of this argument:
1. A compiler is a tool to help the programmer
2. Compilers for the Rust programming language help the programmer by validating the program to be within a subset of all computable programs that operate within the language's rules (the borrow checker and type system)
3. there are likely many programs that are computable and correct that cannot be modeled within Rust's safety system (see most of the world's software to date)
4. For some use cases the most optimal solution may not fall within the subset of programs that Rust allows
5. Because of this it may be impossible for Rust to implement the most optimal solutions for some programs.
Blow's goal of making compilation describable within the language itself brings forward a huge set of features that other languages need a runtime or complex compiler to do. Things like code generation, reflection, metaprogramming, linting, and correctness validation could simply be packages you install with a package manager. If the language is kept at a minimal feature set and complexity with an advanced enough metaprogramming phase entire language features and abstractions can be implemented in this step. For example imaging being able to do something like `import grpc; import application.proto` and all of the gRPC magic happening without any complex build system at the full native speed of the compiled language with no runtime deps.
I'm not saying Blow is correct, I'm just saying it is a very interesting direction to take programming languages: weak guarantees but completely programmable.
> Blow's goal of making compilation describable within the language itself brings forward a huge set of features that other languages need a runtime or complex compiler to do. Things like code generation, reflection, metaprogramming, linting, and correctness validation could simply be packages you install with a package manager. If the language is kept at a minimal feature set and complexity with an advanced enough metaprogramming phase entire language features and abstractions can be implemented in this step.
I know you're not advocating for Lisp, but it kind of sounds like you are.
I love Lisp as much as the next neckbeard, but macros aren't unique to Lisp and they aren't the only kind of compile-time execution.
It's tough to come up with a better syntax than sexprs for writing macros in, that's clearly true. A number of recent languages have managed good-enough macros, Nim and Rust being two examples.
I have not listened to the podcast, but the example regarding entity pointers not outliving the frame would be something Rust is really good at.
The borrow checker can make sure that references to entities are strictly contained within the lifetime of a frame container and statically check that aspect.
> Because what’s an entity pointer vs a pointer to something else? The compiler doesn’t know that
Rusts compiler can know the difference and it can check lifetimes around that. Lifetimes can be made part of the type
of the pointer.
Pointers living through a render pass aren't the main use case he is interested in. It's a problem space that many engineers are familiar with so it's easy to talk about. Game developers have some very domain-specific problems that are less common outside of game engines. A more detailed description of his opinions are laid out here where he goes into much more detail about his experiences porting The Witness to mobile (I think): https://www.youtube.com/watch?v=4t1K66dMhWk
I think most of the time you're right, but in particular in game programming you know the optimizations you're going to need since the patterns have been pretty well established by now. And those patterns and optimizations are pretty low level which requires you to really understand how things are laid out in memory and rust might not give you great insight into how it lays things out (or it's not as well known or talked about...).
You can lay out your types exactly how you want in Rust, just by using the `#[repr(C)]` or `#[repr(packed)]` attributes to guarantee an ordering of the fields. So,
> rust might not give you great insight into how it lays things out
Is not true, and this is one of the first things you will learn when you try any sort of FFI. So
When the article says the compiler doesn’t know whether a given pointer is meant to be an entity pointer or not, but that you do as the programmer (and thus should use complex metaprogramming facilities to encode correctness of handling semantics of that pointer), it loses me completely. Those are code smells of bad program structure (especially creating the metaprogram to enforce a type of correctness chosen by the programmer, and highly susceptible to YAGNI premature abstraction).
In response to “boy it’s hard to guarantee keeping track of all these things” the bad response is to take on more code liability in the form of metaprogram “safety” enforcement. The good response is to ruthlessly remove entity-style pointer handling entirely and restructure the program to simply not need it.