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