[Vala] Difficulty in using the managed string and array and workarounds.



Dear friends,

Yesterday or so I was attempting to rewrite a piece of my little project
in C+GLib to VALA. It heavily utilizes string operation and array
operation. 

Eventually I failed in the attempt. What I found is, I have to use weak
string everywhere, and I have to workaround the array duplication. I am
not satisified with the quality of VALA generated ccode.

The VALA program I end up with is like this, and I'll comment out the
problem I met and the way I solved them. Perhaps they are due to my
lacking of knowledge of VALA, or perhaps they are due to problems with
vala.

namespace GdaKit {
        class Object: GLib.Object {
            // Each object can be created with a string. Therefore there have to be
            // a property for it because vala doesn't allow anything other than
            // initializing properties in the _new operator.
            // However a property shouldn't return any strong string. therefore I have to 
            // keep a private copy of the string with the object.
                private string str_;
                public weak string str {
                        get {
                                str_ = to_string();
                                return str_;
                        }
                        set {
                                from_string(value);
                        }
                }
                protected virtual string to_string() {
                        return "";
                }
                protected virtual void from_string(string str) {

                }
        }
        interface Quantity {
                public abstract bool equal(Quantity q);
                public abstract int cmp(Quantity q);
                public abstract uint hash();
        }
        class Point: Object, Quantity {
                // A GObject property can only contains 1 value.
                // An array in VALA has two values. 
                // Therefore I have to workaround the limitation by
                // declare two properties for the array.
                private double [] positions_;
                private int dimensions_;
                public int dimensions {
                        get {
                                return dimensions_;
                        } 
                        set {
                                dimensions_ = value;
                                positions_ = new double[value];
                        }
                }
                // It doesn't make sense for a property to take the ownership
                // Therefore coping is a must.
                public double []positions {
                        get {
                                return positions_;
                        }
                        set {
                                for(int i=0; i<dimensions; i++)
                                        positions_[i] = value[i];
                        }
                }
                // Finally the _new builders are happy.
                public Point.at (double [] positions) {
                        dimensions = positions.length;
                        this.positions = positions;
                }
                public Point.import(string str) {
                        this.str = str;
                }
                // Notice the weird looking return in to_string().
                protected override string to_string() {
                        StringBuilder sb;
                        int i;
                        for(i = 0; i< this.dimensions - 1; i++){
                                sb.append_printf("%lf ", this.positions[i]);
                        }
                        sb.append_printf("%lf", this.positions[i]);
                    // I have to cheat by duplicating sb.str to a local variable,
                    // and let return to take the ownership of s.
                    // return doesn't know how to directly take the ownership of 
                    // StringBuilder.str with g_string_free(sb, FALSE);
                   
                        string s = sb.str;
                        return s;
                }
                // To get this compiled, I have to modify glib-2.0.vapi as described in
                // http://bugzilla.gnome.org/show_bug.cgi?id=548550
                // Another way is to do everything with strong.
                // It seems that VALA is wise enough to strdup the out_ptr.
                // However a lot of strdup is slow, and will enlarge the footprint of vala 
                // programs.
                protected override void from_string(string str){
                        weak string s = str;
                        weak string end_ptr = null;
                        int dimensions = 0;
                        while(true) {
                                s.to_double(out end_ptr);
                                if((void*) s == (void*) end_ptr) break;
                                s = end_ptr;
                                dimensions ++ ;
                        }
                        this.dimensions = dimensions;
                        s = str;
                        for(int i = 0; i< dimensions; i++){
                                positions[i] = s.to_double(out s);
                                dimensions ++ ;
                        }
                }
                public bool equal(Quantity o){
                        return (cmp(o) == 0);
                }
                public int cmp(Quantity o){
                        assert(o is Point);
                        assert (this.dimensions != ((Point)o).dimensions);
                        if( o == this) return 0;
                        int i;
                        for(i = 0; i < this.dimensions; i++){
                                if(this.positions[i] < ((Point)o).positions[i]) return -1;
                                if(this.positions[i] > ((Point)o).positions[i]) return 1;
                        }
                        return 0;
                }
                // In the old C code I was using union GDoubleIEEE754.mantissa_low to get the numbers
                // it is missing in VALA.
                public uint hash() {
                        int i;
                        double pp = 0.0;
                        for(i = 0; i < this.dimensions; i++){
                                double p = positions[i];
                                int e;
                                pp += Math.frexp(p,out e);
                        }
                       // No automatic conversion at return. I like this feature.
                        uint rt = (uint) (pp * uint.MAX);
                        return rt;
                }
          }
 }


The core of the problems is still related to the memory management of
non-ref-counted objects. I have an idea that may kill the problem
completely but may make no sense at all.

Given that 
(1) Vala is a language for GLib programming
(2) GLib doesn't show any interest in managing array and string and
boxed structures
by not providing and reference counting thing
(3) non-ref-counted objects (array and string) are with variable length
and tend to frag the memory. They are dirty.
(4) implementing all the quirk to for non-ref-counted objects in VALA
compiler makes the compiler dirty.
(5) To dump all the dirtiness to an optimizer after the compilation is
hard if not impossible.

Why should Vala provide the management at all?

The best way to kill the dirt is to make them weak, and provide a 'new',
a 'delete' operator and let the programmer do the dirty job by hand.

I agree that full automatic memory management IS awesome. But when the
full automatic management becomes a non-intuitive and when people have
to guess how it behaves, in order to write non-buggy code, perhaps it is
better to make it a partial one.

Yu






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]