Disabling ASAP destruction within a function

I recently opened this issue which was closed as “not planned”.

The proposed solution was to model origins as part of the type but this isn’t practical for various reasons. One reason is that many structs in Vulkan have a p_next field which is an opaque pointer to some arbitrary extension struct and so can’t capture those origins. Another is that some structs are the root of a many-level tree. eg. VkGraphicsPipelineCreateInfo has a whopping 9 pointers to other various structs, most of which contain more pointers to structs, which contain more pointers. The Ash Rust crate, the most popular unsafe Vulkan bindings for Rust, choose not to model lifetimes, presumably for this reason.

Another issue raised was that it would “create two dialects of Mojo” and that “just by looking at a line of code (or even a few lines) one would not know what rules really apply”. I’m not really convinced of this being an issue though. While it would require you to see or remember the annotation at the top of the function, this doesn’t seem meaningfully different from having to see or remember the bottom (or wherever the lifetime extensions may be!) to know when something is destroyed currently. Keeping in mind things not on screen is also more just a general issue with long functions and not specific to this proposal.

That all being said, I’m not married to the specific solution I suggested but I cannot personally think of any alternatives. It’s also very possible that Vulkan is just a particularly nasty example of this issue and it’s not common enough in other ffi-heavy code to warrant any new feature. I’d appreciate others weighing in though.

Hi @Ryulord . We’re actively converging Mojo 1.0, we’re not in the mode of adding elective features right now, we’re ruthlessly prioritizing things to get the minimal language out. We can always add accretive things in the future.

Separately, I’ll share my opinion here. ASAP destruction is a core part of the memory ownership model on Mojo. You’re right that interop with C is an important feature, but our preferred way to handle it is to build mojo-native wrappers on top of the C APIs which provide added safety and predictability over the low-level C APIs. Mojo’s zero cost abstractions make this practical.

We can consider adding this in the future of course, but we should make sure to explore other potential ways to solve the problem first, and gain experience showing why they are dissatisfactory enough to warrant making the language more complex.

-Chris

Adding this here to clarify how bad GraphicsPipleLineCreateInfo is

GraphicsPipelineCreateInfo
├── p_next -> NoneType
├── p_stages -> PipelineShaderStageCreateInfo
│   ├── p_next -> NoneType
│   ├── p_name -> CStringSlice
│   └── p_specialization_info -> SpecializationInfo
│       ├── p_map_entries -> SpecializationMapEntry
│       └── p_data -> NoneType
├── p_vertex_input_state -> PipelineVertexInputStateCreateInfo
│   ├── p_next -> NoneType
│   ├── p_vertex_binding_descriptions -> VertexInputBindingDescription
│   └── p_vertex_attribute_descriptions -> VertexInputAttributeDescription
├── p_input_assembly_state -> PipelineInputAssemblyStateCreateInfo
│   └── p_next -> NoneType
├── p_tessellation_state -> PipelineTessellationStateCreateInfo
│   └── p_next -> NoneType
├── p_viewport_state -> PipelineViewportStateCreateInfo
│   ├── p_next -> NoneType
│   ├── p_viewports -> Viewport
│   └── p_scissors -> Rect2D
├── p_rasterization_state -> PipelineRasterizationStateCreateInfo
│   └── p_next -> NoneType
├── p_multisample_state -> PipelineMultisampleStateCreateInfo
│   ├── p_next -> NoneType
│   └── p_sample_mask -> SampleMask
├── p_depth_stencil_state -> PipelineDepthStencilStateCreateInfo
│   └── p_next -> NoneType
├── p_color_blend_state -> PipelineColorBlendStateCreateInfo
│   ├── p_next -> NoneType
│   └── p_attachments -> PipelineColorBlendAttachmentState
└── p_dynamic_state -> PipelineDynamicStateCreateInfo
    ├── p_next -> NoneType
    └── p_dynamic_states -> DynamicState