Related articles |
---|
Compiler writers will love this language ericmuttta@email.com (2003-05-29) |
Re: Compiler writers will love this language torbenm@diku.dk (2003-06-03) |
Re: Compiler writers will love this language vbdis@aol.com (2003-06-03) |
Re: Compiler writers will love this language ericmuttta@email.com (2003-06-05) |
Re: Compiler writers will love this language ericmuttta@email.com (2003-06-05) |
Re: Compiler writers will love this language mwotton@cse.unsw.edu.au (2003-06-08) |
Re: Compiler writers will love this language vbdis@aol.com (2003-06-08) |
Re: Compiler writers will love this language genew@mail.ocis.net (2003-06-08) |
Re: Compiler writers will love this language marcov@toad.stack.nl (Marco van de Voort) (2003-06-20) |
Re: Compiler writers will love this language ericmuttta@email.com (2003-06-20) |
Re: Compiler writers will love this language ericmuttta@email.com (2003-06-20) |
[40 later articles] |
From: | ericmuttta@email.com (Eric) |
Newsgroups: | comp.compilers |
Date: | 5 Jun 2003 23:22:01 -0400 |
Organization: | http://groups.google.com/ |
References: | 03-05-211 03-06-015 |
Keywords: | design |
Posted-Date: | 05 Jun 2003 23:22:01 EDT |
torbenm@diku.dk (Torben Ęgidius Mogensen) wrote:
> ericmuttta@email.com (Eric) writes:
>
> > *if you decide to have _____ then make sure you have/dont have ____
> > due to the way they interact when mixed together
>
> Don't mix unspecified evaluation order with unrestricted side-effects,
> such that the result of a computation may depend on the (unknown)
> evaluation order.
I have often wondered how specifying evaluation order impacts
implementation. The arguments I have heard for it are:
- it allows consistency between different compilers hence allowing
code portability between compilers
- it allows one to take advantage of evaluation order in expressions
The second one sounds dubious at first but thinking about it, we
always rely on our code executing from top to bottom and write the
code so its dependant on that execution order. So then, is it
unresonable to specify that evaluation order is left-to-right (or
vice-versa)? If so, what are the arguments for leaving the order
undefined? (I have heard something related to efficiency and register
allocation during procedure invocations, but no explanation was
given).
> If you have pointers with less-than comparison and arithmetic
> (adding offsets to pointers or subtract pointers to find a
> distance), make it illegal (or at least undefined) to
> compare/subtract two pointers that are not derived on the same base
> pointer (i.e, pointers into the same array or struct).
I think illegal is more like it. If that were allowed, won't the result
*always* point to somewhere that's statically unknown and hence
impossible to prove as legally/safely addressable?
> > * you can include feature _____, its useful and easy to implement
>
> Many things come to mind. Look at SML for a lot of features that are
> nice and (relatively) easy to implement, e.g., higher order functions,
> inductive data types with pattern matching, polymorphism, type
> inference, a good module system, etc.
I haven't had a chance to look at SML yet, but will do soon.
Meanwhile, I am familiar with the above features except "higher order
functions" and "inductive data types". This page:
http://www.dcs.ed.ac.uk/home/stg/NOTES/node31.html
says that higher order functions are "Functions which take functions
as an argument...". Is that similar to function pointers in C/C++
where functions are called by address instead of by name?. On the same
vein, are closures related to this in any way?
> > * keep in mind that ____ is harder to implement than ____ but they do
> > the same/similar thing
>
> OO with dynamic dispatch is harder to implement than polymorphism
> combined with type-classes (as in Haskell), but the latter is just as
> useful (maybe more).
OOP terms seem to have loads of meanings nowadays. When I hear about
"dynamic dispatch" in OOP, I think about how polymorphic invocations
are implemented by using tables of function addresses (eg C++ virtual
tables). It also makes me think about something I have heard being
called "multi-methods". It involves function overloading with
overload resolution occuring at run-time, based on the actual type of
all arguments to the function (this feature strikes me as being harder
to implement than static overload resolution, or atleast harder to
implement efficiently.) Are any of what I have mentioned, what you
mean when you speak of "OO with dynamic dispatch"?
> > * stay away from ____ its not worth the trouble unless you need ____
>
> Mutual inheritance (unless static).
Again, this is a new one to me. Is it about having a class A inherit
from B which inherits from A? If so (due to the circular reference)
how would constructors work in this scenario? What would "static" mean
in this context and how does it help?
> > * look at the grammar for language _____ , its easier/harder to
> > implement because it does/doesn't have _____
>
> Symbol-table dependent parsing, i.e., completely different paring
> depending on whether a symbol is a type name, a variable name or a
> class name. C++ is the prime horror story here, with so many
> context-dependent rules that no parser for C++ is strictky conforming
> to the standard.
I have encountered this one while writing simple parsers. It's a lot
harder to write a parser if each symbol's meaning cannot be resolved
without look-ahead or back-tracking. It's a bit of a trade-off between
having a smaller language (in terms of number of symbols) or a simpler
parser. Languages with fewer symbols will tend to overload many of
them (eg the "static" keyword in C++) and its the symbol overloading
that results in context-sensitive meanings, which in turn make parsing
difficult. Having more *unique* symbols reduces the need to overload
the meanings of symbols, so parsers are simplified because they can
resolve the symbol's meaning without looking at the context of its
occurence. One of the hard parts of language design, is coming up with
good keywords the meaning's of which can easily be guessed at.
> > * language ___ does ____ in this way, but it would be better to do it
> > like ____ because then we would implement it using _____
>
> Many languages implicitly assume that all pointers can be null
> pointers. It is better to distinguish this through the type, so you
> can avoid testing for null pointers when the type ensures it can't
> happen. Ideally, you would have subtyping, so a non-null pointer can
> be passed to a function that expects a possibly-null pointer.
I am having difficulty imagining a type which is implemented using
pointers and ensures that null cant occur. This would imply that for a
variable of such a type, memory would be allocated and then never
released. Memory deallocation is what leads to null pointers and if
the type ensures that you cant have null pointers then it is
implicitly saying you cant deallocate the memory for variables of that
type. Unless ofcourse the language:
1) allowed paramater passing by constant reference (like in C++) and
2) ensured that all pointer parameters were non-null on entry to a
function
then inside a function, we know that the user cant assign a null value
to the pointer (because of rule 1 above) and that the pointer cant be
null to begin with (because of rule 2) so we can remove all null
testing code at each point where the pointer is dereferenced. To do
this for local variables, the language would allow "run-time
constants" where a variable is initialised once (at run time) and
cannot be assigned to from that point on.
Also, on the subject of pointers, I have always been bothered by the
disparity between value types (ie those with value semantics like
int,float etc) and reference types (those with reference semantics
like object variables in OOP).
In Visual Basic for instance, if I dont initialise an integer
variable, its initialised to zero for me and I can use it without
getting some exception thrown (unless ofcourse I divide by zero).
However, with an object variable, if I use it before initialisation, I
get an null reference exception thrown at me. My question is, why dont
I just get an object in its default state (ie the one that would
result after the default constructor has run), ready for use just like
I do with the integer variable? Using lazy initialisation, the
language could leave the reference as null, up until the point I try
to use it. This way I dont have to litter my code with null pointer
testing or "try...catch...end try" blocks. Plus, if I want to
interpret the "nullness" of an object variable to mean something, I
can still test for null and act accordingly. This scheme would
eliminate a lot of error checking code hence allowing code to be
clearer, be written faster, be compiled faster and be smaller.
<snip good recommendation to keep memory management in the language
and I/O in the libraries>
<snip recommendation on good books which I will look at in due course>
> Alas, I know of no good book covering language design. Most modern
> langauges have articles by the designers, presenting the reason behind
> some of the design choices. These are a good place to start. You
> should also read John Hughes' article "Why Functional Programming
> Matters".
I only know of one book on language design and its online too (the
link may break over two lines):
"http://www.awprofessional.com/catalog/product.asp?
product_id={92E30B39-5D91-45F9-9919-D202BE6341F9}"
Thats the Addison Wesley link, but if you Google for "Advanced
Programming Language Design" by Raphael Finkel, you'll find somewhere
to download the PDF files for it.
I also tend to look for language critiques, coding style guides, any
papers with the words "traps and pitfalls", papers that say "X sucks"
where X is the language under fire, and one of the most resourceful of
places: these news groups themselves (especially the language advocacy
groups).
> Torben Mogensen
Thanks Torben, your recommendations have given me plenty to think
about.
Cheers, E.
Return to the
comp.compilers page.
Search the
comp.compilers archives again.