Microsoft .NET is a new programming framework integrating multiple programming language into one "Common Runtime". The idea seems to fit well with the ideal of concept programming: finding the right representation for application concepts in the code should benefit from having the right language to express these concepts.
A Failed Promise
Unfortunately, in its current incarnation, Microsoft .NET doesn't appear to deliver on this promise. Rather than really increasing the vocabulary of programmers by giving them access to the specific functionality of each language, .NET dumbs down rich languages such as Eiffel to a common and rather poor semantics, exemplified by the C# language. For instance, Eiffel loses multiple inheritance when "talking" with .NET objects, even if they are written in Eiffel too. Note that these comments are based only on what I read about .NET, I did not test it myself yet.
As a result, Mozart and .NET are opposite twins: Mozart is about enabling all paradigms and semantics with the simplest possible syntax (including your trustworthy Java). .NET is about dumbing down all possible syntaxen in the world to C#-style semantics.
FAQ: Doesn't Eiffel for .NET now support multiple inheritance? The paper indicates how Eiffel for .NET now "supports" multiple inheritance in the .NET framework. However, reading the article in depth reveals that multiple inheritance is only simulated using interfaces. For instance, if an Eiffel class D derives from classes B1, B2 and B3, the compiler will actually generate interfaces for B1, B2 and B3, shadowing implementation classes named Impl.B1, Impl.B2 and Impl.B3. This is a hack.
Why does it matter? For one, performance. Since the actual details of the class Impl.B3 implementing the interface B3 is unknown to class D, the generated code contains one extra level of indirection to access anything in B3 from a D object. If m is a member in B3, to write the value 2 into m for an object d, a C++ or native Eiffel compiler generally emits code that looks like *(&d + m_offset) = 2;. But the m_offset cannot be deduced from the interface, so the Eiffel.NET compiler has to generate something that looks like tmp_ptr_b3 = *(&d + b3_offset); *(tmp_ptr_b3 + m_offset) = 2; The exact details depend on the binary layout of objects. The .NET runtime may have clever optimizations in that area, but that is unlikely given what I read so far.
Now extend this to 5 levels of inheritance. Where C++ or native Eiffel would add 5 constants (which any decent compiler can reduce to adding the sum of the 5 constants), a .NET implementation will instead use 5 memory accesses and 6 additions before getting the address of the data member. Knowing that on any modern processor, the cost of a memory access is orders of magnitude more expensive than the cost of an addition, that is unacceptable waste. As a result, deep inheritance in Eiffel.NET is inefficient.
This is a typical example of concept cast. By replacing one concept with another, you add significant complexity. Hiding the complexity under the carpet like the Eiffel implementation attempts to do doesn't remove it.
Why many syntaxen?
Various syntaxes have been invented over time to fulfill the needs of different application domains. This is why they are so different from one another. A concept that is important in one application domain may be totally secondary in another environment.
Perl and other similar languages are often criticized for their syntax. Some of this criticism might be deserved. However, if you primarily want to manipulate text streams, having a concise (if somewhat arcane) syntax to replace text is a good thing. In that context, something like s/foo/bar/;, to replace the string "foo" with the string "bar", is actually a good syntax. It is short, readable (once you get to know it) and represents a useful and frequent concept for that application domain.
What concept programming teaches us there is that the syntax itself is important only to the extent that it supports the underlying semantics well. We don't care about a syntax such as s/foo/bar/; that much. We really care about being able to represent this "string replacement" concept in such an efficient way. In other words, it is much more important to keep this semantics than to keep the precise syntax.
But .NET does the exact opposite. If we dealt with Perl the way .NET deals with Eiffel objects, you would still write s/foo/bar, but it would only reliably replace strings of the same length (since that's how memcpy() works in C), and it might also enter an infinite loop if you tried something subtle like s/foo/fool.
One Syntax to Rule Them All
The Mozart approach with XL is very different. The XL language design cares very much about being able to host different paradigms, keeping the original semantics intact, as these examples show. But it doesn't care much about keeping the precise syntax intact. As a matter of fact, much of the XL syntax could be changed (and has been changed over time) with little impact on the language expressive power.
Getting back to the string replacement example, an XL implementation might use an XL-style syntax to perform the replacement, but using Perl-style semantics, for instance using a default variable for its input and output, similar to $_ in Perl. The programmer would write something like subst "foo","bar", but otherwise not have to worry much about the behavior differing from Perl behavior. It would also be possible to "hack" XL using pragmas to get s/foor/bar to compile and do the right thing, but would this really improve usability?
To programmers, this means real expressive power, rather than the dubious "right" to dawdle in their favorite language.
Yes... but
There is just one little thing to remember however. For all its qualities, XL is not really available just yet... On the other hand, there is already a lot you can do with Moka and Java.
|