Greetings and introductions
Jose E. Marchesi
jemarch@gnu.org
Wed Jun 18 23:10:04 GMT 2025
> Thanks for the kind email; a few comments following yours below.
>
> On Wed, Jun 18, 2025 at 12:20 PM Jose E. Marchesi <jemarch@gnu.org> wrote:
>
>>
>> Hello Chris.
>>
>> > As a long-time fan of Algol 68, and having written a bit of "real
>> > code" in that language, I struggle to express how delighted I am to
>> > see all the amazing work being put into GNU Algol 68. A heartfelt
>> > thank you to all involved.
>>
>> Thanks to you for getting in touch!
>>
>> > I am no kind of expert in writing compilers (especially GNU cc based
>> > compilers). I have made my living over the last 40+ years writing
>> > mostly data analysis programs in languages including FORTRAN, Pascal,
>> > C, AWK, Java, Groovy, Python, R and Julia. I have built a number of
>> > data-forward web sites in Grails. Over the last 10 years, I have
>> > written about programming for a generalist open source audience,
>> > primarily on https://www.opensource.com, and a bit on
>> > https://www.opensource.net and https://www.both.org.
>> >
>> > After using Algol 68C in my undergraduate years in the latter half of
>> > the 1970s, I haven't done much more with it than wish that I had a
>> > decent Algol 68 compiler since then, until I stumbled on Marcel's
>> > wonderful Algol68g a few years ago. Since that time, I have written
>> > many insignificant programs to recover my knowledge and at one point
>> > built a first version of a hash table capability based on
>> > split-ordered lists(1) in Algol68g, which at least works, but needs
>> > some cleaning up.
>>
>> It would be great to get these hash tables working with GCC. I could
>> certainly make good use of them in some of my projects.
>>
>
> I obtained a working C (or maybe it was C++? I forget) version from a
> colleague and I imagine he would be happy to share with you as he is also
> an Algol 68 fan.
>
> Of course I can share my existing Algol 68 version with you and anyone else
> who wants it. Compared to the C version which fully supports pointer to
> anything, my code is a bit more baroque, needing to deal with UNIONs for
> key and value modes. My hash function is borrowed from Java and in order
> to make it work with Algol 68 Genie it is limited to 2^30 hash keys, which
> seemed like a mostly minor sacrifice for my needs. Also the "get" and
> "put" functions should be operators, and a bit of cruft like that.
>
> One thing I was planning to implement, but I've been stymied with too
> little time to figure out, is to use hash maps instead of structures (à la
> Python or Groovy), which would given me an acceptable way around the strong
> typing in Algol 68 in order to have something like maps of structures; that
> is, having maps of maps instead.
>
> I have some spare time on my hands to try moving it to GNU Algol 68. Given
> your comments below about the compiler's completeness, I may just give that
> a try.
>
> Let me know if you want mine and/or the C (C++) version.
The Algol 68 one :)
>>
>> At the moment, as you probably know, we don't have support (yet) for
>> separated compilation, but we manage by including the files. See for
>> example how the sources are organized in
>> https://git.sr.ht/~jemarch/godcc.
>>
>
> That's how I handled using the hash tables in Algol 68 Genie (as includes).
>
>>
>> We also plan to implement modals, but until we do so, I suppose using
>> your hash table implementation will require to manually define some
>> modes before include the source file...
>>
>
> See my comment above about maps of maps, which may be an acceptable
> workaround for some of us.
>
> But yes I think the only way to make hash tables generally work with Algol
> 68 modes is to have access to united modes similar to SIMPLIN at least, and
> with some way to handle STRUCT values.
The ALGOL-68RS compiler, and its retargetted algol68toc, implements an
extension that allows programmer to do straightening explicitly, the
form of a new mode STRAIGHT and a new coercion "straightening" available
in strong contexts.
The extension was provided mainly to allow implementing unformatted
transput in Algol 68, and I am considering to implement it for that
purpose, and also because it provides a great level of introspection for
user-defined modes... maybe to the level of facilitating hashing them?
>From the rscompiler manual:
D.3 Straightening
A `straightening' facility is provided to enable Algol 68 programmers
to write transput procedures with arbitrarily structured
parameters. Straightening is the reduction of any type of data
structure to a simple sequence - which we shall describe as a
straight. The basic step is the coercion of a simple row or structure
to a straight; applied recursively, the method can be used to
straighten data structures of arbitrary complexity.
The mode STRAIGHT U, where U is any Algol 68 mode (but most commonly a
union), describes a set of objects of mode U. In this respect it is
similar to [] U, but in other respects it is quite different and must
be treated as a new type of mode. An actual straight is brought into
existence by strong coercion of a row, vector, structure, i-struct or
union. Such modes are strongly coercible to STRAIGHT U if their
"members' can be coerced to U by uniting, straightening or any of the
coercions i-struct to vector to array (A4.1). The coercions excluded
are dereferencing, deproceduring, widening and rowing.
Example 1
STRAIGHT UNION (INT, CHAR) s1 = "ABCD"
As CHAR is coercible to UNION(INT, CHAR), the i-struct "ABCD" can be
coerced to the STRAIGHT. If s1 were the formal parameter of an output
procedure, acceptable actuals would be a row of characters, row of
integers, structure with integer and character fields or a union of
integer and character. However, a single INT or a single CHAR would
not be accepted.
Example 2
STRUCT (INT i, REAL r) p;
STRAIGHT UNION (REF REAL, REF INT, REF CHAR) s2 = p
The members of p have modes REF INT and REF REAL, both of which are
coercible to the given union, so p will be coercible to the mode of
s2. Clearly, s2 might be the formal parameter of an input procedure
and p its actual parameter. The actual could not be a simple real,
integer or character variable.
Example 3
[3] INT v := (1, 2, 3);
STRAIGHT INT s = v;
In this example, the members of the variable v have mode REF INT, but
s is a straight of plain integers. As it stands, v cannot be
straightened to s because dereferencing of members is not allowed. But
as v can be dereferenced before straightening, the example is
correct. Consideredas a formal parameter for an output procedure, s
would handle any row or structure of integers, but not a single
integer by itself.
As a straight cannot represent an unstructured value, most
applications will demand that it be combined with basic modes in a
union, eg
UNION (INT, REAL, ... , STRAIGHT UNION (INT, REAL, ... ))
This mode will handle an object of data which possesses structure at
no level (eg an INT) or one level (eg [] REAL, STRUCT 17 INT) but not
more. When an object is being united to the above mode, then ---
regardless of the order in which the constituent modes have been
written --- the fit will be sought from the non-STRAIGHT modes first,
so as to avoid any possible ambiguities of coercion.
To handle one object structured at any number of levels, a recursive
mode is needed.
MODE PRINTMODE = UNION (INT, REAL, ... , STRAIGHT PRINTMODE)
The definition of STRAIGHT is such as permits this recursion. PRINTMODE
will handle an integer, real, etc, or any row or structure built up
from all these to any depth. For a corresponding input parameter mode,
the basic modes would each be preceded by a REF.
The parameter of the standard print procedure has mode VECTOR []
PRINTMODE rather than RINTMODE. This allows the use of a collateral as
the actual parameter.
A straight cannot be handled with the full generality applicable to
other Algol 68 modes.
The manipulations are confined to subscripting and interrogation by the
operator UPB. Let m stand for any mode, and let s have mode STRAIGHT
M. Then UPB s gives the number of objects in the straight, and s[i]
picks out the ith object (i >= 1). There is no such thing as a STRAIGHT
generator or variable because objects of mode REF STRAIGHT do not
exist.
>
>>
>> > As a great fan of Java, I would love to see Algol 68 evolve a little bit
>> in
>> > the direction of being object-oriented; thinking specifically of STRUCTs
>> > that could refer to "self", simple / single inheritance, MODE templates,
>> > interfaces. From my perspective, that would require some very careful
>> > thinking and design work and being willing to draw a boundary much closer
>> > to Algol 68 classic and much further away from C++.
>>
>> I am personally not the biggest fan of object orientation, but having
>> support for it in an "Algol 68 way" would be useful to have, and quite
>> interesting to design.
>>
>
> I think that point is key. From the point of view that the two level
> grammar and extreme orthogonality buy so much when applied to what amounts
> to what is otherwise a pretty small language definition, how might modest
> but useful object orientation fit into that design?
>
> I've never used Simula but there might be some clues there.
Yes that's the challenge...
>
>>
>> > I might be in the minority but I would see this extension being much
>> > more useful than implementing transput in all its "glory".
>>
>> I agree with that. There are a lot of good ideas in the standard
>> transput that I think would be useful to recover, but after some (much?)
>> modernization.
>>
>
> Or... implement printf and scanf? Just sayin'... Seems like those would
> be pretty straightforward in Algol 68 since one would only have to deal
> with base types.
I was thinking more about unformatted transput, straightening, the
handling of encoding, event-driven handling of transput errors and
conditions (this can be "merged" with the exceptions mechanism we adopt)
etc.
My feeling is that formats are simply too complicated, but I have never
used them myself for anything more complex than toys, so the feeling is
in no way backed by any actual experience...
>>
>> > But nevertheless, having two great mostly standard Algol 68
>> > implementations is an unimaginable richness!
>>
>> Right now ga68 is basically complete in terms of standard Algol 68,
>> modulus parallel clauses, which are currently handled like collateral
>> clauses. The compiler is slow and the generated code performs much
>> avoidable copying (the bane of Algol 68 compilers ^^) so now I am busy
>> adding some much needed optimizations.
>>
>> We have a long list of extensions we want to to implement, like support
>> for modals, partial parametrization, separated compilation, exceptions,
>> etc, but always keeping our extended language a strict Algol 68
>> super-language. You can see a list of extensions already implemented at
>> https://algol68-lang.org.
>>
>
> I believe that is a really sound approach. The alternative of willy-nilly
> gluing stuff on will not end well.
>
> In my opinion, we have collectively learned some pretty cool things at a
> conceptual level since the late 60s / early 70s. The issue is to look at
> which of those conceptual things are outside the current design of Algol 68
> but amenable to being added, and most importantly worthwhile. Of course
> it's also worth identifying what cool things are within the capability of
> Algol 68 - my favourite example being closures, which are easy to do as-is
> - and celebrating that as a demonstration that the overarching design
> principles applied to Algol 68 remain valid.
>
> And as I said above, I think there is a strong argument to be made for not
> investing scarce resources in implementing the full transput package, and
> possibly others (I've heard surly comments about the limited utility of
> parallelism as defined in Algol 68, but again I'm no expert on that
> topic).
Yes I have also read comments on that regard.
An alternative way of handling parallelism in Algol 68 was actually
implemented as an extension by the algol68-s compiler: "eventual
values", which involves two coercions "evening" and "deventing".
This is an excerpt from the ALGOL-S user manual:
Parallel-clauses have several disadvantages. First, the fork and join
points must be nested not only with respect to other parallel-clauses,
but also with respect to the routine and range structure of the
program. This can be undesirable if an activity to be started in
parallel does not interact with the further elaboration of other
activities. A particular irritation is that it is not possible to
start an activity within a routine and have it complete after the
routine. Second, since the piece of program which may be initiated in
parallel is a void unit, a parallel activity may not return a value
except through the use of global variables. The possibility for
programmer error is increased because other parallel activities may
access these variables. Alternatively, the programmer may decide to
use parallelism only for subprograms which return no values. This has
the unfortunate consequence of reducing the amount of parallel
processing. Finally, synchronization within the parallel-clause scheme
is accomplished by scattering up and down operations throughout the
program. This decentralization of control can be as difficult for
programmers to deal with as the unrestricted use of the goto.
The idea behind eventual values may be seen by considering the
following piece of program:
real x, y;
x := sin (3.2);
unit1 .... ; unitn;
y := x + 1.0
When more than one processor is available it would make sense to allow
sin (3.2) to be computed in parallel with the elaboration of the first
assignation and the units Unit1, ..., UnitN. In this case the value
assigned to x can not be the desired real value since it is not
necessarily available at the time of the assignation. The value
assigned is one which will eventually (when the call completes) be a
real value. We call this kind of value an eventual real value. When
the second assignation is reached it is necessary to produce a real
value from the eventual real value; that is, the program must wait for
the call of sin to complete. These ideas are incorporated into the
language by formally defining an eventual value to be a new object,
and by introducing two new coercion actions, deeventing and eventing.
The mode of an eventual value is event amode, where amode is any
mode. An event amode value is composed of a status, which is either
complete or incomplete, and an amode value.
An event amode value may be "deevented" to an amode value much as a
proc amode value may be deprocedured to an amode value. In fact,
deeventing may occur in the same syntactic positions as
deproceduring. Deeventing is used to wait for the amode value to be
computed. Specifically, if an event amode value has a status of
complete, then its amode value is yielded by deeventing. If the status
is incomplete, deeventing causes the current activity to be halted
until the status changes to complete. Then the activity is resumed and
the amode value is yielded.
An amode value may be "evented" to an event amode value. This coercion
may occur in firm and strong syntactic positions. if the construct to
be evented is a call or formula which returns an amode value then the
routine is invoked as a parallel activity and the yield of eventing is
an event amode value with incomplete status. For other constructs the
yield is an event amode value which is complete and has the amode
value associated with it.
The previous example may be written as follows:
event real x; real y;
x := sin (3.2);
unit1 ; ... ; unitn;
y := x + 1.0
The mode of x is ref event real. The call of sin occurs in a strong
event real context. The mode of sin is proc (real) real, so it is
evented by initiating a parallel activity and yielding an incomplete
event real which is assigned to x. When x is used as a real operand it
is dereferenced and deevented. The deeventing waits, if necessary, for
the parallel activity to complete and return the real value which is
needed.
Another useful application of eventual values is to start the parallel
elaboration of an independent action. For example,
mode task = event void;
...
task (print ((a, b, c)));
...
The cast puts the call to print in a strong event void context, so the
call is made in parallel. The program never waits for the completion
because no deeventing ever occurs. Remember, the cast is a comorf and
is voided directly. If it were necessary to wait for the completion,
the following could be written:
task x;
x := print ((a, b, c));
x; { wait }
The applied identifier, x, is not voided directly, so deeventing occurs and
causes a wait.
By now the reader can understand and appreciate the beauty of this final
example:
op + = (event [,] real a,b) [,] real: ... { usual matrix add };
op * = (event [,] real a,b) [,] real: ... { usual matrix multiply };
[1:10,1:10] real a, b, c, d, x;
x := a*b + c*d
>
>>
>> So the world domination plan goes like this:
>>
>> 1. Modern Algol 68 compiler in the form of a GCC front-end, functionally
>> complete. This is basically done. Then optimize the front-end,
>> which is work in progress.
>>
>> 2. Add extensions to the language, carefully describing them both
>> formally and informally, with two main goals:
>>
>> 2.1 To fill gaps in functionality. Examples of these kind of
>> extensions are modules, exceptions, modals, OOP, etc.
>>
>> 2.2 To modernize the language. Examples of these kind of extensions
>> are the modern SUPPER stropping, bold taggles, nestable comments,
>> etc.
>>
>> 3. Use the language! I am already writing some of my new programs in
>> Algol 68 ;)
>>
>
> Sounds like a winning plan! The only thing I would add is the need to
> spread the good word, and I'm certainly willing to help with that (as well
> as any other contributions I could make to your items 1, 2 & 3).
Thank you!
I am preparing some materials for a few talks and articles about the
project, as time allows. I also plan to speak about the GCC front-end
implementation in this year's GNU Tools Cauldron conference in
September.
>
>>
>> > As to this GNU Algol 68 project, I am excited to try out the compiler as
>> it
>> > develops. I'm happy to contribute in the way of testing (of course
>> > contributing any code that might be useful) and writing. And of course
>> to
>> > cheer you all on!
>>
>> Welcome :)
>>
>> First step is I guess to get a ga68 compiler up and running. Debian and
>> Ubuntu Experimental distribute prepackaged versions of the compiler, but
>> at this stage it is always better to compile your own and keep it up to
>> date so problems can be reported and fixed.
>>
>
> I've done that (Ubuntu 25.04)! I encountered a few minor challenges in the
> build and testing process:
>
> 1. I needed flex for something, which I installed and restarted from
> configure;
That is probably required by either the C or the C++ GCC front-ends,
which are built automatically.
> 2. I needed makeinfo, but the only thing I can find in the repo is
> texi2html, though Debian seems to indicate that makeinfo has
> superceded texi2html;
apt-get install texinfo
> 3. I ran into what I think might be a bug in puts() where "\n" is not
> interpreted as a newline.
The standard hardware representation mandates that string breaks shall
begin with apostrophe. This is an excerpt from the ga68 manual, section
"String breaks":
4.6 String breaks
=================
The intrinsic value of each worthy character that appears inside a
string denotation is itself. The string ‘"/abc"’, for example,
contains a slash character followed by the three letters ‘a’, ‘b’ and
‘c’.
Sometimes, however, it becomes necessary to represent some non-worthy
character in a string denotation. In these cases, an escape
convention has to be used to represent these extra string-items. It
is up to the implementation to decide this convention, and the only
requirement imposed by the Standard Hardware Representation on this
regard is that the character used to introduce escapes, the “escape
character”, shall be the apostrophe. This section documents the
escape conventions implemented by the GNU compiler.
Two characters have special meaning inside string denotations: double
quote (‘"’) and apostrophe (‘'’). The first finishes the string
denotation, and the second starts a “string break”, which is the Algol
68 term for what is known as an "escape sequence" in other programming
languages. Two consecutive double-quote characters specify a single
double-quote character.
The following string breaks are recognized by this compiler:
''
Apostrophe character '.
‘n
Newline character.
'f
Form feed character.
'r
Carriage return (no line feed).
‘t
Tab.
'(list of character codes separated by commas)
The indicated characters, where each code has the form ‘uhhhh’ or
‘Uhhhhhhhh’, where ‘hhhh’ and ‘hhhhhhhh’ are integers expressing
the character code in hexadecimal. The list must contain at least
one entry.
A string break can appear as the single string-item in a character
denotation, subject to the following restrictions:
• List of characters string breaks '(...) that contain more than one
character code are not allowed in character denotations. If the
specified code point is not a valid Unicode character then the
value of the denotation is ‘invalid char’.
You may want to take a look at the ga68 manual. It documents the
implementation-specific preludes, the supported stropping regimes, etc.
It is built when you build GCC with the algol 68 front-end.
The manual is still of course work in progress, but already useful,
hopefully.
>> There is some documentation on how to build ga68 at
>> https://gcc.gnu.org/gcc/Algol68FrontEnd.
>>
>> > And thanks again, with great hopes for success!
>> > --
>> > (1) SHALEV, O. and SHAVIT, N. 2006. Split-Ordered Lists: Lock-Free
>> > Extensible Hash Tables. Journal of the ACM, Vol. 53, No. 3. ACM, New
>> York.
>>
>
> Very excited! If it doesn't create too much noise for the list, I'll post
> the occasional comment / code snippet here.
Sure, that would be awesome :)
Salud!
More information about the Algol68
mailing list