-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Describe the feature
I would like functions that can be evaluated at comptime, designated by a @[comptime] attribute.
@[comptime]
fn color(r u8, g u8, b u8, a u8) u32 {
return u32(r) << 24 + u32(r) << 16 + u32(b) << 8 + u32(a)
}
enum Colors : u32 {
red = color(255, 0, 0, 255)
green = color(0, 255, 0, 255)
blue = color(0, 0, 255, 255)
}Could allow something like the above.
Use Case
Another use case is in comptime, for example the current way you could emulate the container_of macro in V is the following:
pub fn container_of[T](ptr voidptr, member_name string) &T {
$if T is $struct && T !is $string {
return unsafe { &T(&char(ptr) - offsetof[T](member_name)) }
} $else {
$compile_error('T is not of type struct')
}
}
pub fn offsetof[T](member_name string) int {
tmp := &T{}
$if T is $struct {
$for field in T.fields {
if field.name == member_name {
access := int(voidptr(&tmp.$(field.name)))
return access - int(tmp)
}
}
} $else {
$compile_error('offsetof only accepts struct types')
}
return 0
}Notice that offsetof needs to loop for all fields in T in order to find the one that matches member_name which adds unnecessary runtime. Since we need to call offsetof inside this function with different types, we cannot have a fixed member name, as this may differ depending on where you call container_of from.
Below is how it could look with @[comptime]:
@[comptime]
pub fn offsetof[T](member_name string) usize {
unsafe {
return usize(
&char(&T{}.$(member_name)) - &char(0)
)
}
}Notice that member_name is used as a constant and replaced as the member name of T. We are calculating the offset of the member named member_name from the start of the pointer. There is no need to loop here as this can be checked at compile-time anyway (given that member_name is a constant).
Proposed Solution
I quick way to implement this would be to "simulate" each function in V repl and insert the constant output in place of the function call.
Other Information
For my second example you could probably implement something comptime if in like:
struct Foo {
bar string
member int
}
const a := 'member'
foo := Foo{
bar: 'hello'
member: 42
}
$if field := a $in Foo.fields {
println(foo.$(field.name))
}Acknowledgements
- I may be able to implement this feature request
- This feature might incur a breaking change
Version used
V 0.5.0 50a7d53
Environment details (OS name and version, etc.)
| V full version | V 0.5.0 a965a39.50a7d53 |
|---|---|
| OS | linux, "CachyOS" |
| Processor | 12 cpus, 64bit, little endian, 13th Gen Intel(R) Core(TM) i5-1335U |
| Memory | 5.32GB/15.31GB |
| V executable | /home/dylan/Repos/v/v |
| V last modified time | 2026-01-28 17:56:57 |
| V home dir | OK, value: /home/dylan/Repos/v |
| VMODULES | OK, value: /home/dylan/.vmodules |
| VTMP | OK, value: /tmp/v_1000 |
| Current working dir | OK, value: /home/dylan |
| Git version | git version 2.52.0 |
| V git status | weekly.2026.02-182-g50a7d536 |
| .git/config present | true |
| cc version | cc (GCC) 15.2.1 20260103 |
| gcc version | gcc (GCC) 15.2.1 20260103 |
| clang version | clang version 21.1.6 |
| tcc version | tcc version 0.9.28rc 2025-02-13 HEAD@f8bd136d (x86_64 Linux) |
| tcc git status | thirdparty-linux-amd64 696c1d84 |
| emcc version | N/A |
| glibc version | ldd (GNU libc) 2.42 |
Note
You can use the 👍 reaction to increase the issue's priority for developers.
Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.