Mixed stuff

Hans-Dieter Dreier Ursula.Dreier@ruhr-uni-bochum.de
Sun, 14 Feb 1999 03:37:36 +0100


This posting contains some rather mixed stuff.
Some of the parts relate to former discussion threads;
you may need to look them up to get the proper context.

I got a new nice language link on Haskell for the link collection:
http://www-i2.informatik.rwth-aachen.de/Haskell/


An idea regarding the use of methods with zero parameters:
==========================================================

In Eiffel (as in Pascal) you need not write the parens ()
to actually call the method if it has no parameters.
I used to dislike this because you don't see that a function call
happens.
But in this Eiffel page I looked at,
the author stated that a parameterless function
can actually be viewed as some form of a (read-only) member variable.
This has the advantage that you can change
the implementation of that "feature" (Eiffel speak for instance item)
if you see that some compilation is needed
or want to write-protect the member variable,
without having to rewrite the classes' clients.
This sounds quite sensible to me. Two questions come to mind:

Q: How do you revent execution if you actually
want a reference to the feature?
A: Have the appropriate type (ref <type of the feature>)
as a required type.

Q: Do you need to recompile clients?
A: Yes, except when the VM would be able
to insert the necessary dereferencing
(which sounds rather messy to me).
This is a little disadvantage, but recompilation
may be required anyway most the time when an implementation
of a client class changes (because method addresses change).


aClass::aMethod (int p1) vs. aFunction (aClass this, int p1)
============================================================

If you compare the above, what's the difference?
aMethod is in aClass's namespace
and has an implicit parameter ("this").
aFunction has this parameter explicit
and no access to aClass's namespace.
IMHO the *compiled* code for those examples
may actually be *identical*.

Am I right?

If so, I find this quite interesting and I wonder
whether this can be used to enhance the expressiveness
of our proposed language in some way.

I'm thinking of automatic conversions, for example.
Remember the old problem of dyadic operators
which are commutative and
take parameters of *different* types.
You got to supply *two* versions:

doItX (a, b)
doItY (b, a)

both actually doing the same thing
(of course, one would call the other with parameters
exchanged, and that one would do "it").
Only one of them can be a class member, though,
because "this" is always the *first* parameter.
The other function must either be
of global scope or belong to the other class,
both of which is not quite satisfactory.

Actually, I don't know what can be done about that.
I just want to direct your attention to this issue.
Any ideas on this are welcome.


Impressions on how to design a syntax
=====================================

Sounds rather vague, isn't it?

I read an article (& follow-ups) in comp.lang.eiffel
on how it feels to program in C++ and java
and find it very interesting from a psychologival
point of view. Remember, as we are humans and not
compilers, the psychology of programming is quite
important; IMHO one is well advised to consider this
for a language to be a success.

If someone likes to read it, here's the path:

From: fungus <spam@egg.chips.and.spam.com>
Newsgroups: comp.lang.java.advocacy,comp.lang.c++,comp.lang.eiffel
Subject: Re: C++ Peeve of the day - SIFI & access control
Date: Wed, 10 Feb 1999 04:53:32 +0100
Organization: SERVICOM
Lines: 105
Message-ID: <36C102BC.A7DC3588@egg.chips.and.spam.com>
References: <796db4$j31$1@nnrp1.dejanews.com>
 <MPG.11215e0c5ae337d0989700@news.teleweb.at>
 <36BA1FEE.3C32C1EE@egg.chips.and.spam.com>
 <36bcf197.0@usenet.ugsolutions.com>
 <36BEDCDA.4972@dmu.ac.uk>
 <36bfc963.0@usenet.ugsolutions.com>
 <36bff356.208397770@news.bctel.ca>


I'd like to make some (rather provocative?) claims:

1. Having multiple ways of doing something
that are effectively equivalent is no good thing
(C example: a->b or (*a).b or a[0].b)
because it imposes design decisions on the programmer
that are completely superfluous and can only serve
to annoy the occasional reader of the code
who would do it the other way round.

It's far better to have exactly one
(intuitive, of course!) way to write things.

Same applies to layout.
It's far better to have some fixed layout
which the editor automatically uses than to do that yourself.
See my notions on outline editors in a former thread.

At our company we are working with a
version control system that merges source files
if two programmers happen to change
the same file concurrently. It does a great job
(it can do so because it takes older versions of that file
into account), but guess what happens if I hit
Alt+F8 to pretty-format my source?
Two lines become different just because of layout.
I have to view them all,
just to make sure not to miss a real change.

2. Use of special characters.

Just stick to the basic set which is well-known:
+-*/<=>[] and the like.
Use words for the rest, or (better) have the editor
be intelligent enough that it supplies a "form"
to be filled out.

I especially hate {curly brackets}.
Small wonder that there are "conventions"
on where to place them;
they are barely distiguishable from ().

I briefly looked at Haskell,
which uses special chars rather differently
than usual (if you are used to imperative languages)
and I find it hard to read because of their use
of special chars.

3. A language should be designed to make
it easy on the compiler, even if this means
that the programmer has to write a little more.
If you look at C++ error messages,
you see what happens if this is not the case:
Forget one { and you get *lots* of messages
which are quite unrelated to the real error.
An (admittedly extreme) counterexample is Centura's 4GL,
where you got to write "Set X = Y" for an assignment.
At first I found that annoying, but I quickly got used to it.
And it has the advantage that you *always* get
exactly *one* error message per error
that is *correct* and the syntax check
can be continued past the error location.
(Please, this is just an extreme example;
I'm not saying that it should really be done so,
but syntax robustness, error recovery and
error message validity certainly are issues).

4. Why do I have to declare scratch variables myself?
I'm a lazy guy when it comes to programming
and like to avoid having to state the obvious:

aThing aVariable; // why can't the compiler insert this for me?

aVariable = someThing;
...

Before you flame: Of course I don't want to go back to BASIC.
It's just that the compiler knows all it takes
for a really intelligent guess: The name is known;
the type can (usually) be inferred from the usage;
access properties can be guessed as "local variable".
I would like the compiler to insert that definition,
flag it as "compiler generated" (shown in some other color, perhaps)
and (optionally) issue a warning.

If the compiler finds a declaration that is no longer used,
it should comment it out and mark that as "compiler generated";
if the declaration was compiler generated in the first place,
it should be removed completely instead.

The same should happen for pre- and postconditions,
invariant conditions, "throws"-declarations (Java style),
"constant" assumptions and similar things,
maybe even "private" access restrictions (?).
If the compiler generated items no longer apply due to a code change,
they should be removed automatically during compilation.
That would be a great auto-comment utility.
If the programmer cares to read those items,
he may even find logical errors in his program
that would otherwise only show up during testing.
If the programmer chooses to elect the compiler generated items
to be mandatory, he would remove that "compiler generated" tag
from the item. After that the item would be treated
as if it were written by the programmer.


Hans-Dieter Dreier