Friday, January 20, 2012

Many long-time Eiffel programmers and experts always knew it: Eiffel should be formatted with a proportional font. Looking for the original reasoning of Bertrand Meyer about it I found this link in Wikipedia:

I tried to follow these rules to write a little style for SyntaxHighlighter (I'll put them online as soon as possible to properly format our sources here). I would like to know your opinion about it; also please feel free to partecipate!
My personal opinion is that this stylistical rule is deeply yet unconsciously linked to Literate Programming since valid Eiffel source code often resemble a natural language like English, at least much more than C, C++, Python, Java and so on.
Actually an Eiffel program is not "written as an uninterrupted exposition of logic in an ordinary human language", yet the source code of an Eiffel class, with its emphasis on documentation, the preconditions, the postconditions and its invariant strikingly resemble an explanation in a natural language,
such as English, of the design of the type it represent.
Eiffel source code looks so much like the pseudocode typically used in teaching computer science to explain algorithms that when Bertrand Meyer wrote Object Oriented Software Construction he actually used Eiffel from page one without telling it to his reader, pretending it was pseudocode; in the pages of the book it justified each and every design choice of his design then in the epilogue he actually revealed that the pseudo-code he used wasn't actually pseudo-code at all but real, effective Eiffel code.

Some weeks ago I stumbled upon this entry of Ada FAQ: Some Isn't Ada less "elegant" than Eiffel? (also readable as a thread in Lisaac mailing list).
Now that I think I finally found an actual way to re-implement deep_twin and is_deep_equal with a pure Eiffel, reentrant, thread safe design (beware that I still have to test it extensively before saying it's good even to be labelled "alpha-quality") I must answer to those issues, since most of them don't hold anymore.
In particular, although I like the assertion
stuff in Eiffel, I think the language has a number of "inelegant"
aspects. For example:

exception handlers only at the top level of a routine,
with the only way to "handle" an exception being by retrying
the whole routine.

As far as I remember this have been a deliberate design choice of Meyer. The rationale behind this is that if a feature, either a command or a query is longer than a 20-30 lines it becomes far more difficoult to understand; it becomes easier to understand for the reader if it is broken in several independant pieces. Therefore the need for intra-feature exceptions fades away: when you need to handle an exception in a specific section of a feature this is the distinguished mark that that piece could be made an independant feature. If you don't want to expose it to your clients just hide it private behind a "feature {} -- Implementation of foo feature".

No way to return from a routine in the middle.
This makes it a pain in the neck to search through
a list for something in a loop, and then return immediately
when you find what you want. (I have never found the
addition of extra boolean control variable a help to
the understanding of an algorithm.)

This is actually something I found myself longing to sometimes.

Namespace control handled by a separate sublanguage, and
no real higher level concept of "module" or "subsystem."

An obscure notation like "!!" being used for an important
and frequent operation (construction).

This was a good point. In fact the "!!" notation have been (somehow) deprecated; while it has never been phased out by the language itself I have never read it in code writter in this century. Nowadays all Eiffel programmers worth their salt always use one of the following syntaxes:

"foo: LINKED_LIST[STRING] .... create foo" used when the created object be an actual instance as declared, using "default_create" feature to initialize it;

"foo: SET[STRING] .... create foo.make_with_capacity(120)", the most widespread usage where you tell the compiler which creation feature shall be used to initialize the newly created object

"foo: COLLECTION[STRING] .... create {TWO_WAY_LINKED_STRING} foo" used when you want to create an object of a subtype of the declared type, either because the declared type is deferred (a.k.a. virtual for you people coming from C++/Java world) or because you want to use a subclass that better fits the task.

in-place creation, in the middle of the arguments of a feature "produce_and_ship_with(12, "Chocolate cakes", create {CAR}.with_plate_and_label(clients_car_plate, "The car of client "|client_name)"; by the way this line show the usage of one of the three concatenation operators we introduced in strings. I should really write a blog entry about these... (they are infix "+", infix "|" and infix "&", see ABSTRACT_STRING for a brief description.

I thing it may be useful to make the compiler emit a warning when such a syntax is still used. Perhaps we may be daring enought to just drop it, allowing to use the exclamation point for free operators: it is a good thing that people learning Eiffel shall not be exposed to that "archeological" syntax.

No way to conveniently "use" another abstraction without
inheriting from it.

This is exactly what both Eiffel standards (ECMA and GNU/Smart) implemented in this decade: non-conforming inheritance; now when you need to use another abstraction without being a type conforming to it you "insert" it.

No strong distinctions between integer types used for array indexing.

I think this is a "non issue" at all, since array access does not have any special status at all in Eiffel; actually you may just define your arrays to accept different types on indexes. I suspect that this

Using the same operator ":=" for both (aliasing) pointer assignment, and for value assignment, depending on whether the type is "expanded." (Simula's solution was far preferable, IMHO).

This were actually confusing some years ago since you may decide in the definition of each feature whenever an argument shall be expanded or not. Now in GNU/SmartEiffel this is notnot confusing in my humble opinion in since the difference between assignment by reference or by value (expanded values) is estabilished class per class; when you need to have a reference to an expanded class you just use REFERENCE[FOO] with FOO being an expanded class. By the way you may read the definition ofREFERENCE discovering that it is a simple, plain and normal generic class that does not require any special support from the compiler at all. I think that deciding once and forever if a class is either a reference or an expanded value makes code far easier to understand for the reader, easier for the designer to conceive and easier for the compiler to parse and optimize.

And most critically:

No separate interface for an abstraction.
You can view a interface by running a tool,
but this misses completely the importance of having
a physical module that represents the interface, and
acts as a contract between the specifier or user of
an abstraction and its implementor.
In Eiffel, one might not even be truly aware when one is
changing the interface to an abstraction, because there
is no particular physical separation between interface
and implementation.

Again this is a deliberate and willingful consequence of an explicit design choice; it has been extensively explained by Meyer in Object Oriented Software Construction; this would be a nice topic for a foreseeable blog entry as it's a sin not to explain it to people on the net; I wish Meyer published OOSC directly on the net as I'm sure that the profits for the advertizing that he would put will more than compensate his lost revenues.

Monday, January 9, 2012

SmartEiffel used to require a manifest tuple for both call and item agent features. The rationale is to force the user to ponder on the number of arguments; and since no actual tuple was created, memory was not wasted.
The drawback is that one had to manually "decapsulate" a provided tuple using an explicit (and ugly) [a_tuple.item_1, a_tuple.item_2]

Now one may call an agent using a variable that contains a tuple.

The only condition is that the entity is correctly statically typed, because the compiler generates calls to the item_i features using the static type. Thus the rationale is still useful (the user needs to know the actual tuple type); but the code is far less ugly. Also remember that the tuple is actually created!