Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] Enum components #60

Open
JaimeGensler opened this issue Nov 23, 2023 · 0 comments
Open

[FEAT] Enum components #60

JaimeGensler opened this issue Nov 23, 2023 · 0 comments
Labels
enhancement New feature or request

Comments

@JaimeGensler
Copy link
Owner

JaimeGensler commented Nov 23, 2023

Describe the problem this feature solves

Rust-like enum components would be a nice win.

Potential Solutions

I've listed out a few options here - currently leaning towards (3) as the most likely ideal approach

Solution 1 (Association Enums)

Each enum variant is its own class and the enum type is a union of the variants. We can "associate" these distinct classes as enums by setting a custom static property and reading it to determine component type (as opposed to just looking at object.constructor).

// Defining
class Pending {}
class Resolved {
	value: any;
}
class Rejected {
	error: any;
}
type Promiseish = Pending | Resolved | Rejected;
// This function mutates these classes to make them associated
const Promiseish = Enum({ Pending, Resolved, Rejected });
const instance = new Promiseish.Pending();

// In use
function mySystem(query: Query<Promiseish>) {
  for (const promiseish of query) {
    console.log(typeof promiseish); // Could be Promiseish or any subtype!
  }
}

Pros:

  • Localizes enum definition to one place
  • Pretty small API
  • Enums look like normal components mostly
  • Direct handling of enum instances

Cons:

  • Must define enums twice (once as a type, once as an object)
  • Enum() mutates the classes given to it
  • Columns will store objects of variable shape, queries could deopt because promiseish is multiple kinds of object

Solution 2 (Wrapper Enums)

Enums as wrappers with a type and data field:

class Promiseish extends Enum({ Pending, Resolved, Rejected }) {}
const instance = new Promiseish(new Pending());
instance.type; // Pending
instance.data; // new Pending() created above

Pros:

  • Pretty straightforward

Cons:

  • Twice as many objects
  • Don't get to handle enum objects directly (i.e. always thru .data)
  • Kind of curious how VMs handle objects with references to other objects with different shapes - no idea on what this looks like for perf, if it even matters.

Solution 3 (Extension Enums)

This isn't exactly enums but it achieves a similar result. Rework how archetypes are modeled (we probably have to do this anyway) and allow filters/modifiers to define a matching function. Expose an Extended<T> type (would come up with a better name) that matches subclasses and not just the exact class. This could have uses beyond just enum-like behavior or the Extended<T> type

// Defining
class Promiseish {}
class Pending extends Promiseish {}
class Resolved extends Promiseish {
  data: any;
}
class Rejected extends Promiseish {
  error: string;
}

// In use
function mySystem(query: Query<Extended<Promiseish>>) {
  for (const promiseish of query) {
    console.log(promiseish.constructor); // Could be Promiseish or any subtype!
  }
}

Pros:

  • Direct object handling
  • Single definition of "union" type
  • Table columns are single-shape
  • Extensible enums! e.g. a physics library could provide a Collider type and just require consumers to extend the class with an onCollide() method. Library systems can then query for consumer components

Cons:

  • Changing enum type is a table move (does this happen much?)
  • Always have to specify Extended<T> in queries (we'd make this shorter, but still)
  • Queries still have de-opt potential
  • Extensible enums (hah)
@JaimeGensler JaimeGensler added the enhancement New feature or request label Nov 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: No status
Development

No branches or pull requests

1 participant