Skip to content

v4.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 12 Sep 19:19

The library reads as methods of its types, and every program that calls it
must change.
Sixteen modules export 203 names where they exported 354; the
151 that went are gone rather than deprecated, because §6.11.2 puts every
imported name in one scope and keeping both spellings would keep the collision
the change exists to remove. There is no migration period. What a caller does:

was is
JsonIntegerOr(JsonMember(p, 'line'), -1) p.Member('line').IntegerOr(-1)
TomlPath(doc, 'server.port') doc.Path('server.port')
ErrorText(e) e.Text
IVecPush(v, 10) / SVecGet(v, 1) v.Push(10) / v.At(1)
NetWriteLine(s, t) / TlsWriteLine(c, t) s.WriteLine(t) / c.WriteLine(t)
StreamReadLine(f, l) / NextEntry(d, n) f.ReadLine(l) / d.NextEntry(n)

A name that is still exported is one with no receiver to select from: a
type, a bound, a constructor (JsonNewObject, TomlNewTable, IVecNew), or
an entry point that answers a value rather than acting on one (JsonParse,
RegexCompile, NetConnect). pascalc --dump-uses and the language server
answer where a method is defined; grep for a bare Put no longer does, which
is the one cost no gate sees.

This is the major number because of that table, not because of the language:
every construct that compiled before this release still compiles, with two
exceptions listed under Removed.

Added

  • A module's implementations reach the components that import it
    (ADR-0411, AP 6.7.10.5). impl Circle; and impl Renders for Circle;
    written in a module-block are selected in every program-component that can
    name Circle — so a library's types carry their own routines, and
    c.Area, Area(c) and a dyn Renders built by the client all reach them.
    Nothing about the spelling changed; what changed is which translations may
    read it.

    Until now this did not work and was not refused: the call compiled and the
    program failed at the assembler or the linker, naming a symbol no source
    spells. AP 6.7.10.1 NOTE 9 had recorded it as not provided (ADR-0341).

    A method's heading is now part of what a component is translated against,
    so changing one without rebuilding the client is refused at the link, the
    way a changed module-heading already was (AP 6.13.2). Changing a method's
    body still costs no relink.

    A method may be external, which had been admitted since methods landed and
    is now pinned by a case; it is the one method shape whose linkage name is
    C's rather than this compiler's.

  • A type may have routines of its own: impl T; and x.M(a) (ADR-0410,
    AP 6.7.10, AP 6.7.10.4). impl Point; declares routines belonging to
    Point, with the receiver written as an ordinary first parameter, and
    p.Shift(1, 1) calls one. It is not a second mechanism: x.M(a) and
    M(x, a) denote the same call, the routine having been selected from its
    first argument's type since traits landed, so a method may be written either
    way and any variable may be the receiver — p.Len, q^.Len, a[1].Len,
    b.inner.Len.

    What it buys is that a method is not an exported name: a module exports
    the type, and its routines travel with it, so two modules may each have a
    Put where §6.11.2 refuses that to two exported names. 139 of this
    library's 486 exported names repeat their own module's noun to work around
    exactly that.

    A type may not have a field and a routine of one name, and is told so where
    the implementation is written. A method called on what a method returned
    needs that second method to take its receiver by value, §6.6.3.3 wanting a
    variable for a var parameter. impl reserves nothing.

    This completes ADR-0315's three increments, all of them now built.

  • A collection may hold values of different types: dyn T, the trait
    object
    (ADR-0408, ADR-0409, AP 6.7.11). type Shape = dyn Renders; denotes
    something that implements Renders, and owned ^Shape owns one; take
    moves a concrete value in and attaches its implementation, and a call
    through the result selects the implementation where the value is used
    rather than where the call is translated. This is what a bound
    (AP 6.7.3.10.5) cannot do — a bound chooses where the type is written, so
    one collection is one type — and it is the first place this compiler emits a
    dispatch table.

    A trait object stands in two positions: the domain of an owned pointer and
    a var or protected var parameter. Everything else is refused with a
    message saying where one can stand, because every other position would hold
    a value whose lifetime nothing states. The implementation travels with the
    value and so does the release, so disposing an owned ^Shape releases
    the concrete value and whatever that owns.

    Not every trait has a trait object: each routine must take its receiver as a
    var or protected var first parameter and name Self nowhere else, and a
    trait that does not is told so where the dyn type is declared, with the
    heading named. dyn reserves nothing — a program may still declare a type,
    a field and a parameter of that name.

    AP 6.7.11 was published one release early, marked [not yet implemented]
    under AP 5.6 — the first and only clause ever to carry that marker — and the
    marker is now gone. Building it corrected two things the clause had said
    (AP Annex E.13, E.14).

Changed

  • PasJson's routines are methods of its types (ADR-0412, AP 6.7.10).
    The module exports 25 names where it exported 50, and a document is read
    by doc.Member('id').IntegerOr(-1) rather than
    JsonIntegerOr(JsonMember(doc, 'id'), -1). JsonKindOf is Kind,
    JsonCharsAddLine is AddText, JsonTextInto is TextInto, and so on
    for 24 routines; what stays exported is what has no receiver to select
    from — the types, the three bounds, the seven JsonNew* constructors and
    JsonParse/JsonParseChars.

    This renames a library's interface and every caller must change. The
    old spellings are gone rather than deprecated: §6.11.2 puts every
    imported name in one scope, and keeping both would keep the collision the
    change exists to remove. JsonChars and JsonPtr now each have a Free,
    a Len and an At, which two exported names could not have been.

  • PasToml's routines are methods of its types too (AP 6.7.10). The same
    change one format over, and the module it was modelled on: 31 names are
    exported where 59 were, and a configuration is read by
    doc.Path('server.port').IntegerOr(80) rather than
    TomlIntegerOr(TomlPath(doc, 'server.port'), 80). TomlKindOf is Kind,
    TomlCharsAddLine is AddText, TomlPositionOf is TomlChars.PositionOf
    -- a buffer asked about itself -- and TomlChars and TomlPtr now each
    have a Free, a Len and an At. TomlParse, TomlParseChars and the
    eight TomlNew* constructors keep their names, a parse answering a document
    rather than being an operation of a buffer. Every caller must change,
    for the reason above; the three TOML cases answer their goldens unchanged,
    which is what says the rewrite moved no behaviour.

  • Eight more library modules read as methods of their types (AP 6.7.10).
    PasVector exports 4 names where it exported 15, PasMap 6 of 16,
    PasStrVec 6 of 19, PasRegex 20 of 31, PasProcess 12 of 22, PasNet 10
    of 14, PasTls 16 of 20 and PasHttp 27 of 38 — with PasJson and
    PasToml, 157 exported names where there were 284. A vector is
    v.Push(x), v.At(i) and v.Len; a socket and a TLS connection both have
    Close, WriteText, WriteLine and ReadLine; a match is
    m.GroupInto(1, s). Every caller must change, and the old spellings are
    gone rather than deprecated, for the reason given above.

    Five spellings could not simply lose a prefix and the compiler said so:
    IVecSet/SVecSet are Put (§6.1.2 reserves set) and BeginRequest/
    BeginResponse are BeginWrite/BeginRead (it reserves begin);
    RegexFaultOf, RegexGroups and RegexSteps are FaultOf, GroupCount
    and StepCount, each beside a field of that spelling; and RegexFaultText
    is RegexFault's own Text, an enumerated type being able to carry an
    implementation. Nine receivers gained protected var: §6.7.3.1's advice is
    deferred for an exported routine and fires on a method.

    PasFile is deliberately unconverted, and so are PasProcess's Run,
    Capture and CaptureLines and PasNet's NetWait: their first parameter
    is a type produced from a schema, or a schema, and neither may carry an
    inherent implementation.

  • PasError and PasLspDiag too, which finishes the conversion at
    sixteen modules and 203 exported names where there were 354. ErrorText(e)
    is e.Text and Failed(e) is e.Failed — an enumerated receiver, so
    errNone.Text works on a constant — and DiagJson(d, line, enc) is
    d.Json(line, enc). 234 call sites across 48 files. What could not convert in
    either module says what a receiver may be: ValueOr takes a type-parameter
    first, and HoldsNul, DiagParse and Utf16Column take string or a
    production of it, which no module owns.

  • Four more library modules read as methods of their types (AP 6.7.10).
    PasList exports 3 names where it exported 13, PasStream 6 of 11, PasLsp
    7 of 10 and PasDir 5 of 7 — with the ten before them, 177 exported names
    where there were 325
    . A list is l.Push(x), l.Len, l.Reverse; a stream
    and a socket and a TLS connection now share WriteText, WriteLine,
    ReadLine and Close. PasList keeps no constructor, a fresh variable of
    an owned ^ being an empty list already. Every caller must change, for
    the reason given above.

  • PasNet.NetService is Socket.Service (AP 6.7.10), the one judgement
    call the previous batch left open. It takes a socket that already exists and
    asks it about itself, which is the receiver test exactly; that its answer is
    about the socket's identity in the system rather than the stream of bytes
    through it is a fact about the answer, not about how the routine is reached.
    PasNet exports 9 names where it exported 14. Its receiver took protected var for the reason the others did.

  • At most one implementation of a type per program (ADR-0413,
    AP 6.7.10). The rule said in a program-component, which every component
    satisfies separately — so the language permitted two modules each giving one
    type routines of its own, and no program that imports both can be given a
    meaning. The library rule that follows: a module must not implement a type it
    does not declare.

    One thing it does change about what the compiler accepts: an
    inherent implementation for a type produced from a schema is now refused,
    a type produced from schema 'string' is the same type wherever it is written, so it cannot carry an implementation of its own. 6.4.7 interns a
    production by its tuple, so routines of its own would be routines of every
    string(255) in the program. The trait form is unaffected — impl Sortable for Name over a string-type of one's own is what that facility is
    for, and three cases in the corpus rely on it.

Removed

  • An inherent implementation for a type produced from a schema is refused
    (ADR-0413, AP 6.7.10). 6.4.7 interns a production by its tuple, so
    string(255) is one type in every module; routines of its own would be
    routines of every string(255) in the program. impl FilePath; compiled
    before this release and does not now. The trait form is unaffected —
    impl Sortable for Name over a string-type of one's own is what that
    facility is for.

  • An inherent implementation for a name that renames another type is
    refused
    (ADR-0414). type Day = integer; impl Day; gave every integer in
    the program that method, held by a name that did not say so. impl integer
    written out stays legal: what is refused is the claim being invisible, and
    the diagnostic names the identifier to write instead.

Fixed

  • A method may name itself through a receiver (ADR-0415, AP 6.7.10.4).
    Inside an implementation, l^.next.Len — a parameterless method-designator
    naming the routine whose declaration contains it — was refused with no
    routine of that name is implemented for it
    , while the same recursion
    written as a statement or as a call with arguments compiled. A routine now
    joins its implementation before its body is checked, so all three spellings
    reach it. Written order still decides: a method declared later is not in
    scope, in any spelling.

  • A method-designator selects from its receiver and not from the scope
    (ADR-0412, AP 6.7.10.2). Inside an implementation that had a routine of
    the name, x.M(a) bound to that routine rather than to x's — so two
    types in one translation could not both have a Free, which is the whole
    of what an implementation is for.

  • A method chain is a procedure-statement. a.M(x).N(y); consumed
    a.M(x) and reported expected 'end' at the end of a compound statement.

  • A parameterless method statement takes any receiver. b.Free was a
    statement and v^.text.Free and arr[1].Free were expected ':=' in an assignment.

  • A designator's type is found in a variant part. A field declared in a
    variant part answered no type when asked quietly, so a method selected on
    one was reported unknown and the owned-vs-owned-pointer hint was not
    given.

  • A var parameter produced from a schema is threatened by being passed
    on
    (§6.9.4 b)). protected var s: string could be handed to another
    routine's var s: string and written through there, with no diagnostic;
    and the advice to add protected was given for parameters that could not
    take the word. One missing call, both faces.

  • A trait may declare a procedure, and calling one now selects an
    implementation.
    AP 6.7.10.2 has named a function-designator or a
    procedure-statement
    since it was written and only the function half was
    built, so Emit(p) over a type implementing the trait reported
    unknown procedure 'emit' while Size(p) beside it resolved (ADR-0407).
    The specification's own NOTE 14 had recorded the gap and thereby
    contradicted the clause above it; it now says what the procedure half
    additionally requires — that the routine selected is a procedure, a trait's
    function used as a statement being refused where any other function is.