The linked commit introduces coroutines in the Eiffel world.
The concept is implemented in the Liberty repository, but that should work in a pristine SmartEiffel too.
Enjoy!
Sunday, December 26, 2010
Friday, September 17, 2010
I was told Eiffel wasn't like C++...
Many Eiffel enthusiasts - I shall put myself in the group - often write about the many pros of our beloved language when compared to C++.
One of those aspects that I was sure Eiffel handled better than C++ was templates, known as generics in Eiffel.
C++ templates has been often accused to lead to code bloat and large executable, since the compiler generates specialized code for each type used in a template.
As an example when you use QList as QList<int>, QList<MyClass*>, QList<AnotherClass*> you will end up having three specialized copies of each and every function defined in QList, a class that has more than seventy functions.
This justify why C++ executables are often considered "fat".
I don't know why but I have been always convinced that generics in Eiffel didn't show this pattern.
SmartEiffel proved me wrong.
I suspected it compiling my own wrappers-generator and getting a 5,2 Mb executable from more or less 4450 lines of code as reported by command "wc".
Ehi! This is more than 1200 bytes of binary code for each and every Eiffel line, empty lines and comments included!
No, my coding style can't be so awesome and this tool is nothing special.
It just shall not be this big.
So I dived into generated source code.
At the beginning of wrappers_generator.id which contains a description of the compiled classes from the C and Eiffel compiler point of view I can read something like:
478 "HASHED_DICTIONARY[XML_DTD_ATTRIBUTE,UNICODE_STRING]" l
#
555 "HASHED_DICTIONARY[COMPOSED_NODE,UNICODE_STRING]" l
#
404 "HASHED_DICTIONARY[WEAK_REFERENCE[ANY_LINKED_LIST_NODE],STRING]" l
#
467 "HASHED_DICTIONARY[RECYCLING_POOL[PROTOCOL],STRING]" l
#
365 "HASHED_DICTIONARY[POINTER,STRING]" l
So I looked into wrappers_generator_T478.c wrappers_generator_T555.c wrappers_generator_T467.c wrappers_generator_T365.c which are the C code containing the translations for those.
Please note that with the exception of POINTER, each and every classes referred in those incarnations of HASHED_DICTIONARY are reference classes that gets converted into a type-less C pointer ("void*" for the C-fond).
Now I looked into the function called Txxxcreate_with_capacity ... I wasn't too surprised to find a couple of pages of machine-generated C code that is exactly the same as all thos Txxx pointers are actually void pointers.
So in the end SmartEiffel actually implements generics in the very same (bloated?) way as C++ implements templates.
Now I guess that people smarter than me have made many researches on the topic but let me wonder whenever Liberty may avoid this.
And I know it is avoidable for reference classes.
Think a little about GLib collections and how they implemented generic object-oriented containers in C. They do not have the compiler to generate templates or generics for them, so they will end up with exactly one "binary" implementation of "replace" (g_hash_table_replace) for every kind of hash table.
That is how I would like to implement generic classes.
The only tricky part is that when you will invoke feature "foo" of the parametric type (ITEM in class LIST[ITEM]) you need to query the runtime for the address of ITEM_foo, so you will need a full fledged object-oriented type system.
I'm thinking about eventual implementation of multiple-inheritance runtime. I'm investigating a variant of Gobject interfaces. In fact if we turn each and every attribute query into an actual function call multiple inheritance looks somehow like using multiple interface; this will have a deep impact of performance since every access to any structure field will be turned into a deferred/virtual/indirect function call; actually I suspect that the link-time function in-lining of LLVM may be the silver bullet. Otherwise it won't be feasible, except if we want to "degradate" Liberty to an interpreted language.
A little ending note: when dealing with "expanded" classes, or with objects passed by value "template instantiation" is the only feasible way to go, so C++ was right.
Luckily (Smart)Eiffel prescribe that reference classes are always passed by reference and expanded always by value. This greatly simplify the work for the compiler to translate source code but most importantly greatly simplify things for our neurons.
Please feel free to correct any wrong deduction of this little note.
One of those aspects that I was sure Eiffel handled better than C++ was templates, known as generics in Eiffel.
C++ templates has been often accused to lead to code bloat and large executable, since the compiler generates specialized code for each type used in a template.
As an example when you use QList as QList
This justify why C++ executables are often considered "fat".
I don't know why but I have been always convinced that generics in Eiffel didn't show this pattern.
SmartEiffel proved me wrong.
I suspected it compiling my own wrappers-generator and getting a 5,2 Mb executable from more or less 4450 lines of code as reported by command "wc".
Ehi! This is more than 1200 bytes of binary code for each and every Eiffel line, empty lines and comments included!
No, my coding style can't be so awesome and this tool is nothing special.
It just shall not be this big.
So I dived into generated source code.
At the beginning of wrappers_generator.id which contains a description of the compiled classes from the C and Eiffel compiler point of view I can read something like:
478 "HASHED_DICTIONARY[XML_DTD_ATTRIBUTE,UNICODE_STRING]" l
#
555 "HASHED_DICTIONARY[COMPOSED_NODE,UNICODE_STRING]" l
#
404 "HASHED_DICTIONARY[WEAK_REFERENCE[ANY_LINKED_LIST_NODE],STRING]" l
#
467 "HASHED_DICTIONARY[RECYCLING_POOL[PROTOCOL],STRING]" l
#
365 "HASHED_DICTIONARY[POINTER,STRING]" l
So I looked into wrappers_generator_T478.c wrappers_generator_T555.c wrappers_generator_T467.c wrappers_generator_T365.c which are the C code containing the translations for those.
Please note that with the exception of POINTER, each and every classes referred in those incarnations of HASHED_DICTIONARY are reference classes that gets converted into a type-less C pointer ("void*" for the C-fond).
Now I looked into the function called Txxxcreate_with_capacity ... I wasn't too surprised to find a couple of pages of machine-generated C code that is exactly the same as all thos Txxx pointers are actually void pointers.
So in the end SmartEiffel actually implements generics in the very same (bloated?) way as C++ implements templates.
Now I guess that people smarter than me have made many researches on the topic but let me wonder whenever Liberty may avoid this.
And I know it is avoidable for reference classes.
Think a little about GLib collections and how they implemented generic object-oriented containers in C. They do not have the compiler to generate templates or generics for them, so they will end up with exactly one "binary" implementation of "replace" (g_hash_table_replace) for every kind of hash table.
That is how I would like to implement generic classes.
The only tricky part is that when you will invoke feature "foo" of the parametric type (ITEM in class LIST[ITEM]) you need to query the runtime for the address of ITEM_foo, so you will need a full fledged object-oriented type system.
I'm thinking about eventual implementation of multiple-inheritance runtime. I'm investigating a variant of Gobject interfaces. In fact if we turn each and every attribute query into an actual function call multiple inheritance looks somehow like using multiple interface; this will have a deep impact of performance since every access to any structure field will be turned into a deferred/virtual/indirect function call; actually I suspect that the link-time function in-lining of LLVM may be the silver bullet. Otherwise it won't be feasible, except if we want to "degradate" Liberty to an interpreted language.
A little ending note: when dealing with "expanded" classes, or with objects passed by value "template instantiation" is the only feasible way to go, so C++ was right.
Luckily (Smart)Eiffel prescribe that reference classes are always passed by reference and expanded always by value. This greatly simplify the work for the compiler to translate source code but most importantly greatly simplify things for our neurons.
Please feel free to correct any wrong deduction of this little note.
Friday, July 16, 2010
Mailing lists
Christophe Haro asked me a very interesting question today: how does one contact the LibertyEiffel community?
There was no mailing list ten minutes ago. Now there is.
Just write to libertyeiffel@librelist.com and you're done!
See their site (http://librelist.com) for details. In a nutshell, when you send your first mail you are returned a standard subscription mail; just answer it and you're set.
Welcome on board!
There was no mailing list ten minutes ago. Now there is.
Just write to libertyeiffel@librelist.com and you're done!
See their site (http://librelist.com) for details. In a nutshell, when you send your first mail you are returned a standard subscription mail; just answer it and you're set.
Welcome on board!
Friday, July 2, 2010
Getting organized.
Thanks to the new github "organization", LibertyEiffel has now gained a central depot independantly to the developers.
You can find the code there: http://github.com/LibertyEiffel/Liberty
Tickets should be opened there too.
You can find the code there: http://github.com/LibertyEiffel/Liberty
Tickets should be opened there too.
Wednesday, May 12, 2010
How easy should it be to install Liberty?
That easy:
$ ./install.shAnd now it is that easy.
Sunday, May 2, 2010
The toddler starts to run
Starting with commit e5799, the interpreter correctly runs arithmetic tests. It is more important than it seems: it means that arithmetic types are correctly promoted (think conversion + a specific conversion of Current for symmetry).
I think I'll start working on agents now, otherwise a lot of tests won't run (see EIFFELTEST_TOOLS which is agent-based)
I think I'll start working on agents now, otherwise a lot of tests won't run (see EIFFELTEST_TOOLS which is agent-based)
Monday, April 12, 2010
Hello, World!
To the immense joy of its parents, the Liberty Interpreter is born today: the classic Hello World program runs successfully.
Liberty is still a toddler: a lot or things are yet to be fixed or even merely implemented (semantic checks, agents, garbage collection, to cite just a few).
Its younger brother, the Liberty Compiler, is still a frozen embryo :-)
Liberty is still a toddler: a lot or things are yet to be fixed or even merely implemented (semantic checks, agents, garbage collection, to cite just a few).
Its younger brother, the Liberty Compiler, is still a frozen embryo :-)
Friday, March 19, 2010
Anchors may drag you down.
Anchors are a Real Good Thing (TM). But the compiler is pretty involved in their evaluation.
Liberty will use the same strategy as SmartEiffel: feature specialization. Each type specializes its features to eliminate anchors while correctly resolving them.
This creates a full flotilla of features... but their buoyancy is improved.
Liberty will use the same strategy as SmartEiffel: feature specialization. Each type specializes its features to eliminate anchors while correctly resolving them.
This creates a full flotilla of features... but their buoyancy is improved.
Wednesday, March 3, 2010
The Liberty Interpreter
The interpreter starts to work!
Objects are correctly created, features are called, contracts are checked, built-ins will be finished in a matter of days...
Now I need ideas for an efficient plugins implementation.
Although I have a few ideas (far from being ripe!) I'd be glad if some people could propose something.
What do you have in mind? Just go wild :-)
Objects are correctly created, features are called, contracts are checked, built-ins will be finished in a matter of days...
Now I need ideas for an efficient plugins implementation.
Although I have a few ideas (far from being ripe!) I'd be glad if some people could propose something.
What do you have in mind? Just go wild :-)
Monday, February 15, 2010
Some news
Just a little update on what's going on in the Liberty world.
- Semantics: simple programs are "understood", meaning that the types are nicely created and ready to be used, in a somewhat reasonable time. Note that only the nominal case should work (yet a lot of testing is yet to be performed). The parser is expected to behave correctly when given a correct program; no provision is yet made for invalid programs (the parser's reactions range from a neat error message to a gory crash)
- Interpreter: that's the next step after having that partially functioning semantics parser. I took that step today. When the interpreter starts to work we can build an REPL.
- Compiler: Paolo is working on the LLVM back-end and is already having some results. I'll wait for having somewhat stabilized the semantics parser, and worked a bit on the interpreter and the REPL, before starting to think about building a full compiler. Some topics still need a lot of thought (objects representation, call stack management, garbage collection...) and the interpreter will help at least partially in putting my ideas in good order.
Sunday, January 10, 2010
First LLVM-made binary
A small step for a humble programmer, a huge leap for Liberty project
(Me - right now)LLVM wrappers begin to be functional; please have a look at LLVM example directory and lauch make; after a while you will find:
- llvm_example : the executable made by SmartEiffel (we are using latest version from subversion repository)
- example.bc: LLVM bitcode, produced by llvm_example
- example.s: ASCII assembler program text, compile from bytecode by llc - the LLVM static compiler
- example: an ELF relocatable, made by as, usually the GNU assembler
A lot of works remains to be done in LLVM, I expect to work out several idea on actual implementation of peculiar technical details of the Eiffel runtime during the wrapping of the rest of LLVM.
I would say that since Eiffel choice not to have namespaces we shall have no name-mangling problems.
Tuesday, January 5, 2010
We need bindings not wrappers...
Interfaces to foreign libraries have been traditionally called bindings or wrappers. I never cared too much about eventual differences in meaning, I used to use them as synonims; now I'm beginning to realize that they have different meaning.
Let's speak in Eiffel or C/C++: a WRAPPER is a tiny reference (i.e. unexpanded) object containing a pointer to the unde lying data structure, think about it as a glorified REFERENCE[POINTER]; a binding - in my humble opinion - shall be a way to directly use the actual data structure as an Eiffel object, turning that pointer into the actual reference used on the Eiffel side.
Needless to say this double layer - WRAPPER and wrappee, referred thorught "feature handle: POINTER" pratically means to manually manage memory inside each effective wrapper coupling it with deferred classes that implements memory policies like EIFFEL_OWNED, C_OWNED, GLOBALLY_CACHED, MIXED_MEMORY_HANDLING, or REFERENCE_COUNTED.
This is how wrapping has always been done in Eiffel, either in Eiffel (in EWLC or EWG) or with C glue code (elj).
To bootstrap Liberty we still need them and we will still need them a lot after Liberty will be ready.
My proposal is to allow better integration with foreign languages or object-models, like C-with-Gobject or C++.
Surely both models do not perfectly map Eiffel's object way; we still will need to instruct Liberty on how to handle those datatypes generated by foreign code,
SmartEiffe started to develop external types, something that eventually bring us "real bindings".
We need "only" to allow the developer of a binding to provide object_size, generator and generator_type.
Those will be interfaced the object-model facility of the foreign language, for example with C++ Run Time Type Identification, the C++ typeid operator and its std:type_info object; Gobject also offers a comfortable type system that will fit.
Obviously there will be mismatches, peculiarities and headaches but it can be done. Other languages have done it, we can also.
There will a cost. The cost is "diverging" farther from ECMA; I read the standard a couple of months ago and I wasn't satistied by what I read about integration with other languages. I had the impression they don't care that much about integration. What I found there was a language that already diverged from what we learned to love as Eiffel.
We standed still, they walked away. We shall find and walk our trail. Perhaps different, perhaps useful for a later merge.
Let's keep writing wrappers and not binding to bootstrap.
Let's speak in Eiffel or C/C++: a WRAPPER is a tiny reference (i.e. unexpanded) object containing a pointer to the unde lying data structure, think about it as a glorified REFERENCE[POINTER]; a binding - in my humble opinion - shall be a way to directly use the actual data structure as an Eiffel object, turning that pointer into the actual reference used on the Eiffel side.
Needless to say this double layer - WRAPPER and wrappee, referred thorught "feature handle: POINTER" pratically means to manually manage memory inside each effective wrapper coupling it with deferred classes that implements memory policies like EIFFEL_OWNED, C_OWNED, GLOBALLY_CACHED, MIXED_MEMORY_HANDLING, or REFERENCE_COUNTED.
This is how wrapping has always been done in Eiffel, either in Eiffel (in EWLC or EWG) or with C glue code (elj).
To bootstrap Liberty we still need them and we will still need them a lot after Liberty will be ready.
My proposal is to allow better integration with foreign languages or object-models, like C-with-Gobject or C++.
Surely both models do not perfectly map Eiffel's object way; we still will need to instruct Liberty on how to handle those datatypes generated by foreign code,
SmartEiffe started to develop external types, something that eventually bring us "real bindings".
We need "only" to allow the developer of a binding to provide object_size, generator and generator_type.
Those will be interfaced the object-model facility of the foreign language, for example with C++ Run Time Type Identification, the C++ typeid operator and its std:type_info object; Gobject also offers a comfortable type system that will fit.
Obviously there will be mismatches, peculiarities and headaches but it can be done. Other languages have done it, we can also.
There will a cost. The cost is "diverging" farther from ECMA; I read the standard a couple of months ago and I wasn't satistied by what I read about integration with other languages. I had the impression they don't care that much about integration. What I found there was a language that already diverged from what we learned to love as Eiffel.
We standed still, they walked away. We shall find and walk our trail. Perhaps different, perhaps useful for a later merge.
Let's keep writing wrappers and not binding to bootstrap.
Etichette:
wrappers
Subscribe to:
Posts (Atom)