This is all just a set of ideas for how to add metaprogramming to Vala. It is not harmful to dream(Russian saying).
1) C++ template style
Simple make generic variables, that you can try to call any method, and the compiler checks whether this can be done or not, checking whether the type that the generic was called with has this symbol.
Perhaps this is the easiest way, in terms of implementation.
2) Macros. (The manipulation of the AST)
Problem: macros cannot be supported by tools.
2 Options:
2.1) Restrict things that macros can change, such as the semantics(Nim) must be preserved.
2.2) To create macros, a special API must be provided, such that when you create a macro, you automatically teach VLS how to work with it. Such changes to the compiler behavior are a separate project. (idea from Kotlin) But here there is a problem in the need to create a reference VLS, or include some part of it in the compiler(such things already happen https://gitlab.gnome.org/GNOME/vala/-/merge_requests/95)
PS A great article describing how this was handled in D.
3) API for code attributes
This option is very similar to the second option, and here you need to think about how to achieve VLS support.
For example, apmasell added a new code attribute to the Vala compiler [Interrupt(vector = "foo", block = true]
to support AVR controllers by implementing his own custom libvala frontend.
Ideas: the class attribute which makes the object’s fields to the fields in XML/JSON/… , an attribute of a method that turns its application into an SQL string(making a class with such methods will result in something like ORM)
Once again, I’m talking specifically about providing the user with an API to create new code attributes, as in the example of how apmasell implemented its Vala forks, but to make it look easier and with restrictions.
4) New C++ backend
Pros
- Free metaprogramming
- Applying var (auto) in previously inaccessible places (method arguments, method types returned…)
- constexpr ()
- concepts (restrictions for types) and other things from C++20…23
- Native interaction with C++ code. This is probably one of the most important advantages, as it gives access to a huge code base, and adds Vala new areas of application besides GTK applications. (Qt -> embended UI, UE4, boost?, …) (Although there aren’t too many limiting factors right now)
Cons/Problems:
- Probably a long compilation, if you do not use some hacks for code generation. (For example, Nim actively uses goto)
- It will take a few tricks to organize the interaction of the code on C - > C++ backends.
The interaction between C++ -> C is limited, perhaps this problem can be solved via GIR/SWIG (ValaBind, example ) - Interaction of the C++ backend with GIR (priority for Vala, I think it is still possible due to compatibility with C ABI)
But
constexpr
and auto
will appear in C2X, and vala will be able to get these advantages for free, but it won’t be soon. However, it is worth considering that by that time new features will appear in C++.
There have already been several attempts to create a C++ backend:
5)
Infix notation (Kotlin) or Uniform Function Call Syntax (D) give the language great opportunities to implement something DSL like, without directly implementing meta programming.
6) Creating custom Methods With Syntax Support
Vala already supports this for certain operators (in
, foreach
, []
, [:]
, [,]
, …) if you let the user choose which text / operator will turn into a function, it will also allow you to create DSL and much more. From the point of view of C, this will just be a function call.
Here some examples:
class Counter: Object{
public int Value { get; set; default = 0;}
// infix
public static Counter plus + (Counter c1, Counter c2) {
return new Counter { Value = c1.Value + c2.Value }; // var res = c1 + c2;
}
// prefix, postfix
public static Counter increment ++ (Counter c1) {
return new Counter { Value = c1.Value + 10 };
}
//
public static bool roughly_equal ~~ (Counter c1, Counter c2) {
return round(c1.Value) > round(c2.Value); // bool res = c1 ~~ c2;
}
public static bool contain in (Counter c1, Counter c2) {
return round(c1.Value) > round(c2.Value);
}
// or like that, Most likely it will require the implementation of the first option
public static bool contain<T> in (T left_value){
return this.contain(left_value);
}
//with keyword? Need to implement templates from first variant
delegate T WithFunc<T> (T t);
public static void with with (params WithFunc[] funcs){
foreach (var func in funcs)
func(this);
// or
this.func;
}
//real with, same but with AST manipulation?, T here is somehow type for code (Dlang mixin?)
public static void<T> with with (params T[] anything){
foreach (var any in anything)
this.T;
}
}
7) API for creating / modifying parsers as Genie.
This must also be accompanied by correct VLS changes so that syntax highlighting and the rest will continue to work. Something similar has already been discussed here (I didn’t know HAXE existed then). This option is very similar to macros.
All these options are too complex to implement, and Vala already has unresolved problems(I think all languages have). But there is progress in improving the syntax, for example, the params keyword added in 0.48 from C#, PR by adding the null-conditional member access operator ?.
, negation of is/in operators, Kotlin-style namespace declaration, and my favorite is the with keyword .