1

I've been writing some Vulkan code using the rust library Vulkano, and came across the following snippet:

let compute_pipeline = Arc::new(ComputePipeline::new(
    device.clone(),
    &shader.main_entry_point(),
    &(),
));

I'm specifically asking about the 3rd parameter here - in the implementation of ComputePipeline::new it is listed as :

/// Builds a new `ComputePipeline`.
pub fn new<Cs>(
    device: Arc<Device>,
    shader: &Cs,
    specialization: &Cs::SpecializationConstants,
) -> Result<ComputePipeline<PipelineLayout<Cs::PipelineLayout>>, ComputePipelineCreationError>
where
    Cs::PipelineLayout: Clone,
    Cs: EntryPointAbstract,
{
    ...
}

What is the &() syntax here? A reference to the unit type?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Nic Barker
  • 891
  • 1
  • 8
  • 16
  • 5
    *A reference to the unit type?* - that's exactly what it is – kmdreko Nov 22 '20 at 21:59
  • Thanks @kmdreko, It may have sounded like a rhetorical question but I wasn't sure, and with Rust I've found that it pays to make sure you really understand what's going on. – Nic Barker Nov 23 '20 at 00:46

3 Answers3

3

Yes it's a reference to a unit. This is needed here because ComputePipeline::new is generic:

pub fn new<Cs>(
    device: Arc<Device>,
    shader: &Cs,
    specialization: &Cs::SpecializationConstants
) -> Result<ComputePipeline<PipelineLayout<Cs::PipelineLayout>>, ComputePipelineCreationError> where
    Cs::PipelineLayout: Clone,
    Cs: EntryPointAbstract, 

The type of specialization is an associated type related to the type of the shader. The type of value provided for shader will determine the type of specialization, depending on its implementation of EntryPointAbstract.

In the example code you've provided, it's not clear what type shader.main_entry_point() has, but it must have an implementation of EntryPointAbstract and its associated SpecializationConstants type is ().

In order for type checking to work, you must pass &() for specialization, even though it most likely represents "no value". The compiler can optimise this away so, at runtime, this value does not exist and the function effectively has only two parameters.

Presumably, other implementations of EntryPointAbstract have more interesting types for SpecializationConstants.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • Thank you for the explanation! So just to clarify - passing of a reference to the unit type here will still representing "nothing" at run time, it's a result of compatibility / type checking at compile time? – Nic Barker Nov 23 '20 at 00:44
  • @NicBarker kinda, unit is not exactly "nothing" (depending on context that would usually be either `Option::None` or `!`) but since it's always the same value it doesn't carry any information, so it tends to be used when there's no information to send or return (e.g. where C or Java has the `void` pseudo return type, a rust function uses `()`). – Masklinn Nov 23 '20 at 06:53
3

Vulkano's ComputePipeline::new takes a reference to the associated type SpecializationConstants as its third parameter:

pub fn new<Cs>(
    device: Arc<Device>,
    shader: &Cs,
    specialization: &Cs::SpecializationConstants
)

In this case, the associated type is a zero tuple, or the unit type:

type SpecializationConstants = ()

Passing a reference to a value means adding a &, so a reference to the unit type looks like this &() :

ComputePipeline::new(
  ...
  &(),
)
Ibraheem Ahmed
  • 11,652
  • 2
  • 48
  • 54
1

[Is it] a reference to the unit type?

That's exactly what it is. Its just passing a reference & to the value ().

Similar syntax:

  • &1: a reference to a literal 1.
  • &[]: a reference to an empty slice.
kmdreko
  • 42,554
  • 6
  • 57
  • 106