Thursday, December 22, 2011
They call me GNU-Eiffel
We are continuing the development of the academic project that acquired in 1998 the status of "Gnu Eiffel compiler". As I wrote in the beginning article of this blog Dominique Colnet is focusing his academic interests on other aspects of Information Technology. Cyril - a member of the former core team of developers - and me still believe that this language has still to a useful role as a free-as-in-freedom project.
We thought to use the existing compiler - SmartEiffel - to bootstrap another one - LibertyEiffel, but we soon realized that it may be evolved into something more modular, more scalable. The only prerequisite to the latter approach is an extensive knowledge of the inner design of the compiler: Cyril has done a good work cleaning it up and know it seems easier to grasp it all. So Liberty design ended up becoming part of our improvements toSmartEiffel.
SmartEiffel also does not implement ECMA-Eiffel, trying to be follow the original design and spirit of the language that wanted to be simple yet powerful. ECMA-Eiffel is quite a different language and more complex: the original definition of Eiffel was under 50 pages, current ECMA is quite bigger.
All those considerations are pushing me to call the language and the tools implementing it GNU-Eiffel.
Wednesday, December 21, 2011
Insert or non-conforming inheritance
All programming languages have been weak spots that are criticized, Eiffel is no exception.
One of the most sound critique to the original Eiffel is that inheritance was the only modularity mechanism available.
In fact it is a fundamental part of the object oriented approach to programming.
Yet in its pristine, original form inheritance it does not allow to implement shared constant or commodity features (either queries or commands) in a clean way.
For example to implement dictionaries, hash tables and many cryptografic algorithms there's the need to have a handy list of prime numbers or a function that tells the first prime higher than a given integer. Let's say we put all these informations into a PRIMES_LIST class; in pristine Eiffel we would have written:
In this (oversimplified) example a DICTIONARY actually is a list of primes, but a really strange one, since with "export all {NONE}" we told the compiler that all the features originally defined in PRIMES_LIST cannot be invoked, queried or used by any code handling a DICTIONARY.
Beside looking a palese breach in the OO architecture it actually answered in the wrong way to a rightful need: sharing some code or data between different parts of the programs; the pecualiar aspect is that all that code or data is not linked or bounded to a particular type at all, but they are quite generic.
There's the need to have all the features - queries, commands constants and attributes - of another class without being a subtype of that class; we need what is known as non-conforming inheritance or feature insertion.
That's exactly the role of "insert": to have all the feature on another class without being conforming to that class.
In fact with the previous example you may write:
When we do want to share some definitions or a list of primes like in this example we may have inserted the features of PRIMES_LIST, like this:
ECMA Eiffel has the same non-conforming mechanism, but its syntax is "inherit {NONE} PRIMES_LIST", meaning inherit conforming to no class. While this is correct it seems to allow to write "inherit {MY_CLASS} PRIMES_LIST", bringing confusion together with a useful, simple mechanism. I have discussed the rationale behind this some time before SmartEiffel team decided not to implement ECMA, I'll try to dig it out.
One of the most sound critique to the original Eiffel is that inheritance was the only modularity mechanism available.
In fact it is a fundamental part of the object oriented approach to programming.
Yet in its pristine, original form inheritance it does not allow to implement shared constant or commodity features (either queries or commands) in a clean way.
For example to implement dictionaries, hash tables and many cryptografic algorithms there's the need to have a handy list of prime numbers or a function that tells the first prime higher than a given integer. Let's say we put all these informations into a PRIMES_LIST class; in pristine Eiffel we would have written:
class DICTIONARY [A_VALUE, A_KEY] inherit PRIMES_LIST export all {NONE} end .... end -- class DICTIONARY
In this (oversimplified) example a DICTIONARY actually is a list of primes, but a really strange one, since with "export all {NONE}" we told the compiler that all the features originally defined in PRIMES_LIST cannot be invoked, queried or used by any code handling a DICTIONARY.
Beside looking a palese breach in the OO architecture it actually answered in the wrong way to a rightful need: sharing some code or data between different parts of the programs; the pecualiar aspect is that all that code or data is not linked or bounded to a particular type at all, but they are quite generic.
There's the need to have all the features - queries, commands constants and attributes - of another class without being a subtype of that class; we need what is known as non-conforming inheritance or feature insertion.
That's exactly the role of "insert": to have all the feature on another class without being conforming to that class.
In fact with the previous example you may write:
feature strange is local primes_lists: LINKED_LIST[PRIMES_LIST] do create primes_list primes_list.append ( {PRIMES_LIST} ) primes_list.append ( {DICTIONARY[STRING; INTEGER]} ) primes_list.append ( {CRYPTO_USING_PRIMES} ) ... endWhat a strange collection: a list compraising a list of primes, a dictionary containing strings and a cryptografic stream! The designer of a program may actually do not want to have such objects.
When we do want to share some definitions or a list of primes like in this example we may have inserted the features of PRIMES_LIST, like this:
class DICTIONARY [A_VALUE, A_KEY] insert PRIMES_LIST .... end -- class DICTIONARYActually it is customary to declare those auxiliary classes deferred, in order to forbid direct usage of that class itself.
ECMA Eiffel has the same non-conforming mechanism, but its syntax is "inherit {NONE} PRIMES_LIST", meaning inherit conforming to no class. While this is correct it seems to allow to write "inherit {MY_CLASS} PRIMES_LIST", bringing confusion together with a useful, simple mechanism. I have discussed the rationale behind this some time before SmartEiffel team decided not to implement ECMA, I'll try to dig it out.
Case sensitivity
Eiffel was born as a case-insensitive language. So it would allow to write this code:
cLaSS nice_AnD_READableAnd using it elsewhere like:
INHERIT foo
FEAture BOOO is oD pRiNt("Boo!") end
eND
local MY_obj: NICE_and_readABLE
do
CREate my_obj
my_OBj.booo
....
Nice, isn't it?
Now such code quite obviously will give an headache to people reading it and it will make life harder to all tools. While the latter "would not count" if those requirements will make code easier to read it is quite the opposite: making the language case-insensitive does make the language less readable.
The idea was - if I recall correctly OOSC - to turn casual case-errors into warnings allowing the developer to concentrate on the logic instead of the case of the identifiers.
Actually style counts, so rightfully the definition of the language comes with a very precise style guide:
The idea was - if I recall correctly OOSC - to turn casual case-errors into warnings allowing the developer to concentrate on the logic instead of the case of the identifiers.
Actually style counts, so rightfully the definition of the language comes with a very precise style guide:
- all classes names shall be uppercase
- all constants shall be lowercase with the first letter uppercase
- all other identifiers and language reserved words shall be written lowercase
class NICE_AND_READABLE inherit FOO feature boo is do print("Boo!") end end ... local my_obj: NICE_AND_READABLE do create my_obj my_obj.boo ...This may look quite strict and at first it feels so; my experience tells me that this discipline is actually good for the developer writing the code, those reading the code allowing for a smoother reading.
Tuesday, December 20, 2011
Highlighting Eiffel syntax in Blogger (DONE!)
Syntax highlighting of programming languages seems to require a little tweaking in Blogger. SyntaxHighlighter from Alex Gorbatchev is a most widespread syntax highlighter used in Blogger but it doesn't support Eiffel out-of-the-box.
Luckily it's all JavaScript and supports Delphi and Pascal and it's hosted on github, so I forked it (with git it's fast, light and easy to merge the changes in the main trunk) to add (Smart)Eiffel support, thanks to the nice guide the main developer provided.
2011-12-22 update: I tried a really quick hack and I got a preliminary working version. To use it in Blogger I had to switch to a "simple" theme, one whose sources can be hacked, adding in the head the following code:
Please note that I couldn't directly use the file on github, perhaps it does not like https so I falled back putting on a website on mine (namely at 'http://www.monodes.com/scripts/shBrushEiffel.js') until I improve it a little before proposing it to the main trunk. Also since Alex says: While the hosting is offered as a free service, I’m currently receiving approximately 22m requests a and 83GB in bandwidth every month which is costing me an additional $40 on Amazon S3. Where am I going with this? You guessed it – please donate to help me pay for this :) I think I would rather put an entire copy of the package on my domain.
Luckily it's all JavaScript and supports Delphi and Pascal and it's hosted on github, so I forked it (with git it's fast, light and easy to merge the changes in the main trunk) to add (Smart)Eiffel support, thanks to the nice guide the main developer provided.
2011-12-22 update: I tried a really quick hack and I got a preliminary working version. To use it in Blogger I had to switch to a "simple" theme, one whose sources can be hacked, adding in the head the following code:
<link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css"></link> <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js' type='text/javascript'/> <script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXML.js' type='text/javascript'/> <script src='http://www.monodes.com/scripts/shBrushEiffel.js' type='text/javascript'/> <script language='javascript'> SyntaxHighlighter.config.bloggerMode = true; SyntaxHighlighter.config.clipboardSwf = 'http://alexgorbatchev.com/pub/sh/2.1.364/scripts/clipboard.swf'; SyntaxHighlighter.all(); </script>
Please note that I couldn't directly use the file on github, perhaps it does not like https so I falled back putting on a website on mine (namely at 'http://www.monodes.com/scripts/shBrushEiffel.js') until I improve it a little before proposing it to the main trunk. Also since Alex says: While the hosting is offered as a free service, I’m currently receiving approximately 22m requests a and 83GB in bandwidth every month which is costing me an additional $40 on Amazon S3. Where am I going with this? You guessed it – please donate to help me pay for this :) I think I would rather put an entire copy of the package on my domain.
Creation procedures
Eiffel required - a quarter of century ago - explicitly provide a creation procedure for each object; so each creation was in the form of
create my_list.make_emptyNowadays SmartEiffel allow us to write
create my_listwhen a class has put default_create command in the creation clauses list such as:
class LITTLE_LIST [ITEM]To create collections, lists, arrays, associative dictionaries you may use the manifest notation, like this:
-- A list to contain few elements
inherit COLLECTION[ITEM]
creation default_create, make, make_empty, with_capacity
...
some_primes := {LINKED_LIST[INTEGER] <<1, 3, 5, 7, 11, 13, 17, 23>> }Please excuse the horrible formatting of the code, I'm working on it.
dictionary := {HASHED_DICTIONARY[CHARACTER, STRING] << 'a', "key #1";'z', "key #2";'z', "key #3";'a', "key #4" >> }
bijective_dictionary :={HASHED_BIJECTIVE_DICTIONARY[STRING, STRING]<< "value #1", "key #1";"value #2", "key #2";"value #3", "key #3" >> }
diff "Eiffel: the language" "GNU Eiffel"
We have been asked for some informations about the differences between the language originally described in "Eiffel: the language" (1992 by Bertrand Meyer) and those accepted by the current GNU/Smart/Liberty Eiffel compiler.
Such a request is not only reasonable but requires some answer: there have been several additions and quite a few changes to the language.
The main changes are:
Such a request is not only reasonable but requires some answer: there have been several additions and quite a few changes to the language.
The main changes are:
- Creation procedures
- agents
- conformance of agents
- anonymous, in-lined agents (a_command(12, "Foo", agent (x: INTEGER): REAL is do Result:=x.to_real ^ 2 end )
- insert, also known as "non-conforming inheritance"
- case sensitivity
- inspect allow for integer intervals...
- FLOAT is replaced with REAL
- There is no NONE (pun intended :-)
- other I don't recall now.
Monday, October 3, 2011
Hello World… again
The first version of the Liberty interpreter was stillborn. It took a year to utter Hello World… and never said anything more.
The second version, based on SmartEiffel, is alive and kicking, after 2 weeks gestating.
The "runner" is screaming: Hello World!
The second version, based on SmartEiffel, is alive and kicking, after 2 weeks gestating.
The "runner" is screaming: Hello World!
Monday, September 26, 2011
Overflow and correctness
Eiffel is a programming language that strives for correctness.
In C instead most of the times speed is regarded as more important than correctness (paraphrasing a comment of Eric Sosman ).
Most Eiffel compilers use C as an intermediate language (Liberty/SmartEiffel, ISE), so a programming language striving for correctness relies on one that trade correctness for speed.
I've been thinkering about
I think we cannot blame C as this is a issue that has no "solution"; let's see a little panoramic of the efforts poured into something "as simple" as correctness in integer calculations:
An answer may be saturation arithmetic; digging my fading knowledge of assembler, mainly from my days on 6502 I was wondering why no one seems to use the overflow flag present in almost all CPU: it seems there is no portable way to do it access it. Oh it would be so nice to write in INTEGER_GENERAL
In C instead most of the times speed is regarded as more important than correctness (paraphrasing a comment of Eric Sosman ).
Most Eiffel compilers use C as an intermediate language (Liberty/SmartEiffel, ISE), so a programming language striving for correctness relies on one that trade correctness for speed.
I've been thinkering about
I think we cannot blame C as this is a issue that has no "solution"; let's see a little panoramic of the efforts poured into something "as simple" as correctness in integer calculations:
- Best way to detect integer overflow in C (from Stackoverflow.com)
- CERT's "as-if" infinitely ranged (AIR) integer model and "Ensure that operations on signed integers do not result in overflow"
- Integer security
- Catching Integer Overflows in C
An answer may be saturation arithmetic; digging my fading knowledge of assembler, mainly from my days on 6502 I was wondering why no one seems to use the overflow flag present in almost all CPU: it seems there is no portable way to do it access it. Oh it would be so nice to write in INTEGER_GENERAL
«infix "+" (another: like Current): like Current is external "built_in" ensure has_overflowed=False end»I naively thought that an arithmetic overflow would have triggered a SIGFPE signal in POSIX systems. It seems I'm wrong:
class OVERFLOWWhen compiled with "compile overflow.e" Liberty Eiffel correctly says:
-- Test integer overflow
insert PLATFORM
creation make
feature make is
local i,j: INTEGER
do
i := Maximum_integer
j := i+1 -- SIGFPE expected
("i:=#(1), j=i+1=#(2)%N"# (&i) # (&j) ).print_on(std_output)
end
end
*** Error at Run Time ***: Require Assertion Violated.but when we compile it with "compile --boost overflow.e" it happily says: "i:=2147483647, j=i+1=-2147483648" which is obviously wrong. You have to compile it with "compile --boost overflow.e --cc gcc -ftrapv" to laconically receive the answer
*** Error at Run Time ***: no_overflow
3 frames in current stack.
===== Bottom of run-time stack =====
<system root>
Current = OVERFLOW#0x925b038
line 5 column 9 file /media/Liberty/tybor-liberty/work/tybor-sandbox/overflow.e
======================================
make OVERFLOW
Current = OVERFLOW#0x925b038
i = 2147483647
j = 0
line 9 column 4 file /media/Liberty/tybor-liberty/work/tybor-sandbox/overflow.e
======================================
infix + (infix + INTEGER_32)
Current = 2147483647
other = 1
Result = 0
line 21 column 80 file /home/paolo/current-liberty/src/lib/numeric/integral.e
===== Top of run-time stack =====
*** Error at Run Time ***: Require Assertion Violated.
*** Error at Run Time ***: no_overflow
"Received signal 6.Which is not what I would expect, since signal 6 is ABRT on my system.
Eiffel program crash at run time.
No trace when using option "-boost"
infix "#": Eiffel's printf
It's really nice to be able to write in Liberty/SmartEiffel:
which may look cryptic to most Eiffel programmers, but may look familiar when translated into C:
("i:=#(1), j=i+1=#(2)%N"# (&i) # (&j) ).print_on(std_output)
("obviously foo := #(2), bar := #(1)%N" # &42 # &17).print_on(std_output)
which may look cryptic to most Eiffel programmers, but may look familiar when translated into C:
printf("i:=%d, j=i+1=%d\n", i,j)Beside looking a little more convoluted it actually has quite a few advantages:
printf("obviously foo := %d, bar := %d\n", 17,42)
- like QString::arg of Qt fame it allows positional arguments,
- it does not rely on variable argument function calls,
- it does not allocate an unnecessary array to hold the arguments; each call to # actually return a ROPE which does is an ABSTRACT_STRING holding references to two substrings; the prefix "&" operator returns a LAZY_STRING (praises to Adrian for good idea) which will not be converted to a string until it gets iterated over, usually printing or copying it.
- it allows to write things like:
local s,t,u: STRING
do
s := "Eiffel"; t:= "beautiful"end
u := s | " is a " |t| " language"
assert (u.is_equal("Eiffel is a beautiful language")
t.prepend("really ")
assert (u.is_equal("Eiffel is a really beautiful language")
-- which may also obtained with
u := "#(1) is a #(2) language" # s # t - it does retain type-safety (AFAIK)
Sunday, July 17, 2011
SmartEiffel as Liberty core
OK guys, I have permission from Dominique, and I guess it is better anyway.
SmartEiffel is back in the trenches. It is now completely part of LibertyEiffel.
Here is the plan:
Extra points to fix:
The Liberty libraries (both native and wrappers), on the other hand, are here to stay. They deserve being enhanced.
Spread the news :-)
SmartEiffel is back in the trenches. It is now completely part of LibertyEiffel.
Here is the plan:
- really integrate SmartEiffel into Liberty (done)
- separate the C backend from the AST (fix and use the acyclic visitor)
- remove or rewrite the Java backend (using the acyclic visitor)
- rewrite the interpreter as a SmartEiffel backend (maybe using the acyclic visitor)
Extra points to fix:
- sedb — it lost some of its power in the latest releases (some break points disappeared)
- Liberty core — will be removed; that code is dead.
- some bugs in inline agents parsing (SmartEiffel segfault)
- some bugs in boost mode (invalid C code)
The Liberty libraries (both native and wrappers), on the other hand, are here to stay. They deserve being enhanced.
Spread the news :-)
Subscribe to:
Posts (Atom)