(defmacro my-quote (x)
`(quote ,x))
and (defmacro my-quote (x)
(list 'quote x))
That `(quote ,x) is just way of writing (list 'quote x), not a notation for writing macros.That's it.
Macro's in Lisp are essentially "just" functions where the arguments are un-evaluated - you can use all the same functions etc...
Writing a simple Lisp interpreter is really quite educational - when you add macros and quoting into the language, you suddenly have a realisation at how simple it is.
But on the other hand, even C++ templates are Turing complete and even C++ parse trees can depend on the output of a Turing-complete evaluation. So it is hard to see what benefit a C++-like template feature is buying in comparison.
One alleged benefit of Java constrained genetics is that they allow in theory better error messages. Still in complex cases even after over 15 years with genetics in Java the error messages are not that great. Zig to some extend delegates to the compile-time library authors responsibility of producing good error messages. But then the error messages can be improved without waiting for the compiler to improve its reporting heuristics to cover all edge cases.
pub fn floor(x: anytype) @TypeOf(x) {
const T = @TypeOf(x);
return switch (T) {
f16 => floor16(x),
f32 => floor32(x),
f64 => floor64(x),
f128 => floor128(x),
else => @compileError("floor not implemented for " ++ @typeName(T)),
};
} template <class T> T floor(T x) { /* ... */ }
I think a documentation generator could display your Zig signature verbatim and a user could make sense of that.One that comes to mind is Terra: http://terralang.org/
In retrospect Terra seems a clear precursor to Zig (though I don't know if it was a direct influence).
My current work on a visual programming compatible language also uses this strategy for meta programming, so I’m very familiar with the academic literature. It certainly seems that Zig got this right and is doing well implementing it in a way that is usable and understandable.
MetaML certainly does seem to be similar to Zig, although the one paper I've now read thanks to your suggestion (https://www.sciencedirect.com/science/article/pii/S030439750...) does not mention introspection and type functions, and another commenter here suggests that it is, actually, referentially opaque.
1. It is referentially transparent, i.e., unlike Lisp, i.e. nothing in the language can distinguish between `1 + 2` and `3`. This means that the semantics of the language is the same as if everything was evaluated at runtime, and the comptime annotation has no impact on semantics (assuming syntax terms aren't objects and there's no `eval`).
2. It supports type introspection and construction.
3. It doesn't have generics and typeclasses as separate constructs but as applications of comptime.
I think 3 is unique to Zig, but I wonder about 1: is it possible in MetaOCaml, as it is in Lisp, C, C++, Rust and Haskell -- but not in Zig! (or, say, Java) -- to write a unit `m`, such that m(1 + 2) is different from m(3)?
D has been making structs at compile time for years now, however.
struct Socket
{
version (Posix)
int handle;
else version (Windows)
SOCKET handle;
else
static assert(false, "Unsupported platform");
}
Another example is the checked numeric type [1] in the D standard library. It takes two types as parameters. The first being the underlying type and the second being a "hook" type. The hook type allows the user to decide what should happen in various error conditions, like overflow, divide by zero and so on. The implementation is written in a Design By Introspection style and inspects the hook type and adopts its implementation depending on what hooks it provides. If the hook type implements the hook for overflow, that hook will be executed, otherwise it falls back to some default behavior.[1] https://dlang.org/phobos/std_experimental_checkedint.html