Port "Schemes" For Finding Module Dependencies

A discussion with @rgchris on the Oldes R3 Issues covers some questions about where to search for module dependencies:

Import doesn't resolve a file `module` argument relative to the modules folder · Issue #130 · Oldes/Rebol3 · GitHub

Quoting some of that here.

Rebol [
    Title: "My Script"
    Needs: [
        r3:xml
        ; works as the word 'xml works currently

        r3:rgchris:deflate
        ; resolves to ~/.rebol/modules/rgchris/deflate.reb

        r3:rgchris:deflate@0.1
        r3:rgchris:deflate@0.1.x
        ; (eventually) ensures a version matching 0.1.x

        r3:rgchris:deflate@1+
        ; (eventually) ensures a version matching 1.0.0 and up

        r3:rgchris:deflate?delay
        ; allows for extensible options (could use web conventions, or not

        r3:rgchris:image.png
        ; allows for alternate filetypes (broken)
    ]
]

Some design choices:

  • Uses : instead of / so as to imply a conceptual entity rather than a literal file path—other implementations of this scheme might use non-filesystem ways of resolving these URLs

  • Version and Options are currently placeholders, this leaves open the option of backwards/forward-compatibility

  • I have some mixed feelings about whether user modules should be ~/.rebol/modules/user/ or ~/.rebol/user/modules/. The latter would allow simple Git cloning of someone's Rebol 3 Scripts repository into the .rebol folder, while the former might mean symlinking a folder into modules. The former doesn't impose any naming schemes on a user's folder though...

I haven't gotten to a good point of understanding about the balance between Needs: and import in the body of the module.

Who needs NEEDS: headers when you have IMPORT?

Putting it in the header where you can't write imperative code is strictly less powerful, but I'm not exactly sure how to gain leverage from that power.

The choice to take : for an interstitial in the CHAIN! datatype means things like r3:rgchris:deflate are CHAIN!.

Because of that, you're more limited in what you could write. Internal @ signs aren't legal (for example). And if you put 0.1 in that will be a DECIMAL!, but 0.1.x will be a TUPLE!. Etc.

But there's structure:

>> chain: first [r3:rgchris:image.png]
== r3:rgchris:image.png

>> type of chain
== \~{chain!}~\  ; antiform (datatype!)

>> length of chain
== 3

>> third chain
== image.png

>> type of third chain
== \~{tuple!}~\  ; antiform (datatype!)

I'm not that concerned about being prescriptive about module names (e.g. saying you can't name a module file something that would be an illegal WORD!).

I have a branch maintaining an implementation of the modules scheme (and the addition of the underscore/NONE! literal :relieved_face:). Hoping that both are adopted :crossed_fingers:

At least for old-school Rebol, I think a URL scheme like this is a much tidier way to refer to modules than the alternatives. This particular scheme doesn't overreach all that much—could be automated or could just mean the user has to tend to their module garden. Either way, it removes the ambiguity of using filenames, or worse, words.

I think _ as the literal form of the space "RUNE!" has turned out to be a strong choice:

Reified Unreassignable Nothingness: SPACE RUNES

The null state being an antiform...and the only falsey state... is strong as well. It can be in many cases reified and de-reified without concern about conflation, as I've shown:

REIFY and DEGRADE: a Narrower LIFT and UNLIFT

"blank" now being an empty splice, has a lifted form as ~()~, which has applications.

I'm interested in seeing compelling usages which don't have solid answers in this model, if you can show them...

I did consider other, more conventional forms. module://xml, module://rgchris/deflate&version=1.x, but that adds certain connotations and expectations that aren't appropriate.

If there's one other advantage to this switch, it's the possibility of transitioning away from words as the pivot point for modules.

I guess it's a matter of style. Like the Type header, you get a top-level view of what the script is about and where it fits. You also get an immediate loud warning if modules are unavailable before a single atom of code has been evaluated. I suppose if you use a URL scheme, you can scan each whole script for those values and provide availability warnings that way.