Mixed stuff

Matthew Tuck matty@box.net.au
Mon, 01 Mar 1999 21:58:51 +1030


Hans-Dieter.Dreier@materna.de wrote:

>> Not sure how.  Can you give an example?  I think there might be some
>> problems with this facility, I'll have to check.
> Example: lazy evaluation of parameters. Someone chooses to write a method
> call as an actual parameter, and wants to evaluate that lazy (when and if
> it is actually needed). We got to pass a reference to that parameter to
> the function that is called.

>> I meant to say, all accesses to variables in an object - local variables
>> would be accessed as normal.
> I still can't see why. Could you please explain ?

Well every type has to be laid out so that it can support get/sets,
since it is unknown whether implementations will use a variable or
computation.

> That's true. I wonder which way is better:
> C++ assumes static dispatch for efficiency,
> Eiffel assumes dynamic dispatch to reduce fragility.

C++ isn't more fragile, it's really that Eiffel chooses flexibility.

> Certainly the user should have the chance to override whatever the
> compiler assumes as a default.

Well the language is the language - if it provides that facility, then
the user must choose optimisation and recompilation or neither.
 
>> Hmm, I think the JVM does something to avoid this - can't remember what
>> though.
> If you find out, please let me know.

I did a search on fragile superclass.  The answer is that Java does not
work out the layout of its classes until runtime, which in Java is link
time.

We could easily do the same thing with ASTs, identifiers are used rather
than offsets.  Link time is then the final monolithic step where modules
are combined and program wide optimisation might be done.

See "http://java.sun.com/docs/white/langenv/Interpreted.doc1.html".

>> Dynamic dispatch is there because it improves flexibility.  An optimiser
>> can remove its overhead if it's not needed, including, but not
>> necessarily limited to, static dispatch determination, subsequent method
>> inlining, and table method elimination after there are no possible uses
>> of it exist.
> At the expense of having to do global analysis, yes.

That's the tradeoff of object-oriented programming.  There really isn't
any other way within OOP.  OOP gives enough flexibility to eliminate the
efficiency loss, which can be negated through both program optimisation
and increased time available to manually improve algorithms.

> BTW, if we implement weak pointers, table elimination may be done by
> GC. There's a lot of eliminations GC can do for us.

Well eliminations are a mark-sweep algorithm, which is the same
algorithm nonincremental GC uses.  Often the difficult part of
elimination is determining just what the relationships are.  Things like
dynamic dispatch complicate the situation.  How are weak pointers
relevant?
 
> Yes. It's the old problem that you can look at conversions to be *to* or
> *from* some classes, but you can normally only implement the *to*
> direction inside the class using normal methods and the *from* direction
> using constructors, which (at least in C++) involves different syntax
> (return...), so sharing a common function would be impossible.

> IMO, a conversion should be coded only once and be visible to *both*
> classes, in different roles. That would help to avoid having ambiguous
> conversion paths.

Well given that the type has sufficient interface to query and set the
full state (and if it's a type that can be value copied, why not), you
could just have one converter for the whole type outside of any
implementation.  Or you could increase efficiency and create a native
converter for each impl, creating m.  Of course, the fastest would be a
cross-product, for m^2 converters.  I hasn't thought of trying just one
converter for the whole type before.

> If either class were deleted, the conversion would also be deleted.

While you're at it, why not anything that uses the type or
implementation?
Maybe something like a view which shows the user what elements use other
declarations that don't currently exist, and let you delete them.  It
can be ia view since it's really a presentation of the AST.  Again, I
think deleting it automatically might not be good if you intend to
replace the type.
 
>> I'm not sure what you mean by "representations transformable", but if I
>> said it, I agree.  =)
> I mean, you can take a program that was edited with one editor, put it
> into another editor, change it there using the syntactic sugar that is
> defined there, reload it into the first editor where that sugar is not
> available, and it will show the *equivalent* syntactic construct without
> the sugar.

Yes, the lack of this facility is what has caused other schemes to fail
- for example, some programmers define their own little macros for
language constructs in C - making it unreadable to everyone else.
 
> The more complicated the syntax, the more difficult to produce meaningful
> error messages because the number of possible error scenarios gets too
> big. That may not be true in any case, but IMO in general it is.

I would say most complicated languages are complicated in their checkers
not parsers, where no real error recovery is needed.  But I suppose a
simpler syntax would lead to a simpler parser leading to more time to
work on error recovery.

> I wrote an interpreter many years ago that had an extremely simple yet
> powerful syntax (no static type checking, though). I always got decent
> error messages.

Do you still have it around as an example?
 
> As I have heard, Emacs is a pretty powerful and very customizable editor.
> Do you know anything about it? I personally wouldn't like to program Yet
> Another Text Editor.

Yes, I used Emacs as my primary text editor is University.  Basically it
has a LISP interpreter built-in that is used to extend it.  It can do
some rudimentary intelligent things, like syntax highlighting,
bracketing matching and I think outlining.  But in the end a text editor
will always be a text editor.
 
>> Well the reason we have explicit declarations is so a programmer has to
>> go through and write the type in, to avoid typing errors.  I didn't want
>> to lose that.  You wanted to make things easier to write.  I was trying
>> to go somewhere in between.
> There is a general solution to issues like this: Make it customizable. Who 
> wants it may use it; who doesn't want it, may switch it off.

Certainly, but you also have to pick your fights.  Would allowing this
option, which could increase bugs and is very tempting, warrant the
effort, or do other things warrant it more?

This being said, type inference is not new, and there are many
supporters.  I'm not aware of it being done in imperative languages
though, although it probably has been.  There's not quite as much
argument against it as back in the old implicit just-about-everything
days.
 
>> Agreed, though I would prefer not choosing a name, requiring it to be
>> entered, otherwise we'll end up with silly names being left around.  As
>> much as we might complain about extra effort, programmers are lazy, and
>> often we'll just not do something if we don't need to, even if we
>> should, like choosing a good name.  Some do, some don't.  This would just
>> be enforcing what we all know is best.  If "x" is the best you can think
>> of, so be it, but we shouldn't encourage it.
> See note above. If it comes to programming GUIs, one can pretty soon loose
> the desire to attach a meaningful name to each new control. And if there
> is a context-aware renaming utility (I'd love that), no harm is done if
> the window was named wnd23.

When you lose the desire it's probably that you're being lazy.  GUI code
isn't amazingly enthralling.  But that doesn't change the fact you
should be doing it.  Not many GUI components couldn't be given good
names.

Don't get me wrong - I support user choice, but not when I perceive it
degrades the programming experience as well as increasing complexity. 
And programming with as few bugs as possible should be a non-negotiable
thing.
 
> >Yes, but I was thinking more about back-end effort in the logistics of
> >doing all those actions.
> What do you mean by that? back-end = compiler ?

I meant all the type inference algorithms.

> Certainly we should be careful about letting the compiler do irreversible
> changes to a program. I think a lot of this needs to be evaluated in
> everyday programming business. I'm just uttering some ideas here that come
> to my mind everytime when the C++ compiler or the IDE forces me to type in
> a lot of stuff that I deem unnecessary.

That's where the best ideas come from.  =)

> BTW, if you lean back and think it over, you may find that the compiler
> already *does* a lot without asking you explicitly. I found that out the
> hard way when I wondered why something wasn't doing what I wanted it to
> do: Wrong (local) assumed storage class of some intermediate value (that I
> wasn't even aware of), which went out of scope prematurely. Sure this is a
> beginner's mistake, but doesn't it fall into the same category?

I'm not quite sure of your example.  Could you elaborate?

-- 
     Matthew Tuck - Software Developer & All-Round Nice Guy
             mailto:matty@box.net.au (ICQ #8125618)
       Check out the Ultra programming language project!
              http://www.box.net.au/~matty/ultra/