-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Proposal: Adding interfaces to the language #20819
Comments
You can use the GitHub issue search for "interface label:proposal": https://github.com/ziglang/zig/issues?page=1&q=interface+label%3Aproposal . The issue template section for "Language Proposal" links to a statement that the maintainers do not welcome language proposals at this time. As for my personal feedback now that I've read the current version:
IMO your proposal doesn't specify the deficiency in the language well enough that it tries to solve.
One of Zig's fundamental goals is to be explicit and value reading code over writing it. A feature request aligned with these goals ("the Zen") is easier to justify than one only oriented on a hunch, without direct comparison to status-quo. Simplicity is also a design goal of Zig, and an easy way for simplicity is to keep a small size overall.
Every one of those would need to be justified:
|
The basic idea behind this proposal is to have an easier/more flexible way to do interfaces, for example, allocators implementation should look like: // in some std/mem/allocator.zig
pub const Allocator = interface {
// on dynamic interfaces, all declarations are *const T (T being the type of the decl)
rawalloc: fn (self: *@Implemented(), len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8,
rawresize: fn (self: *@Implemented(), buf: []u8, buf_align: u8, new_len: usize, ret_addr: usize) bool,
rawfree: fn (self: *@Implemented(), buf: []u8, buf_align: u8, ret_addr: usize) void,
// just like with structs, you can have methods on interfaces, having a aspecific
// syntax for method calling could really be useful here tbh
pub fn create(self: Allocator, comptime T: type) Error!*T {
if (@sizeOf(T) == 0) return @as(*T, @ptrFromInt(math.maxInt(usize)));
const ptr: *T = @ptrCast(try self.allocBytesWithAlignment(@alignOf(T), @sizeOf(T), @returnAddress()));
return ptr;
}
// . . .
}; And every Also if you implement an interface twice, it changes absolutely nothing, and Another use could be in places where we need some generic implementations (well that's the primary use of interfaces), so that being
Well, it could work with comptime and I think having a clearer way of doing interfaces would be great in any points. Right now, a lot of languages have interfaces or things similar to them: C++ (virtual functions), obj-c (protocols), c#, java, go, rust (traits) and (i guess) many others. Having a standard way of doing interfaces could be great. While writing this, i realized how weird it could end up, and become a footgun, like, what if you give a default function with comptime logic depending on the implemented type ? compile error, the interface becomes unusable alone, apparently, not a lot of people complain except new-comers, guess i'm too young to the language ¯_(ツ)_/¯ (i've been using it for like 10 month or so). Anyway good day, might have been useless to waste 30 mins of my life writing a useless proposal. Even though comptime-set declarations could be really interesting :^ |
Comptime interfaces have the potential to be an innovation that no other system level language supports. (Although go comes close, with its generics system that does comptime duplication of the code for each required type) Given zig's (awesome) love for allocators, there is a significant potential to improve the way allocators are handled with comptime interfaces as well. If comptime interfaces dont arrive before 1.0 then it'll probably be too late to add them later. |
I guess it already has been discussed and maybe rejected, if not just tell me, but they are in practically every languages. Interfaces/traits (whatever you call them, warning: will may or may make some develop ptsd <:0) would be nice in zig and make it the unbeatable systems programming language (at least for me), the current method of making interfaces in zig is, well, the good old "vtable" one, but it's a bit tedious to make and use. A basic implementation could be with static interfaces: a single interface gets regenerated for every types implementing it, this is nice, easy and it works well, proven to be really reliable, but it has some flaw, like you can make an array of those without specifying a type (btw rust's trait are static by default). But the big goal is: dynamic interfaces (ooh scary). They got a fixed size for all implemented types: they have a vtable and a pointer to the actual interface data (just like
std.mem.Allocator
), those can be harder to debug (maybe). But what everyone cares about is "how do would I use them in zig!". For this I'd like to introduce you the syntax I though for them:They are declared just as structs, except that the fields declare public, mandatory declarations for the implemented type. They can be implemented on structs, opaques, enums and unions (every types which can have declarations). interfaces can have default values (which result in a default behavior if the declaration is not specified) and they can be pretty much anything. For dynamic interfaces, the
interface
type is dynamic by default. If referenced in anyway other than implementation, a default code gets generated for it (if there's default functions). To declare a static interface though, you'll need to use the new&&
operator (could maybe change if you'd prefer to):Also static interfaces can be coerced to dynamic interface like this:
Which clearly indicates that it stores the pointer to
baz
(which makes more sense for zig). However dynamic interfaces cannot be coerced back to static ones except via@ptrCast
or maybe a new builtin function for this special case (which also would make more sense for zig).As I said before, dynamic interfaces are literally the equivalent of a struct containing all the declarations as pointer + the pointer to the interface data and thus, getting should do as so (being able to access data pointer, declaration pointers is pretty straight-forward).
The text was updated successfully, but these errors were encountered: