Skip to content

Proposal: Way to force a struct/type to be distinct/unique #5578

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

Closed
suirad opened this issue Jun 10, 2020 · 3 comments
Closed

Proposal: Way to force a struct/type to be distinct/unique #5578

suirad opened this issue Jun 10, 2020 · 3 comments
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@suirad
Copy link
Contributor

suirad commented Jun 10, 2020

Background:

A strangeness that @DutchGhost and I found when developing zorrow was that in order to have comptime variables be instanced for a specific struct, we needed to introduce a var to force it to treat that type as unique. Otherwise those type seem to alias to another, causing comptime values to either not matter or not mutate for that type.

The following 3 examples will illustrate what is expected to "just work", the required way to accomplish it and the proposed change to accomplish it.


Expected:

const testing = @import("std").testing;

fn GiveTwice(comptime valt: type) type {
    comptime var times: usize = 2;
    return struct {
        val: valt,

        const Self = @This();

        pub fn init(_val: valt) Self {
            return Self{ .val = _val };
        }

        pub fn give(self: *Self) valt {
            comptime if (times == 0)
                @compileError("You can only 'give' 2 times");

            times -= 1;

            return self.val;
        }
    };
}

test "Test 1" {
    var a = GiveTwice(usize).init(1);
    _ = a.give();
    _ = a.give();
    _ = a.give(); // <-- Should Fail

    var b = GiveTwice(usize).init(1);
    _ = b.give();
    _ = b.give();
    _ = b.give(); // <-- Should Fail
}

Required:

const testing = @import("std").testing;

fn GiveTwice(comptime valt: type, comptime uniq: var) type {
    comptime var times: usize = 2;
    return struct {
        val: valt,

        const Self = @This();

        pub fn init(_val: valt) Self {
            return Self{ .val = _val };
        }

        pub fn give(self: *Self, comptime _uniq: var) valt {
            comptime if (times == 0)
                @compileError("You can only 'give' 2 times");

            times -= 1;

            return self.val;
        }
    };
}

test "Test 1" {
    var a = GiveTwice(usize, .{}).init(1);
    _ = a.give(.{});
    _ = a.give(.{});
    _ = a.give(.{}); // <-- Should Fail

    var b = GiveTwice(usize, .{}).init(1);
    _ = b.give(.{});
    _ = b.give(.{});
    _ = b.give(.{}); // <-- Should Fail
}

Proposed:

const testing = @import("std").testing;

fn GiveTwice(comptime valt: type) distinct type {
    comptime var times: usize = 2;
    return struct distinct {
        val: valt,

        const Self = @This();

        pub fn init(_val: valt) Self {
            return Self{ .val = _val };
        }

        pub fn give(self: *Self) valt {
            comptime if (times == 0)
                @compileError("You can only 'give' 2 times");

            times -= 1;

            return self.val;
        }
    };
}

test "Test 1" {
    var a = GiveTwice(usize).init(1);
    _ = a.give();
    _ = a.give();
    _ = a.give(); // <-- Should Fail

    var b = GiveTwice(usize).init(1);
    _ = b.give();
    _ = b.give();
    _ = b.give(); // <-- Should Fail
}

Summary:

The reason for the distinct keyword or something to that effect, is to solve the following problems:

  • Without the uniq arg on the .give() , the comptime var times doesn't persist mutations
  • Without the uniq arg on the GiveTwice(), any subsequent GiveTwice instance aliases to the first
@Vexu Vexu added the proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. label Jun 10, 2020
@Vexu Vexu added this to the 0.7.0 milestone Jun 10, 2020
@emekoi
Copy link
Contributor

emekoi commented Jun 10, 2020

duplicate?: #1595

@ghost
Copy link

ghost commented Jun 23, 2020

This relies on explicit ordering of comptime operations and closure, which is incredibly hexaflexagonical and possibly imposes tighter restrictions on comptime than we'd like. Also, if you're trying to implement a borrow checker, you'll need to handle more cases than this will let you.

As it stands, the proposed use case could be accomplished by accompanying each wrapped value with a GiveToken, and could be made much more convenient if comptime struct field semantics worked slightly differently. I'll open an issue for that, hang on.

@ghost
Copy link

ghost commented Jun 23, 2020

The above linked issue proposes another solution that doesn't get into the weeds of comptime execution.

@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Oct 27, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 May 19, 2021
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 Nov 23, 2021
@andrewrk andrewrk modified the milestones: 0.10.0, 0.11.0 Apr 16, 2022
@andrewrk andrewrk modified the milestones: 0.11.0, 0.12.0 Apr 9, 2023
@andrewrk andrewrk modified the milestones: 0.13.0, 0.12.0 Jul 9, 2023
@andrewrk andrewrk closed this as not planned Won't fix, can't repro, duplicate, stale Jul 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests

4 participants