Re: [Vala] non-gobject generics



On Fri, Aug 21, 2009 at 20:13:10 +0200, pancake wrote:
I have written a simple API in C for managing lists of pointers
which is going to
be used as a simple interface for iterators.

 http://radare.nopcode.org/hg/radare2/file/8e9c1ea44114/libr/util/iter.c

The same functions are written as defines in the iter.h file
libr/include/iter.h to
inline as much as possible by using the external lib.

This API works fine with the C example, but I tried to do the VAPI
implementing this
as a Generic compact class. The definition looks like:

   [Compact]
   [CCode (cprefix="r_iter_")]
   public class Iter<G> {

Radar.Iter is generic. We'll need to remember that later.

       public Iter (int size);

I thought it's an iterator, but it looks like it's a collection here. That
does not look like a good design, because it limits you to one iteration over
the collection at a time. Normally you have a collection and an iterator over
that collection which acts as index into that collection and you can create
any number of iterators in different states for each collection.

Also, we need to remember, that the only constructor takes an int argument.

[...]
       public unowned G get ();
       public unowned G next ();
       public unowned G next_n (int idx);
       public unowned G prev ();
       public void delete ();
       public G first ();

The get/next/prev above return unowned pointers. Why does this one return an
owned one?

       public bool last ();
       // TODO: foreach()
       public G free ();

If it is what the interface suggests (NULLs the pointer in the collection and
returns it) the GLib convention would be to call it "steal".

       public void set (int idx, G data);

Please, check whether the reference-counting you get here is sane. I believe
you have to take care of it inside the set method.

   }

Overall, the .vapi seems to be correct. None of the problems above is hard
error.

But I get this error while trying to compile the test program:
using Radare;

-------------------
public class IterableObject : Radare.Iter {

Radare.Iter was generic above, so it must be generic here too.
So either

public class IterableObject<G> : Radare.Iter<G>

or

public class IterableObject : Radare.Iter<Item>

       public string name { get;set; }

       public IterableObject(string name) {
               this.name = name;
       }

The base class has only constructor, one with an int argument. So you have to
pass that argument from your constructor. Like this:

        public IterableObject(string name, int number) : base(number) {

However, you would need to have a

void r_iter_construct(RadareIter *, int)

function in addition to

RadareIter *r_iter_new(int)

in your C API for that to work, because it needs to initialize RadareIter it
already allocated and the _new variant does not allow that.
(And it wouldn't work than anyway, as we'll see later)

}

Radare.Iter<IterableObject> get_iter_list ()
{
       Radare.Iter<IterableObject> list = new
Radare.Iter<IterableObject>(3);

Now you have an iterator of iterators (and a collection of collections).
Didn't you want to call the class "ItemObject" and not derive it from
Radar.Iter at all?

[...]
-------------------

pancake flubox:~/prg/radare2/libr/vapi/t$ valac iter.vala --pkg r_util
iter.vala:6.2-6.22: warning: unable to chain up to base constructor
requiring arguments
       public IterableObject(string name) {
       ^^^^^^^^^^^^^^^^^^^^^

As I mentioned above, you need to specify the argument to the base
constructor when all you have is a constructor with argument.

iter.vala:3.1-3.41: error: derived compact classes may not have
instance fields
public class IterableObject : Radare.Iter {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Hm, I didn't know about this, but it acutally makes sense.

Normally, classes have "constructor" whatever_new, which allocates and
initializes the class. However, that cannot be used for inheritance, where
you need to allocate the larger structure and call something to initialize
the base part of the already allocated data.

Normally the GType descriptor has a pointer to parameterless function, that
should be called to initialize the base class data. The compact classes don't
have this pointer, so Vala is not willing to extend them, because it can only
allocate them with the _new function.

Perhaps this restriction could be lifted when appropriate construct method
is defined also for the argument-less case. But in reality most [Compact]
classes are incomplete (i.e. the library does not expose the layout of the
struct). That allows the library to extend the structure without breaking the
API (because you can't depend on it's size or layout), but effectively
prevents deriving from it (because you can't include it in your derived
struct if you don't know it's layout).

However it's actually irrelevant in your case as there is actually no reason
to derive from a generic iterator.

Looks like vala does not supoprt to implement non-gobject (aka
compact) generic classes, or
at least i cannot inherit such methods from there.

Is this a bug? or I am doing something incorrect?

You are doing something incorrect. You are trying to derive your generic
class when all you should do it use it with appropriate type parameter.

There are some limitations inherent in what the C API allows and some
limitations that could be lifted when the C API is suitable, but 

-- 
                                                 Jan 'Bulb' Hudec <bulb ucw cz>



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