Generics, modals, "self", introspection, mode Anything

chris hermansen clhermansen@gmail.com
Mon May 11 01:43:08 GMT 2026


Good evening, Jose, everyone,

On Sun, May 10, 2026 at 4:25 AM Jose E. Marchesi <jemarch@gnu.org> wrote:

>
> Hello Chris.
>
> > Good evening everyone,
> >
> > A few topics that are picked up and put down every so often, some
> mentioned
> > in the meet-up, that I would like to see discussed more fully...
> >
> > I haven't worked with generics nor modals in languages other than Java,
> so
> > my perspective is not particularly rich.  Nevertheless...
> >
> > Java makes extensive use of generics to facilitate static type checking
> at
> > the same time as allowing for extremely flexible typing.  For those of
> you
> > not familiar with this, a nice example of the value provided by generics
> in
> > Java is the Collection class and its various extensions providing all
> kinds
> > of lists, maps, sets and so on.  So assuming one has a class used for
> > aggregating data called Data, then one can create a hashtable-based map
> of
> > (say) string keys to instances of Data as:
> >
> > var myDataMap = new HashMap<String,Data>();
> >
> > and then insert instances of Data into it with
> >
> > myDataMap.put("foo", dataInstance1);
> > myDataMap.put("bar", dataInstance2);
> >
> > and later fetch the values
> >
> > var diFoo = myDataMap.get("foo")
> >
> > By now anybody who is listening is probably sick of hearing me bang on
> > about hash tables, but they really are quite useful...
> >
> > Anyway, back to Algol 68 - I think the suggestion of restricted modals,
> > summarized by Jose and further elucidated by Paul Leyland, could give us
> a
> > way into this kind of flexibility.
> >
> > For reference, Jose illustrated the concept with the following procedure
> > declaration:
> >
> > pub proc qsort = (mode X, ref[]X list, proc(ref X, ref X)int cmp) void
> >
> > And so I assume that we could define a module containing a collection of
> > procedures like
> >
> > pub proc put = (mode X, string k, X v) void
> > pub proc get = (mode X, string k) X
> >
> > I believe the "get" procedure is not feasible however because I think X
> is
> > only known inside the collateral clause parameter list... though I
> suppose
> > it must be also known inside the procedure body {how does that
> > work?}... anyway perhaps get would have to look like
> >
> > pub proc get = mode X, string k, ref X v) void
> >
> > This all seems plausible to me, since I feel that very many uses of this
> > restricted modal concept would want to treat the parametrized mode as
> > something quite opaque; or, if not opaque, then the caller would have to
> > provide one or more "helper" procedures that could provide access to the
> > bits  that must be available within the generic procedure.  The quicksort
> > procedure example of Jose's takes this approach, using a helper procedure
> > to carry out the comparison of the keys of two items on the list.
>
> Right.
>
> In Lindsey's restricted modal proposal, the body of the generic routine
> can only operate on values of mode ref* X.
>

Not sure I completely follow that - do you mean that we can't have "read
only" parameters of mode X?

Also, the business of returning a value of mode X (or ref mode X) - is that
allowed?

It seems to me that if we allow mode X to be defined in the collateral
clause that is the parameter-pack but then be manifest within the procedure
body itself, which is clearly "outside" the parameter pack in some sense,
then we could perhaps allow the return value to be of mode X as well... am
I wrong?


>
> > Of course if we're really going to have a useful hash table facility, we
> > have to have generic keys as well as generic values, so that we can
> > accomodate int, string, Date... whatever keys.  So I guess those put and
> > get procedures would look like
> >
> > pub proc put = (mode K, V, K k, V v) void
> > pub proc get = (mode K, V, K k) V
> > or
> > pub proc get = (mode K, V, K k, ref V v) void
> >
> > Returning to the "what is the scope of the modals" question for a
> minute, I
> > have toyed with the idea that we might want the get procedure to be more
> > like
> >
> > pub proc get = (mode K, V, K k) ref V
> >
> > so that we can use it on the left-hand side of the assignment, that is,
> >
> > get("foo",my_data_map) := data_instance_1
> >
> > thus eliminating the need for a separate put procedure.
>
> Thats a nice idea.  Reminds me of the -> operators I got in place for
> JSON values, that allow syou to:
>
>   JSON_Val cmd := json_new_obj;
>   cmd->"source" := json_escape_string(src);
>   cmd->"base" := style;
>   cmd->"useSpaces" := use_spaces;
>   cmd->"tabWidth" := tab_width;
>
>   string answer = json_str(res->"answer");
>

Exactly!  And you see that you are already liking the procedure (ok
operator, whatever) that returns a reference so that we can assign to
whatever it refers to...

So more leaning into the generic being visible not only to the procedure
body but to the return value as well... ¿No?


> > Anyway!  I think this idea deserves a lot of consideration as I believe
> it
> > works closely with existing Algol 68 concepts (mode declarations and
> static
> > type checking) and makes a huge jump to extensible code that united modes
> > do not come close to providing.
> >
> > Which brings me to my other three topics: "self", introspection and "mode
> > Anything".
> >
> > In reverse order - I claim that modals by themselves do not solve
> problems
> > like InType and OutType. The problem that arises immediately is that
> > operators STRAIGHTIN and STRAIGHTOUT conceal something very much like
> > introspection - they have to be able to look inside of structures in
> order
> > "flatten" the structure into rows of SIMPLIN and SIMPLOUT components.
> >
> > Maybe we would like to use some kind of "compiler writing magic" to
> > implement STRAIGHTIN and STRAIGHTOUT.  For example, I suppose that every
> > time a struct or mode is declared, a hidden pair of STRAIGHTIN and
> > STRAIGHTOUT operators could be declared as part of the structure or mode
> > that could be accessed by any programmer whose magic wand is sufficiently
> > shiny.  Maybe that wouldn't be too bad.  This could also ensure that no
> > operators are created for structures that violate the restrictions
> > mentioned in the RR "a mode which does not contain 'flexible', 'reference
> > to', 'procedure' or 'union of'.
> >
> > However, I find it kind of odd that the only place we seem to have
> > identified the need for these two operators is in transput... can that be
> > right?  So just in case, maybe what should really be generated by the
> > compiler is the introspection data necessary to implement STRAIGHTIN and
> > STRAIGHTOUT.
>
> I agree straightening is best implemented ad-hoc in the compiler.
>
> That said, IMO straightening is specifically tailored to transput, and
> probably nothing else.  It is just marshalling/demashalling built in the
> compiler.
>

Ok, so if we say "straightening is something that only happens in the
transput module", then we MUST have some other mechanism to deal with
marshalling / demarshalling when we need it - or something like it -
somewhere else... like my infamous hash tables, or a linked list library
that doesn't know the mode of the values therein linked... or a stack...


>
> As for Anyode, we know that the Interactive Algol 68 compiler from
> Cambridge Oxford Compilers used to support it, as an union with infinite
> moods, the set of all possible Algol68 modes.  One aspect I like of
> Algol 68 unions, along with uniting, is that it allows the programmer to
> adjust the amount of desired polymorphism and therefore the associated
> run-time overhead: if x is definitely an int, there are no run-time
> checks, but if it may be also a real, the value should be tagged and
> pertinent run-time checks performed before accessing it.
>

I get your point here, and I sort of agree with it.  Aaaaaaaaaaand I would
be prepared to use it were it available.

However, there are no compile time checks with this, since we cannot write
an infinite case clause.  Or am I wrong?

Bringing it down to concrete terms - with modals I can see writing a hash
table "put" routine

proc put = (mode K, V, K key, V value, Hash_Table ht) void: (
ref V value_slot := find_or_create_slot(key, ht);
value_slot := value
);

Or similar-ish.

With Anymode, I am imagining there is some kind of case construct; or maybe
not?  What does some Algol 68-ish code look like?

>
> Let us not underestimate unions: the whole orthogonal syntactic frame is
> oriented towards them, including balancing and operator overloading.
> After all, a firm syntactic position is one in which the a posteriori
> mode of the coercee can be one among _several_ modes, as opposed to a
> strong syntactic position, in which the a posteriori mode of the coercee
> is exactly _one_ particular mode.  In both cases, the desired mode is
> known at compile time: in firm positions, the desired mode is resolved
> statically by balancing all the modes implied by all the available
> versions of the operator.
>

Ok, but if we speak of firm positions and operators, we don't expect to see
a compile time message that says "hey, you're missing a version of FOO that
takes mode Bits", unless you try to apply FOO to a Bits value.

But with unions, we need the case-conformity-clause to address all the
modes united in the union, and if it's union-of-everything, I don't see how
we accomplish that.

Maybe an example?

>
> Adding an AnyMode union to GCC is perfectly feasible.
>
> > Leading to my final topic - "self".  In case anyone is still reading and
> is
> > unaware of what I mean by "self", this would be the ability to declare a
> > structure containing one or more procedures which could operate on the
> > fields of the structure directly.  A simple example (not claiming correct
> > pseudo-syntax here);
> >
> > mode Circle = (real x, y, r, proc real area);
> >
> > Circle c = (3.7, 4.1, 18.0, proc = real: pi * r of self * r of self)
> >
> > or maybe even
> >
> > proc circleArea = real: pi * r of self * r of self;
> >
> > Circle c1 = (3.7, 4.1, 18.0, circleArea);
> > Circle c2 = (0.9, 1.3, 12.0, circleArea);
> >
> > We could think of achieving this as a kind of short hand for something
> like
> > this (which clearly won't work as is but anyway to get the idea across):
> >
> > proc circleArea = (Circle self) real: pi * r of self * r of self;
> >
> > mode Circle = (real x, y, r, proc (Circle) real area);
> >
> > Circle c1 = (3.7, 4.1, 18.0, circleArea(c1));
> > Circle c2 = (0.9, 1.3, 12.0, circleArea(c2));
> >
> > (of course that can't work as written since c1 is not yet available to
> > participate in its own declaration, nor is c2).
> >
> > I know that the "self" concept creates all sorts of interesting
> conundrums
> > in object oriented languages where we also may need to have available the
> > concept of "parent of self"... not sure that would apply if we were to
> > determine how to handle this in Algol 68+.
> >
> > I believe "self" might encourage us to bind data and behaviour more
> closely
> > into more comprehensive mode definitions, which to me is a good way to
> > encourage more maintainable code.
>
> Hehe I absolutely hate this, it breaks like a thousand and a hundred
> language rules, or more :P
>

I'm super cool with alternative suggestions!

>
> An object oriented language design I like is the Ada 95 tagged records.
>
> Using a similar approach, we could have:
>
>   mode Circle = tagged struct (real x, y, r);
>
> Then any procedure declared in the same range that takes a Circle as
> first argument is a method:
>
>   proc area = (Circle c) real: pi * r'c * r'c;
>
> Declaring the method adds an implicit field to the Circle struct:
>
>   proc real area;
>
> That you can access via selection, like any other field:
>
>   area'c
>
> The tagged struct would add a dynamic tag to values of mode Circle, like
> tagged records in Ada 95, that would also allow inheritance, etc.
>

That's quite lovely.  Can you forsee AVW grammar for that?


>
> But if we didn't want to go so far, we could go with something like this
> instead:
>
>   mode Circle = struct (real x, y, r);
>
>   method area = (Circle c) real: pi * r'c * r'c;
>
> I like the tagged approach best though: it is more powerful, and it
> doesn't require adding "methods" to the set of declarable objects..
>

Sure, agreed, because adding something like "method" is not really all that
simple, I think.

>
> > Ok, that's it!
>
> As always, thanks for the awesome food for thought.
> You are the best :)
>

Wow such a nice compliment!

I will respond by saying that I'm not looking for classes, extensions,
implementations etc etc. above, just the way to connect behaviour and data
more closely (because I think that is a really good thing to do in terms of
clarity and maintainability - but heck I could be wrong, I often am).


-- 
Chris Hermansen · clhermansen "at" gmail "dot" com

C'est ma façon de parler.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/algol68/attachments/20260510/b7b73a72/attachment-0001.htm>


More information about the Algol68 mailing list