vala issueshttps://gitlab.gnome.org/GNOME/vala/-/issues2023-05-08T19:57:09Zhttps://gitlab.gnome.org/GNOME/vala/-/issues/1433Type of generic type parameter for the struct is not saved.2023-05-08T19:57:09ZVladyslav StovmanenkoType of generic type parameter for the struct is not saved.It is possible to create and use generic structs in Vala, however information about the parameter exists only on compilation stage. While it works for basic read and write operations, it is not possible to use generic type to call other ...It is possible to create and use generic structs in Vala, however information about the parameter exists only on compilation stage. While it works for basic read and write operations, it is not possible to use generic type to call other generic functions and/or create other generic objects.
Consider such vala code:
```vala
namespase Test {
public void print_type<T> (T obj) {
stdout.printf ("%s\n", typeof (T).name ());
}
public struct Foo<T> {
T data;
public Foo (T val) {
data = val;
}
public void print () {
print_type<T> (data);
}
}
public class EntryPoint {
public static void main (string[] args) {
Foo<int> test = Foo<int> (1);
test.print ();
}
}
```
Translation to C completes successfully, but the compilation to executable failes. The following code looks incorrect (unnecessary parts are ommited)
```c
struct _TestFoo {
gpointer data;
};
void test_foo_print (TestFoo* self)
{
gconstpointer _tmp0_;
_tmp0_ = (*self).data;
test_print_type (self->priv->t_type, NULL, NULL, _tmp0_);
}
```
Tested on Fedora 37 with version from sources and version from repository
```bash
bash-5.2$ valac --version
Vala 0.57.0.146-94582
bash-5.2$ /bin/valac --version
Vala 0.56.3
```https://gitlab.gnome.org/GNOME/vala/-/issues/1427Enforce a resonable style for TypeParameters2023-04-15T23:15:31ZRico TzschichholzEnforce a resonable style for TypeParametersCurrently it is possible to use arbitrary strings of any length to define a TypeParameter. This can lead to confusions with actual type names.
So this is allowed, but should be dicouraged?
```vala
class Foo<RandomGenericTypeParameter> :...Currently it is possible to use arbitrary strings of any length to define a TypeParameter. This can lead to confusions with actual type names.
So this is allowed, but should be dicouraged?
```vala
class Foo<RandomGenericTypeParameter> : Object {
RandomGenericTypeParameter _r;
public Foo (RandomGenericTypeParameter r) {
_r = r;
}
public RandomGenericTypeParameter get_foo () {
return _r;
}
}
```
Usually this should look like this by using a single capital letter.
```vala
class Foo<G> : Object {
G _r;
public Foo (G r) {
_r = r;
}
public G get_foo () {
return _r;
}
}
```
What restrictions would be reasonable?https://gitlab.gnome.org/GNOME/vala/-/issues/1313Add information about type parameters into generated GType.2022-05-03T23:03:50ZVladyslav StovmanenkoAdd information about type parameters into generated GType.## Motivation
Currently GLib.Array<int> and GLib.Array<MyObjectType> are of type G_TYPE_ARRAY. And ```typeof(GLib.Array<int>).is_a(typeof(GLib.Array<MyObjectType>))``` is true. It causes troubles when checking types, in reflection for ex...## Motivation
Currently GLib.Array<int> and GLib.Array<MyObjectType> are of type G_TYPE_ARRAY. And ```typeof(GLib.Array<int>).is_a(typeof(GLib.Array<MyObjectType>))``` is true. It causes troubles when checking types, in reflection for example. It is impossible to either distinguish types or cast such types to some common parent. Gee.Traversable<G> allows to get the value of Type element_type property and find information about type of the element in the collection. With this property it is possible to separate Gee.Traversable<T> object from Gee.Traversable<G> object. However in that case object is required and type information does not contain any information about type parameters. GLib definition of GType, as far as I know, does not allow to store additional information regarding type parameters. It would be nice to add this opportunity there, but it requires bigger changes and discussion within GLib team (I doubt this is going to happen).
## Suggestion
CLR (.Net) aware of generics and it is possible to construct information about generic type in runtime like
```typeof(MyType<>).MakeGenericType(typeof(float))``` and later instantiate this type. JVM is not aware about generics, so there is type erasure on compilation and Type for corresponding types are different. However it is still possible to check is type a generic type and what type parameters was used. GLib is not aware of generics, but like CLR, creates one type for all generic type parameters (MyType<int>, MyType<float?> and MyType<MyObjectClass> are all of type MY_CLASS).
Use C++ like approach. It won't require changing anything in GLib itself. Every declaration of MyType<T> with concrete type should cause generation of GLib type for it. Not MY_TYPE, but MY_TYPE__G_TYPE_INT__. Code generator should be changed, I think quite a lot, to support it.https://gitlab.gnome.org/GNOME/vala/-/issues/1209Cannot pass GLib.List <string> as an argument (error: duplicating List instan...2021-08-06T06:44:28ZNaohiro CHIKAMATSUCannot pass GLib.List <string> as an argument (error: duplicating List instance, use unowned variable or explicitly invoke copy method)# What is problem.
I got an below error.
```
../src/parser/CountLineOfCode.vala:34.27-34.38: error: duplicating List instance, use unowned variable or explicitly invoke copy method
public void cloc (List<string> list) {
...# What is problem.
I got an below error.
```
../src/parser/CountLineOfCode.vala:34.27-34.38: error: duplicating List instance, use unowned variable or explicitly invoke copy method
public void cloc (List<string> list) {
^^^^^^^^^^^^
```
So, I check a similar problem and tried to solve it, but I couldn't.
I think the ownership of the variable is incorrect.
When verified with a small code, however, the same error did not occurs.
# Success Case
In case of success, error does not occurs.
```
/* Application.vala */
namespace Camilla {
public class Application : GLib.Application {
public static int main (string[] args) {
Run run = new Run ();
run.run ();
return 0;
}
}
}
```
```
/* Run.vala */
namespace Camilla {
public class Run : GLib.Object {
GLib.List<string> list;
public void run () {
list = new List<string> ();
list.append ("aaa");
list.append ("bbb");
Ok ok = new Ok ();
ok.printList (list);
}
}
}
```
```
/* Ok.vala */
namespace Camilla {
public class Ok : GLib.Object {
public void printList (List<string> list) {
foreach (weak string str in list) {
stdout.printf ("%s\n", str);
}
}
}
}
```
# Failure Case
In this case, the cloc method of the CountLineOfCode class will result in the error.
Only the relevant parts are shown below.
```
/* Application.vala */
namespace Camilla {
public class Application : GLib.Application {
public static int main (string[] args) {
Camilla camilla = new Camilla ();
return camilla.run (args);
}
}
}
```
```
/* Camilla.vala */
namespace Camilla {
public class Camilla : GLib.Object {
/** File list to be checked. */
private List<string> targetFileList;
public int run (string[] args) {
/* walk () returns files under the current directory as GLib.List<string> */
targetFileList = Core.File.walk ("."); /* return list with copy_deep(strdup) [Camilla.vala](/uploads/ec189b4b1ace296fdac31f4ed7372a82/Camilla.vala)
[Application.vala](/uploads/ea2b349a98f60b91493600d7815c1331/Application.vala)[CountLineOfCode.vala](/uploads/ee6606ebf5203a77dc5cc2d72f891698/CountLineOfCode.vala)*/
parse ();
return EXIT_STATUS.SUCCESS;
}
private void parse () {
if (argParser.hasOption ("c")) {
CountLineOfCode cloc = new CountLineOfCode ();
cloc.cloc (targetFileList); /* Error point. */
return;
}
}
}
}
```
```
/* CountLineOfCode.vala */
namespace Camilla.Parser {
public class CountLineOfCode : GLib.Object {
public void cloc (List<string> list) { /* Error point. */
/* Omit */
}
}
}
```
To remove the error, I changed method definition like that `cloc (owned List<string> list)`.
After that, I changed caller like that `cloc.cloc (targetFileList.copy_deep (strdup));`
However, error still occurs.
In the case of unowned, that is `cloc (List<weak string> list)` and `cloc.cloc (targetFileList.copy());`,
same error occurs.https://gitlab.gnome.org/GNOME/vala/-/issues/1169Generic array returns default values2021-10-07T21:49:49Zgavrgavr123456789@gmail.comGeneric array returns default valuesWorks add arrays code:
```vala
int[] array_add(int[] a, int[] b){
int[] c = {};
foreach (var q in a){
c += q;
}
foreach (var q in b){
c += q;
}
return c;
}
void main () {
int[] a = {1,2,3};
int[] b = {1,2,3};
...Works add arrays code:
```vala
int[] array_add(int[] a, int[] b){
int[] c = {};
foreach (var q in a){
c += q;
}
foreach (var q in b){
c += q;
}
return c;
}
void main () {
int[] a = {1,2,3};
int[] b = {1,2,3};
var c = array_add(a, b);
prin(c.length);
foreach (var thing in c){
prin(thing);
}
}
[Print] void prin(string str) { print(str + "\n"); }
```
Output:
```
6
1
2
3
1
2
3
```
Failed code:
```vala
T[] array_add<T>(T[] a, T[] b){
T[] c = {};
foreach (var q in a){
c += q;
}
foreach (var q in b){
c += q;
}
return c;
}
void main () {
int[] a = {1,2,3};
int[] b = {1,2,3};
var c = array_add(a, b);
prin(c.length);
foreach (var thing in c){
prin(thing);
}
}
[Print] void prin(string str) { print(str + "\n"); }
```
Output:
```
6
1
2
3
0
0
0
```https://gitlab.gnome.org/GNOME/vala/-/issues/964Non-simple generics should be forbidden on methods with params-array2020-05-27T07:33:03Zgavrgavr123456789@gmail.comNon-simple generics should be forbidden on methods with params-arrayExample:
```vala
struct Map<K,V>{
K k;
V v;
}
void reproducer<K,V>(params Map?[] maps){
K k = maps[0].k;
}
void main(){
reproducer<int,string>({Map<int,string>(){k=1, v="1"}});
}
```
C Error:
`incompatible types in assig...Example:
```vala
struct Map<K,V>{
K k;
V v;
}
void reproducer<K,V>(params Map?[] maps){
K k = maps[0].k;
}
void main(){
reproducer<int,string>({Map<int,string>(){k=1, v="1"}});
}
```
C Error:
`incompatible types in assigning "gpointer" {aka " void *"} type values to "Map" {aka "struct _Map»}`
C Code:
```c
void
_vala_main (void)
{
gchar* _tmp0_;
Map _tmp1_ = {0};
Map _tmp2_;
Map _tmp3_ = {0};
Map _tmp4_;
_tmp0_ = g_strdup ("1");
memset (&_tmp1_, 0, sizeof (Map));
_tmp1_.k = (gpointer) ((gintptr) 1);
_tmp1_.v = _tmp0_;
_tmp2_ = _tmp1_;
_tmp3_.k = _tmp2_; // HERE ERROR
_tmp4_ = &_tmp3_;
reproducer (G_TYPE_INT, NULL, NULL, G_TYPE_STRING, (GBoxedCopyFunc) g_strdup, (GDestroyNotify) g_free, &_tmp4_, NULL);
map_destroy (&_tmp2_);
}
```https://gitlab.gnome.org/GNOME/vala/-/issues/906Get the difference between nullable and value types2020-02-10T14:31:18Zgavrgavr123456789@gmail.comGet the difference between nullable and value types~"1. Feature"
~"2. Needs Design"
~"5. Code Generator: Gtype"
For example in a Generic function I need to find out if I accepted `int` or `int?` :
```vala
void foo<G> (G g) {
if ( typeof(G) == Type.POINTER ){ // or BOXED here
...~"1. Feature"
~"2. Needs Design"
~"5. Code Generator: Gtype"
For example in a Generic function I need to find out if I accepted `int` or `int?` :
```vala
void foo<G> (G g) {
if ( typeof(G) == Type.POINTER ){ // or BOXED here
if (typeof(G) == Type.INT) prin("int?");
} else {
if (typeof(G) == Type.INT) prin("int");
}
}
void main () {
int a = 42;
int? b = 25;
foo<int> (a);
foo<int?> (b);
}
```
Got int int, also if just :
```vala
prin(typeof (int).name());
prin(typeof (int?).name());
```
gives gint gint when in C code we can see:
```c
gint a = 0;
gint* b = NULL;
foo (G_TYPE_INT, NULL, NULL, (gpointer) ((gintptr) a));
foo (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, b);
```
I understand that this is probably not possible, but it could be solved using flag enum:
```vala
if (Type.BOXED in type && Type.INT in type) print ("int?\n");
```
##### What is it for
This could solve some problems with Gee/GLib collections and just generics by providing the ability to execute more boilerplate code on the library side for example get_compare_func_for, get_equal_func_for, get_hash_func_for.
```vala
Seq.of_array<int?>(numbers).max((a, b) => {
if (a == null) return -1;
else if (b == null) return 1;
else return a < b ? -1 : (a == b ? 0 : 1);
});
//Can be replaced to
Seq.of_array<int?>(numbers).max(); // just like C#
```https://gitlab.gnome.org/GNOME/vala/-/issues/834Support casting Generic to GVariant2019-08-20T19:12:30Zgavrgavr123456789@gmail.comSupport casting Generic to GVariantSimple Example
```vala
void print_simple_types (Variant v) {
...
}
void func<G> (G[] sa) {
foreach (var a in sa) {
print_simple_types (a);
}
}
void main () {
func<int> ({1,2,3});
}
```
`error: GVariant serializa...Simple Example
```vala
void print_simple_types (Variant v) {
...
}
void func<G> (G[] sa) {
foreach (var a in sa) {
print_simple_types (a);
}
}
void main () {
func<int> ({1,2,3});
}
```
`error: GVariant serialization of type 'G' is not supported`
This will require a bunch of runtime checks and obviously asserts if an unsupported type is passed. It will be restricted to supported GType.https://gitlab.gnome.org/GNOME/vala/-/issues/816SIGABRT on generic struct with string2020-04-11T21:48:19Zgavrgavr123456789@gmail.comSIGABRT on generic struct with string```vala
public struct Pair<T,G> {
T v0;
G v1;
Pair (T v0, G v1) {
this.v0 = v0; this.v1 = v1;
}
Pair.empty () {}
public T first () {
return v0;
...```vala
public struct Pair<T,G> {
T v0;
G v1;
Pair (T v0, G v1) {
this.v0 = v0; this.v1 = v1;
}
Pair.empty () {}
public T first () {
return v0;
}
public G second () {
return v1;
}
}
public static int main(string[] args) {
var b = new Pair<int,string>(4,"test");
string s = b.second();
return 0;
}
```
got `free(): invalid pointer
fish: './template_struct' terminated by signal SIGABRT (Abort)`
I think the problem is with string because if write `int i = b.first();` then everything works fine.
Vala 0.44.5https://gitlab.gnome.org/GNOME/vala/-/issues/811Generic container SIGSEGV2020-04-11T21:48:56Zgavrgavr123456789@gmail.comGeneric container SIGSEGV```
var list = new ArrayList<int?>.wrap ({1,2,3});
```
display `terminated by signal SIGSEGV`
```
var list = new ArrayList<int>.wrap ({1,2,3});
```
works fine```
var list = new ArrayList<int?>.wrap ({1,2,3});
```
display `terminated by signal SIGSEGV`
```
var list = new ArrayList<int>.wrap ({1,2,3});
```
works finehttps://gitlab.gnome.org/GNOME/vala/-/issues/628Assuming Covariance for generics is unsound.2018-12-05T23:30:55ZBugzillaAssuming Covariance for generics is unsound.## Submitted by astrothayne@gmail.com
**[Link to original bug (#796291)](https://bugzilla.gnome.org/show_bug.cgi?id=796291)**
## Description
Given class A inherits from class B. And there is a generic class C, then vala's type syste...## Submitted by astrothayne@gmail.com
**[Link to original bug (#796291)](https://bugzilla.gnome.org/show_bug.cgi?id=796291)**
## Description
Given class A inherits from class B. And there is a generic class C, then vala's type system assumes that `C<A>` is a subclass of `C<B>` (C is covariant). However if C is contravariant the correct relationship should be that `C<B>` is a subclass of `C<A>`, and if C is invariant, then there is no relationship between `C<A>` and `C<B>`. See https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science).
If `C<T>` has a method that takes a parameter of type `T`, then if that method is called on a `C<A>` (runtime) as a `C<B>` (compile-time), then an object that isn't of type `A` might end up being used as an `A`.
As a concrete example:
```vala
class Parent: Object {
public int a;
public Parent(int a) {
this.a = a;
}
}
class Child: Parent {
public int b;
public Child(int a) {
base(a);
this.b = a+1;
}
public void foo() {
stdout.printf(@"b = $b\n");
}
public static int main(string[] args) {
var list = new List<Child>();
list.append(new Child(1));
test(list);
list.foreach((entry) => {
stdout.printf(@"entry $(entry.a)\n");
entry.foo(); // oops!
});
return 0;
}
}
void test(List<Parent> list) {
list.append(new Parent(5));
}
```
When `foo` is called on the second entry of the list, it will print garbage (or maybe segfault), because the `Parent` class doesn't have a `b` field.
Maybe there is a good reason for this, and I don't know of a great way to remedy it without breaking backwards compatibility. But I haven't seen any comments about this issue in the documentation, and at the very list there should be a clear warning in the documentation for generics about the danger of assuming covariance.
Version: 0.36.x1.0https://gitlab.gnome.org/GNOME/vala/-/issues/620Non-null mode allows a constructor to have null assigned to a non-nullable ge...2021-03-09T07:31:35ZBugzillaNon-null mode allows a constructor to have null assigned to a non-nullable generic field## Submitted by Al Thomas `@astavale`
**[Link to original bug (#793912)](https://bugzilla.gnome.org/show_bug.cgi?id=793912)**
## Description
In the example below the int, string and class fields all need to marked nullable with '?' ...## Submitted by Al Thomas `@astavale`
**[Link to original bug (#793912)](https://bugzilla.gnome.org/show_bug.cgi?id=793912)**
## Description
In the example below the int, string and class fields all need to marked nullable with '?' when compiling with --enable-experimental-non-null.
When the field is of a generic type non-null mode still picks the field is not nullable when a null assignment is made in the main() block. When this is done in the constructor, however, it is not picked up by the checker.
```
void main () {
var a = new Test<MyClass> ();
a.int_field = null;
a.string_field = null;
a.my_class_field = null;
// a.my_generic_field = null; // Produces "Assignment: Cannot convert from `null' to `MyClass'"
}
class Test<T> {
public int? int_field;
public string? string_field;
public MyClass? my_class_field;
public T my_generic_field; // Should be 'public T? my_generic_field' for this code to compile
public Test () {
int_field = null;
string_field = null;
my_class_field = null;
my_generic_field = null; // Should produce "Assignment: Cannot convert from `null' to `MyClass'"
}
}
class MyClass {}
```1.0https://gitlab.gnome.org/GNOME/vala/-/issues/612Vala's pointer based generics system should not compile when used with an arr...2020-05-27T04:13:53ZBugzillaVala's pointer based generics system should not compile when used with an array of value types## Submitted by fsb..@..dex.ru
**[Link to original bug (#792534)](https://bugzilla.gnome.org/show_bug.cgi?id=792534)**
## Description
Consider the code:
```vala
/* file test.vala */
void main() {
int[] numbers = { 10, 30, 1, 8, -5...## Submitted by fsb..@..dex.ru
**[Link to original bug (#792534)](https://bugzilla.gnome.org/show_bug.cgi?id=792534)**
## Description
Consider the code:
```vala
/* file test.vala */
void main() {
int[] numbers = { 10, 30, 1, 8, -5, 7, 666, 12 };
foreach (int a in numbers) { stdout.printf("%d ", a); }
stdout.printf("\n");
qsort_with_data`<int>`(numbers, sizeof(int), (a, b) => { return a == b ? 0 : a < b ? -1 : 1; });
foreach (int a in numbers) { stdout.printf("%d ", a); }
stdout.printf("\n");
}
```
If you will compile it with the command:
`valac -X -fsanitize=address -X -fsanitize=undefined -X -fsanitize=leak -X -fno-omit-frame-pointer test.vala`
You will get the output:
```
(linux mint, gcc-7, valac 0.36.8)
10 30 1 8 -5 7 666 12
/usr/share/vala-0.36/vapi/glib-2.0.vapi:5714:11: runtime error: load of misaligned address 0x60300000efb4 for type 'const `<unknown>` *', which requires 8 byte alignment
0x60300000efb4: note: pointer points here
0a 00 00 00 1e 00 00 00 01 00 00 00 08 00 00 00 fb ff ff ff 07 00 00 00 9a 02 00 00 0c 00 00 00
^
/usr/share/vala-0.36/vapi/glib-2.0.vapi:5714:11: runtime error: load of misaligned address 0x60300000efc4 for type 'const `<unknown>` *', which requires 8 byte alignment
0x60300000efc4: note: pointer points here
fb ff ff ff 07 00 00 00 0c 00 00 00 9a 02 00 00 02 00 00 00 ff ff ff 02 20 00 00 00 01 00 00 7a
^
-5 1 7 8 10 12 30 666
or if you use FreeBSD, you will get:
0 30 1 8 -5 7 666 12
/root/MyProjects/test.vala.c:68:28: runtime error: load of misaligned address 0x603000000314 for type 'gconstpointer' (aka 'const void *'), which requires 8 byte alignment
0x603000000314: note: pointer points here
0a 00 00 00 1e 00 00 00 01 00 00 00 08 00 00 00 fb ff ff ff 07 00 00 00 9a 02 00 00 0c 00 00 00
^
SUMMARY: AddressSanitizer: undefined-behavior /root/MyProjects/test.vala.c:68:28 in
/root/MyProjects/test.vala.c:68:19: runtime error: load of misaligned address 0x603000000324 for type 'gconstpointer' (aka 'const void *'), which requires 8 byte alignment
0x603000000324: note: pointer points here
fb ff ff ff 07 00 00 00 0c 00 00 00 9a 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
^
SUMMARY: AddressSanitizer: undefined-behavior /root/MyProjects/test.vala.c:68:19 in
-5 1 7 8 10 12 30 666
```
If you sort arrays with Posix.qsort, you will not receive sanitizer errors.
Version: 0.36.x
### See also
* [Bug 791556](https://bugzilla.gnome.org/show_bug.cgi?id=791556)
* [Bug 663251](https://bugzilla.gnome.org/show_bug.cgi?id=663251)https://gitlab.gnome.org/GNOME/vala/-/issues/610Generic type problem when passing a delegate to a base constructor2019-11-04T15:05:46ZBugzillaGeneric type problem when passing a delegate to a base constructor## Submitted by kos..@..ex.com
**[Link to original bug (#792355)](https://bugzilla.gnome.org/show_bug.cgi?id=792355)**
## Description
code:
```vala
public abstract class LambdaObject<G> : Object {
public LambdaObject (G g, Func<G> ...## Submitted by kos..@..ex.com
**[Link to original bug (#792355)](https://bugzilla.gnome.org/show_bug.cgi?id=792355)**
## Description
code:
```vala
public abstract class LambdaObject<G> : Object {
public LambdaObject (G g, Func<G> func) {}
public void method (G g, Func<G> func) {}
public virtual void virtual_method (G g, Func<G> func) {}
}
public class IntLambdaObject : LambdaObject<int> {
public IntLambdaObject () {
// argument 1 is fine.
// but an error occurs at argument 2 : Cannot convert ...
base(123, int_func);
// passing to a non-constructor method is fine.
method(123, int_func);
}
public override void virtual_method (int g, Func<int> func) {
// passing to a non-constructor base method is also fine.
base.virtual_method(123, int_func);
}
public void int_func (int g) {}
}
void main () {
var obj = new IntLambdaObject();
}
```
output:
```shell
test.vala:11.13-11.20: error: Argument 2: Cannot convert from `void IntLambdaObject.int_func (int)' to `void GLib.Func`<G>` (G)'
```
Version: 0.38.xhttps://gitlab.gnome.org/GNOME/vala/-/issues/564Generics are broken with non-pointer types2023-04-21T14:27:12ZBugzillaGenerics are broken with non-pointer types## Submitted by Colomban Wendling `@ban`
**[Link to original bug (#774713)](https://bugzilla.gnome.org/show_bug.cgi?id=774713)**
## Description
Generic support for fundamental value types like int, long, double, float, or even enum ...## Submitted by Colomban Wendling `@ban`
**[Link to original bug (#774713)](https://bugzilla.gnome.org/show_bug.cgi?id=774713)**
## Description
Generic support for fundamental value types like int, long, double, float, or even enum and flags is currently broken when `sizeof(gpointer) != sizeof(G)`.
The problem is easy to understand: Vala uses `gpointer` as the C type for generics, but fundamental value types do not necessarily work with that.
There are good examples of the problem e.g. in libgee's https://bugzilla.gnome.org/show_bug.cgi?id=597737 and https://bugzilla.gnome.org/show_bug.cgi?id=774669.
Even simple code like this will have problem if `sizeof(G) > sizeof(gpointer)`, as the value will be truncated:
```vala
G value_generic<G>(G x) {
return x;
}
```
calling `value_generic<int64>(4200000000000000000)` on a 32 bits architecture will not result in the expected `4200000000000000000`. FWIW, with GCC's -m32 on a Linux x86_64, it gives me `1487142912`.
However, this part isn't *too* problematic, as it only applies for types larger than `gpointer`, and, on x86, only when the value actually is larger: `value_generic<int64>(42)` actually works as the truncation doesn't lose anything relevant.
But it gets real problematic when doing more subtle things, like libgee's Collection.to_array(): creating an array of Gs:
```vala
G[] array_generic<G>(G x) {
G[] y = new G[2];
y[0] = x;
y[1] = x;
return y;
}
```
The problem is that it is expected that using array_generic`<int>`() would be the same as replacing every occurrence of `G` in the definition with `int`. But it is not, it actually is `gpointer`, so the function creates an array of `gpointer`s, which on an x86_64 Linux doesn't have the same layout as an array of `int`s (`int`s being 4 bytes, and pointers 8). So the array returned by `array_generic<int>()` *cannot* be used as an `int[]`. Worse, if the generic type is larger than `gpointer`, it'll result in a too small array the caller will happily access outside its actual bounds.
libgee worked around *some* of the issue in its `Collection.to_array()` implementation by special-casing most fundamental value types (`char`, `uchar`, `int`, `uint`, etc.), and providing an implementation actually working on those specific types -- see https://git.gnome.org/browse/libgee/tree/gee/collection.vala#n158 However, they missed enumerations and flags -- see https://bugzilla.gnome.org/show_bug.cgi?id=774669 -- which are actually trickier to support (see below).
I unfortunately don't see a proper solution for the issue, at least not one that would be mostly compatible and fix everything. Maybe using `GValues` for passing the generics by value would slightly help. Or always use the largest possible type for them instead of `gpointer`?
For the array part, it could probably be hacked around manually playing with the memory: all it really requires is knowing the size of the type, and probably the layout of the actually used type in memory (`gpointer` currently). Then, generics could use convoluted logic like that:
```c
gpointer* array_generic (GType T, ..., gpointer x) {
guint8* result = g_malloc0_n (n, size_of_T);
memcpy(result + size_of_T*0, (guint8*) x, size_of_T);
memcpy(result + size_of_T*1, (guint8*) x, size_of_T);
return (gpointer*) result;
}
```
so, so long as the caller casts it back to the real type, it would work -- unless `size_of_T` is larger than `gpointer`, again. Reading `x` might require some slightly more convoluted code though if the relevant part of the value isn't packed at the start of the `gpointer`, but that would be doable too knowing enough about the platform I guess.
Another possible simpler/safer solution would be doing the same as libgee's in the compiler itself: emit specialized versions to be used for basic types. It would result in larger generated code, but it might be worth it. But it still doesn't really work good when `sizeof(G) > sizeof(gpointer)` as some truncation will occur passing some data as `gpointer`s (here, the `x` argument).
Supporting enumerations and flags is even trickier, because their actual type size is trickier to know. GCC will use `int` when it can, but will happily switch to a larger type if the enumeration has values larger than what an `int` can represent. And this means we need to know the *actual* size of the enumeration to properly support that. Would it be a property on GEnumClass it would be easy. But unfortunately it isn't, and worse, GEnumClass doesn't actually really support enums larger than `int` (as minimum and maximum are `int`s, it's impossible to even guess the required size).
So… maybe it's good enough to support them only when their size `== sizeof(int)`? Not sure, but at least it would work in *most* cases.
In the end, I guess the most realistic short-term solution would be using something like libgee's approach. But I have no good idea for a perfect long-term solution.
Version: 0.34.x
### See also
* [Bug 663251](https://bugzilla.gnome.org/show_bug.cgi?id=663251)1.0https://gitlab.gnome.org/GNOME/vala/-/issues/557[CCode(simple_generics = true)] generates invalid C code2020-04-06T13:43:54ZBugzilla[CCode(simple_generics = true)] generates invalid C code## Submitted by Matthias Berndt
**[Link to original bug (#772209)](https://bugzilla.gnome.org/show_bug.cgi?id=772209)**
## Description
Hey,
when declaring a function e. g. like this:
```vala
[CCode(simple_generics = true)]
extern G...## Submitted by Matthias Berndt
**[Link to original bug (#772209)](https://bugzilla.gnome.org/show_bug.cgi?id=772209)**
## Description
Hey,
when declaring a function e. g. like this:
```vala
[CCode(simple_generics = true)]
extern GLib.HashTable<K, V> g_hash_table_ref<K, V>(GLib.HashTable<K, V> ht);
```
The generated C prototype will look like this:
```c
GHashTable* g_hash_table_ref (GType k_type, GBoxedCopyFunc k_dup_func, GDestroyNotify k_destroy_func, GType v_type, GBoxedCopyFunc v_dup_func, GDestroyNotify v_destroy_func, GHashTable* ht);
```
But because of the simple_generics attribute, at the call site only a single argument (i. e. the hash table) will be passed. The resulting C code can not be compiled due to this.
Version: 0.32.xhttps://gitlab.gnome.org/GNOME/vala/-/issues/453Cannot implement next_value style iterator with generics2018-05-22T15:10:30ZBugzillaCannot implement next_value style iterator with generics## Submitted by Evan Nemerson
**[Link to original bug (#731311)](https://bugzilla.gnome.org/show_bug.cgi?id=731311)**
## Description
Created attachment 277983
test case
I was just playing around with adding a GLib.HashSet type and ...## Submitted by Evan Nemerson
**[Link to original bug (#731311)](https://bugzilla.gnome.org/show_bug.cgi?id=731311)**
## Description
Created attachment 277983
test case
I was just playing around with adding a GLib.HashSet type and I wanted to implement the iterator interface so it would work with foreach, but I run into this problem: "error: return type of `GLib.HashSetIter.next_value' must be nullable". It is nullable :(
Test case attached.
**Attachment 277983**, "test case":
[test.vala](/uploads/59ab7f672b76095c949f235c74d52247/test.vala)https://gitlab.gnome.org/GNOME/vala/-/issues/413Missing cast for g_value_set_pointer() on generic property value2019-01-07T15:57:01ZBugzillaMissing cast for g_value_set_pointer() on generic property value## Submitted by Philip Withnall `@pwithnall`
**[Link to original bug (#710863)](https://bugzilla.gnome.org/show_bug.cgi?id=710863)**
## Description
If a generic class (with type parameter `T`) has a property of type `T`, the generat...## Submitted by Philip Withnall `@pwithnall`
**[Link to original bug (#710863)](https://bugzilla.gnome.org/show_bug.cgi?id=710863)**
## Description
If a generic class (with type parameter `T`) has a property of type `T`, the generated C code will use `g_value_[get|set]_pointer()` for the property marshalling. However, it will pass the value from the property’s getter method (which has return type gconstpointer) into `g_value_set_pointer()`, which takes a `gpointer`. This means GCC will complain about discarding the const qualifier from the pointer because Vala is violating the C type system.
For example:
```vala
public abstract class Folks.AbstractFieldDetails<T> : Object
{
public virtual T @value
{
get { return this._value; }
construct set { this._value = value; }
}
}
```
generates the following:
```c
static void _vala_folks_abstract_field_details_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) {
…
switch (property_id) {
case FOLKS_ABSTRACT_FIELD_DETAILS_VALUE:
g_value_set_pointer (value, folks_abstract_field_details_get_value (self));
break;
…
}
}
gconstpointer folks_abstract_field_details_get_value (FolksAbstractFieldDetails* self) {
g_return_val_if_fail (self != NULL, NULL);
return FOLKS_ABSTRACT_FIELD_DETAILS_GET_CLASS (self)->get_value (self);
}
```
This is with Vala 0.22.0.26-f79fe.https://gitlab.gnome.org/GNOME/vala/-/issues/376Vala ignores the generics during type checking2021-02-19T13:33:23ZBugzillaVala ignores the generics during type checking## Submitted by Maciej Marcin Piechotka `@mpiechotka`
**[Link to original bug (#700142)](https://bugzilla.gnome.org/show_bug.cgi?id=700142)**
## Description
Created attachment 243870
0001-Check-the-generic-types-while-checking-the-s...## Submitted by Maciej Marcin Piechotka `@mpiechotka`
**[Link to original bug (#700142)](https://bugzilla.gnome.org/show_bug.cgi?id=700142)**
## Description
Created attachment 243870
0001-Check-the-generic-types-while-checking-the-subclasse.patch
Vala ignores the generics during type checking which can cause subtle, hard to find bugs.
For example current vala pass the following code while it doesn't after this patch:
```vala
class TestBase<A> {
}
class TestUp<A> : TestBase<A> {
public A field;
}
class Test2<G, H> : TestUp<Test2<G, H>> {
public G g;
public Test<H> h;
}
class Test<A> {
public void aaa (Test2<Test<A>, A> hash) {
hash.g = hash.h;
hash.field = hash;
set = hash;
set2 = hash; // This line should fail as Test<A> != A
}
private TestBase<Test2<Test<A>, A>> set;
private TestBase<Test2<A, A>> set2;
}
void main() {
}
```
~~**Patch 243870**~~, "0001-Check-the-generic-types-while-checking-the-subclasse.patch":
[0001-Check-the-generic-types-while-checking-the-subclasse.patch](/uploads/78992e777283a4de135dc629cf0ef013/0001-Check-the-generic-types-while-checking-the-subclasse.patch)1.0https://gitlab.gnome.org/GNOME/vala/-/issues/360Compact classes can silently leak memory2018-05-22T14:42:48ZBugzillaCompact classes can silently leak memory## Submitted by Maciej Marcin Piechotka `@mpiechotka`
**[Link to original bug (#695050)](https://bugzilla.gnome.org/show_bug.cgi?id=695050)**
## Description
Consider following case:
[Compact]
class LeakMemory`<G>` {
G g;
}
Lea...## Submitted by Maciej Marcin Piechotka `@mpiechotka`
**[Link to original bug (#695050)](https://bugzilla.gnome.org/show_bug.cgi?id=695050)**
## Description
Consider following case:
[Compact]
class LeakMemory`<G>` {
G g;
}
LeakMemory<Gtk.Widget>? lm = new LeakMemory<Gtk.Widget>();
lm.g = new Gtk.Window();
lm = null; // lm.g memory is freed, right?
Proposed solution:
- Add warning for old-style generics that contains generic fields
- Add attribute [GenericDtor] or similar (possibly [GenericMethods] as well) which allows to pass the generic attributes via arguments rather then store in class.