ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) (09/24/90)
I got the Metrowerks Modula-2 compiler for MPW a few days ago, and after nodding my head at some of the demos, I wrote my first couple of Modula-2 programs on the Mac today. I thought I'd share some very preliminary impressions, in the hope that there a few other folks out there who have given up on the arguments over Pascal-versus-C and decided to move on to a decent language... First of all, I should warn you about the crummy licence agreement. On the page after the credits, in the MPW manual supplement, it says "You may not rent, lease, sell or give away copies of the software ... nor include these copies in any package which you then distribute. You may not reverse assemble or reverse compile the software." This is pretty rough. Let's take the second part first: You may not disassemble or decompile the software. I had to do exactly that this morning, to figure out some internals of the run-time library. I was trying to write an FKEY, which I managed to get working just fine. In the process, I had to find the main module in MRuntime.o, so that I could remove it and prevent clashes with my code for defining the FKEY entry point. I couldn't just leave out the entire library, because it had some other bits in it which the program needed. And the next thing I had to do was check to see if any part of their code needed access to global variables, which would have made it unusable in an FKEY. I found that their glue for BlockMove was making an assignment to a global variable called "err". Exit their glue code, enter some custom inline code. And what about the sentence that says you may not include copies in any package that you distribute? It's not clear whether this applies to library routines linked into your programs. Could it be you aren't allowed to distribute programs containing *any* such code? To make it worse, the next paragraph says "All these actions are in violation of the license agreement and we will prosecute anyone who attempts to do so." They'll never take me alive... But enough of the depressing stuff. In my view, Modula-2 doesn't remedy enough of the flaws in Pascal, but it seems to be enough of an improvement to be widely considered a "serious" programming language. Its scope control is very tight, and a sizeable program is liable to have IMPORT and EXPORT lists all over the place. Also it's case-sensitive, which personally annoys the hell out of me. But it's got the low-level access, and the separate compilation, and it doesn't sacrifice the type-safeness (at least, not much). Metrowerks actually sell three different versions of their compiler for the Mac, and there is even one for MIPS machines. Besides the MPW version and a "student" version, there is the "Professional Stand-alone Edition" (PSE), which is a custom development environment all on its own. I had a look at the PSE version when I was at a conference where they were showing the product at a stand. The one thing I wanted to know was, since they have their own custom linker, do they implement *proper* checking for circular imports? For those not familiar with Modula-2, modules may have initialisation code which is automatically executed before the program starts using stuff from those modules. If a modula A refers to things in module B, then the initialisation code for B is guaranteed to execute before that for A. It's a very naughty programming practice to have a module A which depends on module B which depends on module C which in turn depends on module A, but for some reason Niklaus Wirth is very coy about actually denouncing this practice: he just says that the results in this case are "undefined". Speaking of Wirth, does anybody know a good book mail-order firm so I can order a copy of "Programming in Modula-2", 4th Ed? It's hopeless trying to order books from bookshops in this country: they keep telling you it'll take 4 months to arrive via surface mail. Anyway, to get back to PSE, what I wanted to know was, would the linker detect a circular import situation, and issue some kind of warning? (It was too much to hope that it would disallow the circularity altogether). The answer was: nope, not a peep. There didn't even appear to be an option to produce such a warning. So, having decided that Metrowerks had blown the one advantage that they could have offered with a custom stand-alone development environment, and being an MPW freak from way back, I ordered the MPW version. The language has changed a little since I last seriously played with it, in 1985. Back then, definition modules had to have an explicit list of the names that they exported; now, the assumption is that everything you put in the definition part is exported. It makes sense, I guess. One welcome improvement is that type casting is no longer done as it is in UCSD-style Pascal (as on the Mac), using TypeName(Value); you have to use the CAST function, as follows: CAST(TypeName, Value). And you have to explicitly import CAST from the SYSTEM module. This is a good way to prevent mistakes, and make sure that your low-level stuff is confined to the places that you think it's in. If you think this is a nuisance, just stop and think about the difference between ADR(x) and ADDRESS(x) (using old-style type casts), and how easy it would be to confuse them. Actually, you can still compile programs using old-style type casting; you need to specify a compiler command-line option to allow this. One thing that's always annoyed me about Modula-2 is that you can't pass the addresses of routines nested within other routines. In the Mac Pascals, you can use the "@" operator to get the address of a variable, function or procedure, but this value didn't have any meaningful type, so all your operations on it were totally unsafe. Modula-2 and C remedy this particular defect, but only Modula-2 avoids throwing out the baby with the bathwater by keeping the ability to declare a routine as local to another. The problem with calling inner routines is that you have to pass the correct "static link" value on a call, so that the routine can make references to variables and things declared in an outer routine. Actually it's very easy to cover up the necessity for this "special" treatment, but it involves generating code at run-time, and many people feel squeamish about this, for some reason. Anyway, the Metrowerks compiler does offer an escape: you can use the ADR function to take the address of an inner routine, which you could then "bind" to the static link value, and then cast to the appropriate PROCEDURE type. The intermediate steps are somewhat low-level, but the result is still type-safe. One restriction with no work-around is that you aren't allowed underscores in identifiers. I personally prefer "red_ball" (which I like to write as "Red_ball" occasionally) to "RedBall". Unfortunately, the Metrowerks compiler uses the underscore as a separator between the parts of the names it generates in the object code. For example, a procedure "TheProc" exported from a module "TheModule" is named "TheModule_TheProc" in the object code. I haven't had a play with the symbolic debugging yet. It's apparently SADE-compatible--I guess it pretends to be Pascal to the debugger. What else--the calling conventions are similar to, but not quite Pascal. The arguments are pushed on the stack in Pascal order (so they end up backwards), but value arguments are always passed by value, even if they're bigger than four bytes. Each routine expects the caller to save all the registers by default, which can cause you grief if you're writing code to be called by someone else. Luckily, you can insert a call to SYSTEM.SAVEREGS right at the start of the routine body, and the compiler will adopt the Pascal convention and save the usual registers. I'm looking forward to playing some more with the compiler. In my list of custom submenus which give me quick access to all the language interface files, I've put Modula-2 in the number 2 position, after Pascal. Who knows, someday I may move it to number 1. Lawrence D'Oliveiro fone: +64-71-562-889 Computer Services Dept fax: +64-71-384-066 University of Waikato electric mail: ldo@waikato.ac.nz Hamilton, New Zealand 37^ 47' 26" S, 175^ 19' 7" E, GMT+12:00 "I never feel like I do when I think I should."