GNOME Bugzilla – Bug 589604
Constructors cannot get class-specific variables
Last modified: 2010-03-26 19:58:32 UTC
The following code fails to compile at C time. The 'default' argument passing is done by the caller and not by the class itself. This bug can bring problems while using variable names instead of const values like literal strings or numeric values. ------------- class Foo { string file; Foo(string filename) { this.file = filename; } /* no error at compile time??? */ public void foo(string file = this.file) { stdout.printf("%s\n", file); } } void main() { var foo = new Foo("patata"); foo.foo(); } ------------- In this case, the generated code is: void _main (void) { Foo* foo; foo = foo_new ("patata"); foo_foo (foo, self->priv->file); (foo == NULL) ? NULL : (foo = (foo_unref (foo), NULL)); } ----------- Which is trying to pass the value self->priv->file which doesnt exists out of the class. The correct way to do this is (IMHO) pass 'null' to the function when the argument is not the a string or number and then add a initial stub on the calling function checking for null and then setting the correct value. This brings the problem of the '?' nullable arguments...so probably the good way to do this would be to add a "hidden" method to the class doing this trampoline and calling it to prepare the correct arguments for the endpoint function.
The name of this bug doesnt reflects the problem itself. A correct description of the problem would be something like: "Default parameters accessing instance variables are not supported" The compiler (vala) should call the class method passing the value of the object itself instead of the one in the caller instance. Which in the case of the example doesnt exist.
Created attachment 152105 [details] [review] Fix some self usage in default expression Fixes bug 589604.
Your patch works for me, somebody to review and push it into mainstream? NOTE: to compile my example the constructor must be public.
The patch causes problems if the instance expression has side-effects as in the following example: class Foo { string file; public Foo(string filename) { this.file = filename; } /* no error at compile time??? */ public void foo(string file = this.file) { stdout.printf("%s\n", file); } } Foo get_foo () { message ("side-effect"); return new Foo ("patata"); } void main() { get_foo ().foo(); }
There are more problems, the above code should still be invalid as `file` is a private field and default arguments are applied on the caller side. As default arguments for libraries are actually stored in .vapi files, allowing arbitrary expressions doesn't sound like the right thing to do. I think we should not even support this, and only allow constant expressions as default arguments. With nullable support, it's always possible to implement this on the callee-side with more flexibility. We currently use this in vapi files to make bindings more convenient. It should be possible to rewrite most of them with inline vapi methods, however, it's a bit more complex, so we might want to keep it supported in bindings for now. We should report an error when using non-constant values in actual code, though.
Thanks for the bug report. This particular bug has already been reported into our bug tracking system, but please feel free to report any further bugs you find. *** This bug has been marked as a duplicate of bug 531428 ***