My next thoughts are directed towards two related problems:

1. How get Felix to link to Felix generated (binary) libraries
2. How get C/C++ to link to Felix generated (binary) libraries


For (1) we have a complete solution using plugins.
The result isn't typesafe (another job to examine that).
However this is run time linkage with a trick to preload plugins:
the interface is dynamic, you have to actively load and instantiate
libraries. 

That is, you have to design for plugins. You can refactor code
into a plugin and refactor calls to use it but the process is invasive
and non-trivial (it's not hard but its a task you have to actively do).

With exports we can make library binaries easily. The problem
is using them. Suppose I make a Felix library with exports in it.
Then assuming they're ordinary C functions, with C types
for arguments and results, to use the library you will need to at least

(a) link it
(b) link your program against it
(c) write bindings for it

Steps (a) and (b) aren't hard, and (b) can be eliminated with
the resource/package management system, so we're
left with (c).

Suppose your library has a function

        extern "C" int func(int);

you have to write a binding for it:

        fun func: int -> int;

It's not hard but you have to write it. In particular if you compile
this to an object file:

        export cfun func (x:int) => x;

that same binding is required. Easy for one function. But if you have
a library with 200 functions, one would like the bindings to be generated
automatically. After all, Felix knows the interfaces of all the exports!

But there is a problem: types. When you're linking to a C library, you
have no namespaces and you have no type-safe linkage. So, our
import file for the library which Felix could generate will work fine,
even if the C++ types used by the functions are NOT the same
as those used in the client program, as long as they're layout compatible.

Just a small back step: for plugins, we have to use C linkage, because you
cannot "dlsym()" or "GetProcAddress()" a C++ function name, because 
those names are mangled in a non standard way that is hard to discover.

For static linkage, C linkage omits type information, so we only need
the name of the function, and to get use compatible types. For example
in Felix

        struct X { x:int; y:int; }
        export cfun xproj (a:X) => a.x;

will make a C function, and to use it we can write:

        struct Y { x:int; y:int; }
        fun xproj: Y -> int;

This will work, even though X and Y are not the same type. In fact
just changing the name Y to X will not make any difference because
Felix mangles type names in an impure way, that is, the mangled
names are not deterministic. In fact Felix uses a counter to ensure
names are unique, so the same type in any two programs will
have different C++ names unless the counter "happens" to be the
same when the name is generated.

So now, if flxg is made to generate

        filename_interface.flx

containing all the exported functions, everything is just fine PROVIDED
all the functions are "cfun" or "cproc" and all the arguments are
in the standard library.

If a function uses a type like the struct X above, things get much harder.
We would have to put the definition in the interface.flx file, and in particular
we would have to NOT define it in the client.

How far can we take this? The answer is: all the way, but it isn't
simple! If the function uses some complicated Felix type involving
unions, structs, function values, etc, it's NOT trivial to export
all the type definitions, because we have to AVOID exporting
things that will be shared, such as standard library types
like strings, ints and floats -- but not limited to those!

One way to fix that is delegation. By which I mean, we require
the program to write a file with type definitions in it for sharing,
and include that file in both the library and the client.
After all that's what the standard library does! It gets shared!

So now, we have one remaining problem here: if the function
isn't a C function, but a Felix function:

        export fun .....

then the C wrapper generated requires the libraries "thread frame"
object to be passed as the first argument. Plugins take care of that:
they create the thread frame (library instance) and provide closures
which have the instance bound in.

Unlike C, there's no "static global" variables, so there is no way to 
"merge" global variables. At best the client thread frame contains
a pointer to the library thread frame (which the client has to create)
that is passed as the first argument.

Now, you may say, well just use all "cfun"s. The problem is you can't.
If the function uses the GC it HAS to get at the thread frame to find
the collector. The collector is not to be found in a global variable.
Nothing in Felix uses C++ global variables (except library code
that has to use crap from C/C++/Posix like errno, or do signal handling).

So now, lets ask another question.. can we CHEAT???

I want to explain what I mean: can we pass the library functions
the clients thread frame?? Instead of the one it is suppose to have?

The answer is "layout compatibility". Again. All thread frames have the
same initial data members: argv, argc, pointers to stdin,stdout, stderr
and the GC.

So provided the client function doesn't need any OTHER data, this
will "just work".  So now we have a rule: we can use those funs with
the wrong thread frame provided they do not try to access anything
in the thread frame specific to the library (directly or indirectly).

So what else goes in the thread frame???

Global variables. 

******************************************************************
So -- cheating is safe if and only iff the library doesn't have any
global variables.
*******************************************************************

Is that a draconian restriction? Absolutely! It is a very tight and
very good restriction. It's a basic principle:

        Principle of Explicit Coupling

You should always do this. NEVER use global variables.

There's a problem though! Not all variables are variable :)

Global constants are OK in principle. It's a problem if they
require construction (order of initialisation problem).

However if we have global constants we cannot cheat!

Bottom line here: I think I will try it. I can figure out ways to warn
if the constraints are broken later. Its an issue in Felix at the
moment that not all constraints that could be enforced by the
compiler actually are. 

I will deal with (2) in a separate email.



--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT 
organizations don't have a clear picture of how application performance 
affects their revenue. With AppDynamics, you get 100% visibility into your 
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to