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

Re: Swig and MzScheme's _scheme_get_type_name



Matthew Flatt wrote:
> 
> Quoting Paul Fernhout:
> > This was because "_scheme_get_type_name" can't be found by the linker.
> > Any thoughts on what I might be doing wrong?
> 
> It is not exported by the MzScheme/MrEd binaries for Windows, though it
> should be. 

Thanks for looking into this.

> As an aside, I'm uneasy about the way SWIG is checking types:
> 
>  void *swig_get_c_pointer(Scheme_Object *so, char *c_type) {
>     Scheme_Type st = SCHEME_TYPE(so);
>     //char *type_name = scheme_get_type_name(st);
>     //if(strcmp(type_name, c_type))
>     //scheme_signal_error("wrong type in foreign object %s", type_name);
> 
>     return (void *) ((swig_proxy *) so)->object;
>  }
> 
> What if an extension accidentally choose a name for a type that
> MzScheme or some other extension is already using? The type id returned
> by scheme_make_type() is guranteed to be unique, but the type name is
> not.
> 
> Maybe this is an unavoidable compromise in SWIG's design, though.

As usual, your insight is very helpful.

Based on that, I made this patch which I use to replace the two
functions which puts back in type checking. I apply it by hand for now.
Also, it relies on the fact I only have one new type defined in my
Swigged file. I tested it and it seems to work (it assumes of
Scheme_Type of 0 is invalid...)

======================================================
Scheme_Type pointrel_type = 0;

// NEXT FUNCTION IS ACTUALLY BROKEN, SEE BELOW
Scheme_Object *swig_make_c_pointer(void *c_pointer, char *type_name) {
    swig_proxy *new_proxy;
    new_proxy = (swig_proxy *) scheme_malloc(sizeof(swig_proxy));
    new_proxy->type = scheme_make_type(type_name);
    if (0 == pointrel_type) pointrel_type = new_proxy->type; 
    new_proxy->object = (void *) c_pointer;

    return (Scheme_Object *) new_proxy;
}

void *swig_get_c_pointer(Scheme_Object *so, char *c_type) {
    Scheme_Type st = SCHEME_TYPE(so);
     if (pointrel_type != st)
      scheme_signal_error("wrong type in foreign object expecting %s",
c_type);

    return (void *) ((swig_proxy *) so)->object;
}
======================================================

I don't see any obvious reason why Swig could not do something like
this, although it might require storing each type in a variable in some
sort of registration step, and passing in the stored type index instead
of the name in calls to swig_get_c_pointer.

Actually, as I write this I think Swig is actually abusing
"scheme_make_type" in that it calls "swig_make_c_pointer" and thus
"scheme_make_type" each time an instance of the type is made. Based on
what you are saying, perhaps the ID comes back different each time? If
that is true, it worked in my test as I only made one instance. 

What I think I really want then in my patch for that function is:

======================================================
Scheme_Object *swig_make_c_pointer(void *c_pointer, char *type_name) {
    swig_proxy *new_proxy;
    new_proxy = (swig_proxy *) scheme_malloc(sizeof(swig_proxy));
    if (0 == pointrel_type) pointrel_type = scheme_make_type(type_name);
    new_proxy->type = pointrel_type;
    new_proxy->object = (void *) c_pointer;

    return (Scheme_Object *) new_proxy;
}
=======================================================

I just compiled and tested this and it works, even for two creations of
the type.

I went back and tested the first version and it fails if I make a second
of the type. So the second version is correct and required.

So, Swig out of the box looks broken in this way...

-Paul Fernhout
Kurtz-Fernhout Software 
=========================================================
Developers of custom software and educational simulations
Creators of the Garden with Insight(TM) garden simulator
http://www.kurtz-fernhout.com