andrewlock / StronglyTypedId

A Rosyln-powered generator for strongly-typed IDs
MIT License
1.52k stars 79 forks source link

consider adding + operator for integers #17

Open dzmitry-lahoda opened 4 years ago

dzmitry-lahoda commented 4 years ago

e.g. in games could enumerate entities via ++ (may be minus too)

mikechristiansenvae commented 1 year ago

I like the idea, but I don't think it solves your problem.

You probably want to generate unique IDs, in sequence.

What's stopping you from doing this?

[StronglyTypedId(backingType: StronglyTypedIdBackingType.Int)]
public partial struct FooId { }

public static void Test()
{
    var firstId = FooId.New();
    var secondId = ++firstId;
    var thirdId = ++firstId;
}

Now, secondId and thirdId are equal, but you probably intended them to be unequal.

My opinion, instead, what you're looking for is a StronglyTypedIdGenerator.

Something like this:

[StronglyTypedId(backingType: StronglyTypedIdBackingType.Int)]
[StronglyTypedIdGenerator]
public partial struct FooId { }

public static void Test()
{
    var firstId = FooIdGenerator.Next();
    var secondId = FooIdGenerator.Next();
    var thirdId = FooIdGenerator.Next();
}

Where the implementation of FooIdGenerator would be something like this:

public static class FooIdGenerator
{
    private static int next = -1;
    public static FooId Next() => new FooId(Interlocked.Increment(ref next));
}

A difficulty may be if you are generating a lot of IDs. Re-use may be an issue... You say you would be using it for games. I could imagine that if you were to assign each "particle" an ID, for instance, you could conceivably run out of IDs.

In that case, it may make sense for the FooIdGenerator implementation to be an instance type. Then, you could generate unique IDs within a given context, where the context is specified by you, upon creation of the ID generator.

You could still access the "global" ID generation context via a singleton instance of the generator.

public class FooIdGenerator
{
    public static FooIdGenerator Default { get; } = new FooIdGenerator();
    private int next = -1;
    public FooId Next() => new FooId(Interlocked.Increment(ref next));
}

public static Scene GenerateScene()
{
    var scene = new Scene();
    var idGenerator = new FooIdGenerator();
    for(var i = 0; i < 10_000; ++i)
    {
        scene.Add(new Particle(idGenerator.Next());
    }
    return scene;
}