rust-lang / rust-lang/rfcs

Proposal: A way to guarantee to the compiler that a certain field exists

Open
#3,165 2 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Markdown
Stars
6.6k
Forks
1.7k
Avg merge
16h 14m
Merged PRs (30d)
1

Description

Currently in Rust, there is no way to guarantee to the compiler that something for sure has a certain field. For example, if you are using an enum that has multiple fields, and all of those fields have the exact same name, type and purpose. I want a "semi-struct" of sorts (or maybe just a struct) that can guarantee that all variants inside of an enum have a certain field. Maybe this could also see extended use in traits or functions, to guarantee that XYZ field exists.

I have no idea how the syntax should (ideally) be structured, but here is a proposal that I have in Rust pseudocode.

The drawbacks that I see for this are in the pseudocode's comments.

// 'strict' will be important later
strict field FooField {
  x: usize,
  y: usize
}

field BarField {
  x: usize,
  y: usize
}

// The 'strict' specifier now comes into play here. Now you can automatically implement a new
// function for types that don't implement it and also have the FooField field.
trait FooTrait {
  // I think the dyn keyword should be required
  // for non-strict fields like BarField.
  
  // You also shouldn't be able to initiate a type
  // from Output unless it used a "strict" field.
  type Output: FooField;
  // anonymous fields with the exact names and properties may be
  // used instead of FooField, however ALREADY DEFINED fields
  // with the exact same properties should be disallowed

  fn new(x: usize, y: usize) -> Output {
    // Here, in theory, you should be able to
    // create a new instance since this is a strict field
    Output {
      x,
      y
    }
  }
}

// Implementing MULTIPLE fields on a tuple would also be problematic
// because it uses numbers to access values, as opposed to their names.
field BarTuple(x: usize, y: usize);

// Using anonymous parameters for the declaration above is probably 
// just a bad idea because it makes the purpose of these values 
// less clear.

// =============

fn main() {
  // Anonymous fields.
  let my_thing = field {
      x: 3u8,
      y: 4u8
  };
  other_fn(my_thing);
}

fn other_fn(thing: field {x: u8, y: u8} ) {

}

// Above, the syntax is a bit clunky.
// I think the real advantage would be being able to
// create objects without the need for an enum or
// an entirely new struct, not for usage in functions.

// Should there be a field! macro to allow for this?

// =============

// Here, defining FooStruct is optional since we are not adding additional properties.
struct FooStruct with FooField;

// Here, it is not. The goal here is to make it more difficult to mis-interpret the code while skimming through it.
struct BarStruct with FooField {
    x, y,
    z: usize
}

// Fields that are not strict can optionally be converted into strict
// fields for certain use-cases.
struct BarStruct with strict BarField;

enum FooEnum with FooField {
    // FooVariant does not compile!
    FooVariant {
      // Shorthand, so you don't need to specify types. 
      // Also makes it clearer which types come from the FooField, and which from the enum variant.
      x,
      y,
      // This throws a compiler error because 'strict' was specified. That means
      // that the enum cannot contain any additional fields.
      s: usize
   }
   // Fails, no X or Y fields
   BarVariant,
   NoIdeaVariant {
      // Success!
      x,
      y
   }
}

// All variants must have at least BarField's components,
// but can also add their own fields. Variants of BarEnum
// cannot be constructed in a trait function though, as they might require
// additional fields which won't be included
enum BarEnum with BarField {
   // Valid
   Pos3D {
     x,
     y,
     z: usize
   }
  // Valid
  Pos2D {
    x, y
  }
  // Invalid, does not contain field y.
  Pos1D {
    x
  }
  // Invalid, no implicit fields here!
  Pos0D
}

// Uses all of BarField's fields, but this time,
// it strictly requires that it conforms to BarField
enum xyzEnum with strict BarField {
  // Variants here.
}

The reason I do not wish to add new functionality to structs is because I want fields to be used like traits, while structs are strict types.

I would greatly appreciate criticism.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the proposal in issue #3165, including its pseudocode for strict fields, traits, structs, and enums. Compare the requested guarantees and syntax against Rust's existing type-system concepts; done would require a decided, technically scoped RFC direction rather than an implementation patch.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.