Well, I have a found the source of this problem:

class Checked_ZeroMQ[T] {
  inherit ZeroMQ;
  open Errno::Check[T];
...
  proc bind(x:zmq_socket) (a:string) => int_to_proc$ zmq_bind(x,a);
...


  gen recv_strings (s:zmq_socket) : varray[string] = {
    var ss = Empty[string];
    var more = true;
    while more do 
      var r = recv_string s;
      ss= Cons (r,ss);
      more = zmq_more s;
    done
    return varray (rev ss);
  }
...

}

What happens is we end up with a virtual, ehandler (in Check[T]) without
an instance. This turns out to be correct, because T is set to void.

So I trapped all void instantiations:

Attempt to register instance 5707[void]
SYSTEM FAILURE
Attempt to instantiate type variable with type void

so I could find how the void got in there. When I ran the test harness I got an
unexpected failure:

 * build/release/bin/flx --test=build/release: 
build/release/test/regress/rt/intensional-polymorphism-01.flx -> 
build/release/test/regress/rt/intensional-polymorphism-01
 + build/release/bin/flx --static --output_dir=build/release/test/regress/rt 
-Ibuild/release/test/regress/rt --test=build/release -c --test=build/release 
build/release/test/regress/rt/intensional-polymorphism-01.flx
Attempt to register instance 12284[void]
SYSTEM FAILURE
Attempt to instantiate type variable with type void

So I looked at the code:

~/felix>cat   test/regress/rt/intensional-polymorphism-01.flx
// check for polyvars!
noinline fun poly[u] (px:&u, py:&u) => py,px;
var x = 1;
var y = 2;
var z = &x, &y;
var r = poly z;
println$ *r.(0), *r.(1);

var x2 = 1.1;
var y2 = 2.1;
var z2 = &x2, &y2;
var r2 = poly z2;
println$ *r2.(0), *r2.(1);

Now, in case you're wondering what all that is about:
Felix normally uses extensional polymorphism. This means
you actually replace a type variable with a type eg: 

        T --> int

in one case or

        T --> long

in another. The code for a function with these monomorphisations is
distinct, you get two functions generated.

OTOH many FPLs including Ocaml, and I presume Haskell, typically
use *intensional* polymorphism. This means you can have a single
function which handles all types.

These languages cheat by using boxing, and the trick that pointers
to different types are all the same size.

Felix has intensional polymorphism too! The requirement is that
you have only pointers to the type, and you never dereference them.

In that case, Felix cheats too: it silently changes the function to use a void*,
and then uses casts on the calls. This is, of course, exactly how C does
polymorphism.

In the above example, the two instances of "poly" use physically the same
code. This avoids code bloat. It also means (eventually) you can export
the function and it is truly intensionally polymorphic.

In fact, the Felix handling of this is more general: if a type variable is only
used "under the pointer" it is called a polyvar. Felix merges code for
functions based on polyvars. If two functions differ only in the type of
polyvars, the same physical function is used. [What I mean is that
if you have a two parameter function

        fun f[U,V] ..

and V is a polyvar, then f[Int,*] all use the same function but f[double,*]
use a different one .. it's not necessary that all type variables are
polyvars to get sharing.

So what, you may ask, has this got to do with the ZMQ bug???

~/felix>flx --test=build/release --static -c test/zmq/mtserver
Routine recv_strings<5707> has polyvars
Routine len<8132> has polyvars
Routine len<8144> has polyvars
Routine _lam_1697<23897> has polyvars
Routine fold_left'3<7707> has polyvars
Attempt to register instance 5707[void]
SYSTEM FAILURE
Attempt to instantiate type variable with type void

And there it is! Function 5707, recv_strings, has a polyvar.
This means the function is independent of the class type variable.

So the polyvar is set to void, and that causes the problem.

It is actually interesting, because it is WRONG in this case!

Let me explain:

class X[T] {
  fun f(x:int)=>x;
}

Here, T is a polyvar for f. Because ALL uses of T are "under the pointer".
It's true "in vaccuuo" since T isn't actually used in f at all!
It should be perfectly safe to set T to void, since T isn't used.

However, recv_strings DOES use the type variable indirectly,
by calling other functions that do. Because its inside a typeclass
the type variables aren't mentioned in the syntax .. but they should
be there. The problem seems to be this:


(* note this routine doesn't check types in ts lists, because
 * these apply to variables including parameters as qualifiers:
 * we're only interested in the actual types.
 *)

It would seem this is wrong. No other part of recv_strings uses T,
but routines it calls do. The T inherited from the type class is
not "transmitted" in AST ts lists, but it is there in the fully bound
code and that's teh connection. Recv_strings is NOT intensionally
polymorphic.

The REALLY fun thing here is that the type variable involved is a phantom!
It actually isn't used anywhere EXCEPT in ts lists! Its entire purpose
is to choose an instance of class Check[T].

--
john skaller
skal...@users.sourceforge.net





------------------------------------------------------------------------------
Keep Your Developer Skills Current with LearnDevNow!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-d2d
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to