You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Say you have a lot of platform-specific code (like for supporting windows and posix), which frequently have different return types based on the platform. You want to use the return type optimized for the platform (such as [:0]const u16 on Windows and [:0]const u8 on posix). Ideally, the platform-specific differences are handled by default by the platform-specific functions instead of the callers of the functions (reducing complexity and making it more maintainable)
This means that on Windows, open must convert to []const u16 on every call to open - which is lossy (utf8 != utf16) + costs performance & memory, and it's ambiguous what exactly is the generic type in use without going through @typeInfo on the open fn
This lets us avoid expensive, buggy conversions without significantly complicating the codebase, and the expected type is unambiguous by convention: open.T.
Alternative syntax
Another idea: specify the function to call in the struct definition, similar to packed struct except when not packed, its the function to call:
Maybe I'm missing something, but I fail to see how the example use case motivates the need for callable structs. It seems like you want to expose a single function that takes/returns types that are optimal for the target OS. Wouldn't something like this accomplish what you are asking for?
pubconstPathString=if (builtin.os.tag==.windows) PathStringWelsePathStringZ;
pubconstPathStringZ= [:0]constu8;
pubconstPathStringW= [:0]constu16;
pubfnopen(path: PathString, flags: u32, perm: mode_t) OpenError!fd_t {
returnif (builtin.os.tag==.windows)
openW(path, flags, perm)
elseopenZ(path, flags, perm);
}
pubfnopenZ(path: PathStringZ, flags: u32, perm: mode_t) OpenError!fd_t {}
pubfnopenW(path: PathStringW, flags: u32, perm: mode_t) OpenError!fd_t {}
test {
_=tryopen("foo", 0, 0); // ignoring that this doesn't work on Windows for the reasons outlined above_=tryopenZ("foo", 0, 0);
_=tryopenW(&.{ 'f', 'o', 'o' }, 0, 0);
}
Say you have a lot of platform-specific code (like for supporting windows and posix), which frequently have different return types based on the platform. You want to use the return type optimized for the platform (such as
[:0]const u16
on Windows and[:0]const u8
on posix). Ideally, the platform-specific differences are handled by default by the platform-specific functions instead of the callers of the functions (reducing complexity and making it more maintainable)What are the options today?
Use the same type for all platforms
example:
std.os.open
Then, when you want the more specific type, suffix the function with the type name at the end
This means that on Windows,
open
must convert to[]const u16
on every call toopen
- which is lossy (utf8 != utf16) + costs performance & memory, and it's ambiguous what exactly is the generic type in use without going through@typeInfo
on theopen
fnUse a wrapper struct
This might look something like:
But, this doesn't make the code easier to read.
open.path
obscures the intent. Does that meanZ
andW
are not opening the path?You could also use a
comptime fn
that returns a newtype
, but that ends up looking pretty similar to the wrapper struct approachProposal: callable structs
One idea: if a struct defines a function called
call
, that struct becomes callable like a functionThis lets us avoid expensive, buggy conversions without significantly complicating the codebase, and the expected type is unambiguous by convention:
open.T
.Alternative syntax
Another idea: specify the function to call in the struct definition, similar to
packed struct
except when not packed, its the function to call:The text was updated successfully, but these errors were encountered: