On 08/12/2012, at 9:41 AM, srean wrote: > > Thanks John for taking the time to explain this. > > I havent looked at them yet, will go over them on the weekend. But what > tripped me up when trying to read the source was all those "_GC@^&" and > other such cryptic stuff.
Don't try to read that kind of stuff yet:-) That's extremely technical magic which is typically highly implementation dependent. Roughly speaking: Felix uses an exact garbage collector. For every collectable type there is an RTTI object of type shape_t which describes the shape of the object. In particular it tells the size of the object, a string name of the object, how to finalise the object (usually the C++ destructor) and provides an array of offsets into the object where pointers are stored This offset array is used by the collector to trace pointers. You can find generated shape code in ~/.felix/cache/text/absolute/file/name.rtti for any compilation. For every Felix allocated object, the pointer to the storage P is associated with a shape object (RTTI). This is done with a separate data structure so as not to interfere with the layout of the object (unlike C++ RTTI which is embedded in the vtable, and the vtable pointer is embedded in the object). When you do an allocation you have to call like this in C++: new (gc, shape, mobility_flag) T (args) here gc is the garbage collector, shape is the shape associated with the type T, mobility_flag is a currently unused flag which tells if the object can be moved by a compactor, and T is the usual type name and args the constructor arguments. So when you're making an object type in Felix, such as Google RE2, and a few other things, which are uncopyable, and represented by pointers to heap allocated objects, you see bindings like: private type RE2_ = "::re2::RE2"; _gc_pointer _gc_type RE2_ type RE2 = "::re2::RE2*"; gen _ctor_RE2 : string -> RE2 = "new (*PTF gcp, @0, false) RE2($1)"; which basically says that type RE2 in Felix is a pointer to RE2 in C++, it is a GC trackable pointer (Felix needs to know that) and you make one by using shape @0 which is the shape of the constructor type. This is guru level magic. The bit you need to understand in the above is that gen _ctor_RE2: string -> RE2 means that you write this: RE2 "(ab)*abb" and you have a compiled regexp with Perl notation. A bit magical but _ctor_RE2 just means the same as ctor RE2 which just means "a constructor for type RE2" (although technically its a conversion operator not a type constructor). I had to use _ctor_RE2 here because I also wanted to tell the compiler its a generator not a function. Normally you'd write ctor RE2 but that is literally the same as _ctor_RE2 which is a special hack name for a constructor :) If you use a TYPENAME as a function, Felix looks for the function named: _ctor_TYPENAME Yet another piece of sugar :) A good example of this: type complex = "complex"; typedef cartesian = complex; typedef polar = complex; ctor cartesian : double * double = "complex($1, $2)"; ctor polar : double * double = "complex ($1 * cos ($2), $1 * sin ($2))"; So now you can write: polar ( 0.5, 0.3 * M_PI) for polar coords. Polar and cartesian and complex are all the same type. But now you have "named constructors" so you can get over C++ constructor overload hell. > So I need to know much more about Felix to be able to make sense of whats > going on. I do not know type classes, so these two mails of your will help. Type classes are based on Haskell type classes. A type class is just a collection of templates. A virtual function is a template declaration or definition. An ordinary function in a class is just a template definition. An instance of a type class provides a body for a template function declaration for particular type or types, in other words its just a (partial) specialisation. That's it. Its just template specialisations. There is one MAJOR difference between polymorphism in Felix and in C++ .. so listen up!! Felix does not allow unrestrained dependent name lookup. In other words this does NOT work: fun bad [T] ( a: T, b: T) => a + b; If you try that you WILL get a type error. You cannot add arbitrary types together! Almost all C++ is based on dependent name lookup, and it is VERY BAD. It destroys parametric polymorphism, and it means templates are basically just macros because the semantics depends on what is in scope at the point of use. This is EVIL! Instead, Felix makes you write this: class Addable[T] { virtual fun addem : T * T -> T; } fun bad[T with Addable[T] ] (a :T, b:T) => addem (a,b); That type checks, but as written fails at instantiation time if you write: bad (1,2); To fix this you have to write: instance Addable[int] { fun addem (x:int, y:int) => x + y; } to provide a specialisation of the addem template for int. When you write the function bad and say with Addable[T] that has the effect of injecting fun addem: T * T -> T into the scope of the function body so that the lookup on addem now works. The function no longer parametrically polymorphic: it is polymorphic SUBJECT TO A CONSTRAINT that the type must be Addable. In C++ they want this too, its called Concepts. Note that now, we have "well founded dependent name lookup". The name addem does depend on the type. But the interface clearly specifies the dependence. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial Remotely access PCs and mobile devices and provide instant support Improve your efficiency, and focus on delivering more value-add services Discover what IT Professionals Know. Rescue delivers http://p.sf.net/sfu/logmein_12329d2d _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language