Peter N Lewis wrote:
Clearly you can write code that has the same semantic behaviour as WriteLn by expanding it sufficiently into multiple calls to multiple different procedures for each possible type. But that is not "like" WriteLn in that it is not even close to syntactically the same.
In fact it's only syntactically different. WriteLn (with several arguments) is just a syntactic shortcut, as defined in the standards. Semantically it's the same as a series of simple procedure calls.
The philosophy I refer to is that things that look like functions or procedures in the language should be possible to be written in the language.
I consider this a worthy goal and hence a weakness in the language. The problem can be solved in a number of ways:
- Support types as first class objects and support variable numbers
of parameters.
That's *not* what WriteLn is. It's a common misunderstanding which Chuck tried to rectify. This may be the core of the disagreement here.
The built-in WriteLn is not a magical procedure that takes any number of arguments, plus type information ("types as first class objects") and acts on these.
Though a compiler could implement it like this if it's equivalent to the real semantics, which is not quite easy to achieve due to some hairy details. Also, this approach is generally likely to be less efficient than the standard way. (I should know as GPC tried to do this until last year, and indeed, it failed on some of those hairy details, and it had a little runtime overhead for dispatching, as well as some rather hairy runtime code.)
Sure, a complete, type-safe, variadic routine implementation could emulate WriteLn, but in a less efficient way and with much, much more effort, both for the language designer, the implementor and the end-user. So, when this is usually implied by asking for being able to reimplement "something like WriteLn", this would be huge overkill for lesser results.
To actually do something like WriteLn's standard semantics, one would need a way to specify those in a program. I have seen no real suggestion how this could even look like. These would be things like:
: For n>=1, write(f,p 1 ,...,p n ) shall access the textfile and establish a : reference to that textfile for the remaining execution of the statement. : For n>=2, the execution of the statement shall be equivalent to : : begin write(ff,p 1 ); write(ff,p 2 ,...,p n ) end : : where ff denotes the referenced textfile.
: Writeln(f,p 1 ,...,p n ) shall access the textfile and establish a : reference to that textfile for the remaining execution of the statement. : The execution of the statement shall be equivalent to : : begin write(ff,p 1 ,...,p n ); writeln(ff) end : : where ff denotes the referenced textfile.
The closest thing to these I remember having seen would be variadic macros in the GCC C preprocessor (maybe also in standard C meanwhile). Though not quite the same, because of usual macro issues such as quoting and multiple evaluation, something in this direction might be a way to actually implement something *like* WriteLn in user code.
Not that I have any intentions to add this in GPC.
BTW, IME, the very large majority of possible applications for requested "varargs" are one of these groups:
- A finite number of cases, which can also be solved with overloading, sometimes even with default parameter values.
- Any number of arguments of the same type (e.g., `Concat' for n string values). Actually, rather rare; can't remember another example right now.
- Yet another form of Write[Ln] or Read[Ln] (the latter much rarer). Such routines are somewhat common in C code (often for error reporting etc.). Usually, though, this boils down to passing the arguments around, ultimately to a predefined routine such as [f|s]printf.
In Pascal we can get a very similar effect by using the standard Write[Ln] routine and (possibly) redefining the output of a (pseudo-)file. (In this case I concur with this suggestion of Chuck's.) Both GPC and BP, and probably other dialects, provide some mechanisms (though slightly different) to do this, e.g. called TFDD (text file device drivers -- not to be confused with OS drivers). Another possibility in Extended Pascal is to use WriteStr and then pass a simple string around.
In both cases, we simply use the special syntax of Write[Ln|Str], also including the `: Width' specifiers which I'm leaving out of the discussion otherwiese for now, and just redefine the target of the text, which is actually the purpose. On the target side, things are much simpler, since the text is already formatted, so number and type of arguments don't matter anymore.
Therefore, I don't think it's reasonable to add a huge framework, just to be able to define one's own WriteLn-(un)like procedure which in the end just passes its arguments on to the real WriteLn ...
- Dont support procedures that cannot be written in the language.
That would be a purist approach (IMHO overly so). C did so with varargs, leading to several weaknesses (again, IMHO) in turn: Varargs functions, predefined as well as user-defined ones, are not type-safe, and printf etc. are more clumsy and dangerous to use for that reason and in principle somewhat less efficient because of runtime parsing.
I've seen other overly purist approaches (such as OO languages where everything, including simple numbers, are objects). IMHO, these may be interesting concepts, but not so useful in practice. So I think Wirth chose a good compromise here.
That leaves Pascal, as it is, with its weaknesses intact. I still consider Pascal to be about the best programming language there is, but that does not mean I don't consider some of its design decisions to be less than optimal.
I agree with the general statement, but not WRT WriteLn (more to things such as lack of `endif' and a few other issues) ...
Frank