• Algol68 / Genie - ASSERT isn't NIL, but "access NIL" runtime error?

    From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.misc on Sat Sep 27 17:28:38 2025
    From Newsgroup: comp.lang.misc

    Is that a Genie bug (or may I be missing something)...?

    ASSERT (snake ISNT NIL);
    ASSERT (head OF snake ISNT NIL);
    coord OF head OF snake := new_coord;
    1
    a68g: runtime error: 1: attempt to access NIL name of mode REF SEGMENT,
    in VOID closed-clause starting at "BEGIN" ...

    (where coord and new_coord are plain STRUCT types, no REFs).

    In the context of the untriggered ASSERTs, how can there be a
    NIL access violation?

    Janis, puzzled
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andy Walker@anw@cuboid.co.uk to comp.lang.misc on Sat Sep 27 20:50:41 2025
    From Newsgroup: comp.lang.misc

    On 27/09/2025 16:28, Janis Papanagnou wrote:
    Is that a Genie bug (or may I be missing something)...?

    "Missing" is intrinsically more likely, but "bug" is far
    from impossible!

    ASSERT (snake ISNT NIL);
    ASSERT (head OF snake ISNT NIL);
    coord OF head OF snake := new_coord;
    1
    a68g: runtime error: 1: attempt to access NIL name of mode REF SEGMENT,
    in VOID closed-clause starting at "BEGIN" ...

    "NIL" usually needs a cast in such contexts; in list or tree processing, "snake" [or whatever] would usually /point/ to "NIL" rather
    than /be/ "NIL" for an empty list. That's why people usually declare
    something like "REF SNAKE nilsnake = NIL;", then test "snake" for being "nilsnake" rather than "NIL". Or you may have been careful about the
    mode of "snake"! The other main possibility is that you've somehow
    managed to switch off assertions.

    HTH!
    --
    Andy Walker, Nottingham.
    Andy's music pages: www.cuboid.me.uk/andy/Music
    Composer of the day: www.cuboid.me.uk/andy/Music/Composers/Goodban
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.misc on Sat Sep 27 22:38:24 2025
    From Newsgroup: comp.lang.misc

    On 27.09.2025 21:50, Andy Walker wrote:
    On 27/09/2025 16:28, Janis Papanagnou wrote:
    Is that a Genie bug (or may I be missing something)...?

    "Missing" is intrinsically more likely, but "bug" is far
    from impossible!

    ASSERT (snake ISNT NIL);
    ASSERT (head OF snake ISNT NIL);
    coord OF head OF snake := new_coord;
    1
    a68g: runtime error: 1: attempt to access NIL name of mode REF SEGMENT,
    in VOID closed-clause starting at "BEGIN" ...

    "NIL" usually needs a cast in such contexts; in list or tree
    processing, "snake" [or whatever] would usually /point/ to "NIL" rather
    than /be/ "NIL" for an empty list.

    I've over the past days added all sorts of REF-casts but in cases of
    necessary REF-casts it usually gets reported; and here I haven't got
    any such error message.

    Changing the assert to ASSERT (REF SEGMENT (head OF snake) ISNT NIL);
    triggers an error though, so this is the essential hint! - Thanks.

    When I'm (paranoidal) now changing all REF-based expressions and NIL
    values using such "REF SEGMENT (...)" it indeed "works". Great!
    (Not that the code would look nice with all the casts. But, well.)

    BTW, the expression above where the error was reported needed *no*
    cast to fix the issue. - That was part of me getting mad about that
    error.

    That's why people usually declare
    something like "REF SNAKE nilsnake = NIL;", then test "snake" for being "nilsnake" rather than "NIL".

    Or you may have been careful about the mode of "snake"!

    Don't know what you mean here. 'MODE SNAKE = ...;' and 'SNAKE snake;'
    is nothing strange or overly complex in any way. The only referenced
    items (excluding REF function parameters) are 'REF SEGMENT' entities,
    so I can focus on these.

    The other main possibility is that you've somehow
    managed to switch off assertions.

    No, I already had an additional "ASSERT (FALSE);" tested, and it got
    triggered.

    HTH!

    Yes, indeed. Many thanks! :-)

    Carrying on... (to fix a more "conventional" error now)

    Janis

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.lang.misc on Sat Sep 27 20:47:59 2025
    From Newsgroup: comp.lang.misc

    On Sat, 27 Sep 2025 20:50:41 +0100, Andy Walker wrote:

    On 27/09/2025 16:28, Janis Papanagnou wrote:

    ASSERT (snake ISNT NIL);
    ASSERT (head OF snake ISNT NIL);

    "NIL" usually needs a cast in such contexts ...

    Then lack of same would cause a compile-time error, not a run-time error.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andy Walker@anw@cuboid.co.uk to comp.lang.misc on Sat Sep 27 23:15:01 2025
    From Newsgroup: comp.lang.misc

    On 27/09/2025 21:47, Lawrence DrCOOliveiro wrote:
    On Sat, 27 Sep 2025 20:50:41 +0100, I wrote:
    "NIL" usually needs a cast in such contexts ...
    Then lack of same would cause a compile-time error, not a run-time error.

    No it wouldn't. It's a matter of how the modes [types] are
    balanced. If "snake" is a pointer [ie, has a "REF REF ..." mode] then typically "snake ISNT NIL" because that "NIL" is assumed to be of the
    same type as "snake". If you are testing for an empty list -- the
    usual case, though there are exceptions -- then you need to test what
    "snake" points to rather than "snake" itself. If you dereference
    "snake" [which is what Janis's cast does] then the "NIL" is equally dereferenced for balance, and the test works correctly. He could
    equally have cast the "NIL" to the correct mode and then "snake"
    would have been dereferenced for balance and the test would again
    have worked correctly. /Or/ the simpler solution is to declare a
    "nilsnake" to be a "NIL" of the correct mode and then test
    "snake ISNT nilsnake" [look ma, no casts!], and the balancing is
    automatic. It's all very easy and obvious if you understand A68
    modes, and very difficult and obscure if you don't. Janis is
    experienced enough to be in the former category, but we can all
    slip up from time to time, and it's like typos in general -- once
    you've perpetrated the slip, you just read over it and it's very
    hard to spot [I didn't, at first].
    --
    Andy Walker, Nottingham.
    Andy's music pages: www.cuboid.me.uk/andy/Music
    Composer of the day: www.cuboid.me.uk/andy/Music/Composers/Goodban
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andy Walker@anw@cuboid.co.uk to comp.lang.misc on Sat Sep 27 23:49:04 2025
    From Newsgroup: comp.lang.misc

    On 27/09/2025 21:38, Janis Papanagnou wrote:
    Changing the assert to ASSERT (REF SEGMENT (head OF snake) ISNT NIL); triggers an error though, so this is the essential hint! - Thanks.

    Yes, but "ASSERT (head OF snake ISNT REF SEGMENT (NIL))" would
    have had the same effect; and then you find yourself repeating
    "REF SEGMENT (NIL))" all over the place, and it becomes obvious that
    declaring "REF SEGMENT nilsnake = NIL;" allows you to save typing and
    make the code clearer.

    [...]
    Or you may have been careful about the mode of "snake"!
    Don't know what you mean here.
    The usual case would be that "snake" is a "REF REF SEGMENT",
    declared and initialised by "REF SEGMENT snake := nilsnake" [or, if
    you prefer, "... := NIL;"], but there are contexts, such as procedure parameters, where the mode could be "REF SEGMENT", your test would
    have been correct, and we would have had to look elsewhere for the
    bug. I couldn't tell for sure from the program fragment you gave.
    [Also, for all I knew, "snake" could have been a "REF REF REF SEGMENT",
    as arises naturally in queue processing or in deleting items from the
    middle of lists.] But, of course, common errors are more usual than
    rare ones!
    --
    Andy Walker, Nottingham.
    Andy's music pages: www.cuboid.me.uk/andy/Music
    Composer of the day: www.cuboid.me.uk/andy/Music/Composers/Goodban
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.misc on Sun Sep 28 01:19:36 2025
    From Newsgroup: comp.lang.misc

    On 28.09.2025 00:49, Andy Walker wrote:
    On 27/09/2025 21:38, Janis Papanagnou wrote:
    Changing the assert to ASSERT (REF SEGMENT (head OF snake) ISNT NIL);
    triggers an error though, so this is the essential hint! - Thanks.

    Yes, but "ASSERT (head OF snake ISNT REF SEGMENT (NIL))" would
    have had the same effect; and then you find yourself repeating
    "REF SEGMENT (NIL))" all over the place, and it becomes obvious that declaring "REF SEGMENT nilsnake = NIL;" allows you to save typing and
    make the code clearer.

    I'm aware of the latter. My planned approach was that I reduce that
    plethora of casts to separate superfluous ones from the necessary,
    then homogenize the access methods to something more sensible; the
    introduction of a dedicated nil-constant may happen at that end.

    [...]
    Or you may have been careful about the mode of "snake"!
    Don't know what you mean here.
    The usual case would be that "snake" is a "REF REF SEGMENT",
    declared and initialised by "REF SEGMENT snake := nilsnake" [or, if
    you prefer, "... := NIL;"], but there are contexts, such as procedure parameters, where the mode could be "REF SEGMENT", your test would
    have been correct, and we would have had to look elsewhere for the
    bug. I couldn't tell for sure from the program fragment you gave.
    [Also, for all I knew, "snake" could have been a "REF REF REF SEGMENT",
    as arises naturally in queue processing or in deleting items from the
    middle of lists.] But, of course, common errors are more usual than
    rare ones!

    In decades of programming it was never necessary to use triple-REFs.
    YMMV. (There's discussions about that and IIRC also in some Algol 68
    texts, but yet it had only been an academical theme for me.)

    What I have had and also actually have, are the double-REFs that we
    typically have in procedures when doing (recursive) list processing.
    In my case, for example,
    PROC append_segment = (INT len, REF REF SEGMENT segm) VOID : ...
    where the passed element is either a "native" REF SEGMENT element
    from the actual single-linked-list or the 'head' and 'teil' elements
    in the 'snake' object which also reference SEGMENTs (as seen below).

    The only HEAP allocated items in my case are the SEGMENT elements.
    For 'SNAKE' there's only a flat structure defined
    MODE SEGMENT = STRUCT ( COORD coord, REF SEGMENT next );
    MODE SNAKE = STRUCT ( INT length, ..., REF SEGMENT head, tail );

    The classical algorithmic tasks (with REFs) are not what concerns
    me as "problem". Currently I'm (still!) more concerned with how to
    create and embed yet non-existing low-level functions like 'getkey'
    sensibly into my programs. But that is another topic... :-)

    Janis

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Lawrence =?iso-8859-13?q?D=FFOliveiro?=@ldo@nz.invalid to comp.lang.misc on Sun Sep 28 02:37:45 2025
    From Newsgroup: comp.lang.misc

    On Sat, 27 Sep 2025 23:15:01 +0100, Andy Walker wrote:

    On 27/09/2025 21:47, Lawrence DrCOOliveiro wrote:

    On Sat, 27 Sep 2025 20:50:41 +0100, Andy Walker wrote:

    On 27/09/2025 16:28, Janis Papanagnou wrote:

    ASSERT (snake ISNT NIL);
    ASSERT (head OF snake ISNT NIL);

    "NIL" usually needs a cast in such contexts ...

    Then lack of same would cause a compile-time error, not a run-time
    error.

    No it wouldn't.

    I thought in Algol-68, coercion ambiguities were syntax errors. The mode
    of NIL is unspecified (beyond rCLREF-somethingrCY), so the context needs to completely specify the mode. The rCL:=:rCY and rCL:rea:rCY operators are defined so
    that one operand is a strong syntactic position (is that term?) the other
    one is soft. I guess if one operand is NIL, then that side must always be soft.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andy Walker@anw@cuboid.co.uk to comp.lang.misc on Sun Sep 28 16:04:48 2025
    From Newsgroup: comp.lang.misc

    On 28/09/2025 00:19, Janis Papanagnou wrote:
    [...] My planned approach was that I reduce that
    plethora of casts to separate superfluous ones from the necessary,
    then homogenize the access methods to something more sensible; the introduction of a dedicated nil-constant may happen at that end.

    With respect, I think this is backwards. Your way, it's too
    easy to get the casts wrong [or omit them], giving rise to a plethora
    of places that need to be checked, then once that's sorted out you
    simplify and clarify the code. We saw the result yesterday. If you
    start with the nil-constants, the code is always clear and simple,
    and you scarcely need any casts at all. But it's your code!
    In decades of programming it was never necessary to use triple-REFs.

    I doubt whether it is ever /necessary/. [After all, we had
    decades of programming when the main languages didn't even have
    pointers.] But if you need to delete elements from the middle of
    lists, it's much easier with a triple ref than with alternatives,
    such as two pointers chasing each other down the lists, with all
    manner of special cases.
    --
    Andy Walker, Nottingham.
    Andy's music pages: www.cuboid.me.uk/andy/Music
    Composer of the day: www.cuboid.me.uk/andy/Music/Composers/Herold
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andy Walker@anw@cuboid.co.uk to comp.lang.misc on Sun Sep 28 16:23:10 2025
    From Newsgroup: comp.lang.misc

    On 28/09/2025 03:37, Lawrence DrCOOliveiro wrote:
    I thought in Algol-68, coercion ambiguities were syntax errors.

    Any [non-trivial] ambiguity in the program is an error in the
    Revised Report, rather than the program. [Excepting things that are implementation-defined.] Your program typically has only one possible
    meaning; your task as a programmer is to make the actual meaning match
    your intended meaning.

    The mode
    of NIL is unspecified (beyond rCLREF-somethingrCY), so the context needs to completely specify the mode. The rCL:=:rCY and rCL:rea:rCY operators are defined so
    that one operand is a strong syntactic position (is that term?) the other
    one is soft. I guess if one operand is NIL, then that side must always be soft.

    Just so. But that's basically why unadorned "NIL" is dangerous;
    it's /too/ accommodating, and balances too easily with other operands.
    [As Janis found.]
    --
    Andy Walker, Nottingham.
    Andy's music pages: www.cuboid.me.uk/andy/Music
    Composer of the day: www.cuboid.me.uk/andy/Music/Composers/Herold
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.misc on Sun Sep 28 18:52:18 2025
    From Newsgroup: comp.lang.misc

    On 28.09.2025 17:04, Andy Walker wrote:
    On 28/09/2025 00:19, Janis Papanagnou wrote:
    [...] My planned approach was that I reduce that
    plethora of casts to separate superfluous ones from the necessary,
    then homogenize the access methods to something more sensible; the
    introduction of a dedicated nil-constant may happen at that end.

    With respect, I think this is backwards.

    I basically agree with that. But, that said, I'm obviously not used
    to these castings and the user-defined type-specific NIL definitions.
    My intention here was to get a better feeling for this approach.

    If I inspect my Algol 68 textbook from the 1970's I also cannot find
    a single use of such a code pattern. - Concerning my use of Algol 68
    I'm very biased by its contents, and by the university teaching I
    got. - There was just a single context type for such REF casts, and
    no "own" 'nil' ever required.

    Personally I'm also considering 'NIL' as a universal value. As I've
    also been using it in Pascal, or as 'NULL' (or just 0) in "C" or C++
    (in former times; things have changed over time). - I want to avoid
    multiple "versions" of 'nil'. And my (probably too old?) knowledge
    (including Algol 68, as described above) supported that. And I also
    avoid casting. IMO there's something "wrong" (sort of) if you need
    casting; either in a program's design or in the language definition.
    (But I'm sure that's considered an arguable proposition, especially
    if taken literally in a generally formulated form as I did. :-)

    [...] If you
    start with the nil-constants, the code is always clear and simple,
    and you scarcely need any casts at all. [...]

    As announced, I'm at the point where I introduced an own 'nil_segment' constant. Because I dislike mixes of standard 'NIL' (which I'd prefer)
    and specific 'nil' variants I now omitted/replaced now all 'NIL'. The
    resulting code is less readable, though; they don't stand out any more,
    neither by uppercase-stropping nor by highlighting of my editor!

    The positive consequence is, as you said, that most (in my case: all) REF-related casts vanished by this code pattern, with makes it in that
    respect more readable again! (So it's a code pattern worth following.)

    (Maybe I reduce 'nil_segment' to just 'nil' in cases like the current
    one where there's just a single HEAP REF type used; "nil_segment" is
    just too ugly for my taste.)

    In decades of programming it was never necessary to use triple-REFs.

    I doubt whether it is ever /necessary/. [After all, we had
    decades of programming when the main languages didn't even have
    pointers.] But if you need to delete elements from the middle of
    lists, it's much easier with a triple ref than with alternatives,
    such as two pointers chasing each other down the lists, with all
    manner of special cases.

    Really?

    I've never had any problem with linked-list operations implemented
    with REF REF functions arguments. (Neither in imperative programmed
    form nor in a functional programmed form.) That's actually how I've
    learned it. - I would think that introducing an unnecessary level of
    REF would rather complicate comprehensibility. (Mileages may vary.)

    Janis

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Andy Walker@anw@cuboid.co.uk to comp.lang.misc on Sun Sep 28 23:51:38 2025
    From Newsgroup: comp.lang.misc

    On 28/09/2025 17:52, Janis Papanagnou wrote:
    If I inspect my Algol 68 textbook from the 1970's [...]

    Don't get me started on Algol 68 textbooks! If you compare
    the marketing of A68 with that of Fortran, Pascal and C [to name but
    three] in areas such as the timely availability of compilers, the
    timely availability to students of source for them, and the timely
    availability of /good/ textbooks, it's a miracle that A68 survived
    at all. We're lucky to have A68G.

    I've never had any problem with linked-list operations implemented
    with REF REF functions arguments. (Neither in imperative programmed
    form nor in a functional programmed form.) That's actually how I've
    learned it. - I would think that introducing an unnecessary level of
    REF would rather complicate comprehensibility. (Mileages may vary.)

    In reality the triple-ref simplifies comprehensibility, at
    least for certain classes of problem. The typical deletion problem
    is, say, to remove from the list [eg] all "people aged over 50".
    But by the time you've found such a "person", your pointer is looking
    at the relevant list member and it's too late to divert the upstream
    pointer. The usual solution is to keep a second pointer one element
    further back, so looking at the upstream "person", and to divert that
    around the element to be deleted. That works, but you have to keep
    two pointers in sync, and there is a special case if you need to
    delete the first element, and you need to check carefully that there
    are not further special cases if the list is empty or if the last
    element is to be deleted. Instead the triple-ref solution is to keep
    one pointer to the upstream pointer [initially, the list header], and
    there are no special cases.
    --
    Andy Walker, Nottingham.
    Andy's music pages: www.cuboid.me.uk/andy/Music
    Composer of the day: www.cuboid.me.uk/andy/Music/Composers/Herold
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From richard@richard@cogsci.ed.ac.uk (Richard Tobin) to comp.lang.misc on Mon Sep 29 20:54:24 2025
    From Newsgroup: comp.lang.misc

    In article <10bbp43$2fsef$1@dont-email.me>,
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    I basically agree with that. But, that said, I'm obviously not used
    to these castings and the user-defined type-specific NIL definitions.
    My intention here was to get a better feeling for this approach.

    If I inspect my Algol 68 textbook from the 1970's I also cannot find
    a single use of such a code pattern. - Concerning my use of Algol 68
    I'm very biased by its contents, and by the university teaching I
    got. - There was just a single context type for such REF casts, and
    no "own" 'nil' ever required.

    The ALGOL 68-R Users Guide gives an example of a linked list type:

    MODE LINK = STRUCT(INT item, REF LINK next);

    It recommends declaring a null reference for the end of the list:

    REF LINK empty = NIL;

    The reason why this is preferable is that it enables us to test for the
    end of the chain by means of the clause

    next OF d IS empty

    The mode of 'empty' causes 'next OF d' to be dereferenced to REF LINK

    There's a copy of the guide at

    https://github.com/coolbikerdad/Algol-68-Publications/blob/main/Algol68-R%20Users%20Guide.pdf

    -- Richard
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.misc on Mon Sep 29 23:16:15 2025
    From Newsgroup: comp.lang.misc

    On 29.09.2025 22:54, Richard Tobin wrote:
    In article <10bbp43$2fsef$1@dont-email.me>,
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    I basically agree with that. But, that said, I'm obviously not used
    to these castings and the user-defined type-specific NIL definitions.
    My intention here was to get a better feeling for this approach.

    If I inspect my Algol 68 textbook from the 1970's I also cannot find
    a single use of such a code pattern. - Concerning my use of Algol 68
    I'm very biased by its contents, and by the university teaching I
    got. - There was just a single context type for such REF casts, and
    no "own" 'nil' ever required.

    The ALGOL 68-R Users Guide gives an example of a linked list type:

    MODE LINK = STRUCT(INT item, REF LINK next);

    This is the trivial part. (You find it "everywhere".)


    It recommends declaring a null reference for the end of the list:

    REF LINK empty = NIL;

    This is what Andy also suggested.


    The reason why this is preferable is that it enables us to test for the
    end of the chain by means of the clause

    next OF d IS empty

    This is where the language references or textbooks I used typically
    write code with an explicit coercion like

    REF LINK (next OF d) IS NIL

    (or similar); which is another option to introducing "empty". - The
    advantage of the type-specific "nil" (like your "empty") is that it
    avoids writing these coercions throughout the program.


    The mode of 'empty' causes 'next OF d' to be dereferenced to REF LINK

    There's a copy of the guide at

    https://github.com/coolbikerdad/Algol-68-Publications/blob/main/Algol68-R%20Users%20Guide.pdf

    Thanks. - I think this issue is understood. Andy also elaborated on
    that already. :-)

    Janis

    --- Synchronet 3.21a-Linux NewsLink 1.2