Not an immediate proposal, just a design to consider while other stuff is getting worked on.
This design could be internally helpful and exposed for lots of cool comptime stuff.
TLDR:
let a : int, #isPowerOfTwo, #cm, #blah, #minVal1;
// "#isPowerOfTwo" is a comptime tag, it doesnt enforce anything, just a label
fn log2(x: int) -> int {
// comptime if
if (@has(x, #isPowerOfTwo)) {
return x >> 1;
} else {
return log(x) / log(2)
}
}
IGNORE THE SYNTAX that's just an example.
Stuff like units (dollars, meters) help with debugging and stuff like #nonZero can help with compile optimizations and assertions.
Milestone: 0.3.0.
One of the OG typescript proposals was https://github.com/microsoft/TypeScript/issues/364. Never happened, which is sad but it could be an interesting usecase.
curious more how this will be used.
I think three general ways
For optimizations, the compiler can't fully optimize if the programmer doesnt provide all the information. Tags are a way to provide extra information.
For example, we might know an array (loaded from file storage) is pre-sorted in ascending order. Someone else might write a func like topFiveUnusedIds(array). That argument (array) is sometimes sorted and sometimes not, depending on where its called. So the function has to call .toSorted() then iterate and check if the id is unused. That's hella suboptimal. Not only would that be sorting a sometimes already-sorted maybe-massive array, but also we're making a potentially massive copy when we could've just iterated over the original! But its literally impossible for the compiler to optimize because it doesn't have all the information. If we tagged the array with std.array#sortedAscending, then a user-defined .toSorted() could have at least avoided the double-sort. (Avoiding the unnecessary duplicate memory would require the compiler itself to be smarter, but at least its possible compared to being impossible before). We could do a lot more optimizations if tags could also have constant arg literals, like #lengthRange(1,256) or #typicalSize(1000)
An example of function-guards: lets say we want to write a binary search func. It would be nice to compile-time require the argument to be sorted in ascending order. But an assert for that would be really expensive, even if was onlt at dev time. Imagine a 60fps game engine loop with a binary search in the loop. It could be problematically slow. Instead of just ... hoping the user sorts the array before calling binarySearch, we could require the array be tagged with #sortedAscending.
For an example of the clarification/debugging usecase. Think of accounting and debit/credit terminology and units of currency. For example a positive debit and a negative credit are really easy to get confused (theres tons of articles about it). Like a "widthdrawl of -5" is actually a deposit of 5 dollars. Something like transaction = -5 gets super confusing quickly. Is that a withdrawal of 5 yen, or a negative widthdrawl (aka deposit) of 5 pesos? Being able to tag numbers as #cash #usd #deposit vs #credit #yen #withdrawl could prevent a lot of human "oopsies".
Tags are not traits because tags have no methods, and tags are specific an object (rather than specific to a particular class)