Can MAKE FILE! Dialect Solve the Madness

With Generic Tuple, the dawn of NewPath is upon us.

>> filelike-path: 'base/{sub dir}/name.ext
== base/{sub dir}/name.ext   ; path!

>> first filelike-path
== base  ; word!

>> second filelike-path
== "sub dir"  ; text!

>> third filelike-path
== name.ext  ; tuple!

>> last third filelike-path
== ext  ; word!

At some point you'll need transformations that get you actual FILE! strings out of PATH!s you were using as a convenient structural substitute. I'm trying to think about good sanity-checking features that will pay dividends, like this one:

>> extension: "txt"

>> file: make file! 'base/{sub dir}/name.(extension)
== %"base/sub dir/name.txt"

>> extension: "not/legal"

>> file: make file! 'base/{sub dir}/name.(extension)
 ** Error: Can't use slash in filename sub-component "not/legal"

With this new direction, I want to kill off the old behavior of FILE!s that get path-picked IMPLICITLY doing appending of path segments to file names. That means no more of this:

>> src-dir: %foo/bar

>> src-dir/main
== %foo/bar/main

A Compelling Example Of Why Implicit FILE! Pathing Must Die

Here is a bit of code I'd like you to look at, from rebmake.r:

depends: reduce [
    either user-config/main
    [gen-obj/main user-config/main]
    [gen-obj/dir file-base/main src-dir/main]
]

I thought this was attempting to generate a BLOCK! of FILE!s. My attention was drawn to src-dir/main, which I figured was using the "evil" implicit pathing feature.

This made me imagine the others were doing that too. So the first case would make a block of two files, and the second a block of three.

Looking closer, nope. GEN-OBJ is a function which takes a varying number of directories as arguments, depending on whether it has refinements. So these are two potential calls to that function which generate only one result. user-config and file-base are OBJECT!s from which an element is being picked, while only src-dir is a FILE!. /DIR and /MAIN are refinements to GEN-OBJ, where /DIR takes a FILE! argument.

How can anybody expect to be able to read this?

Let's Try And Make Sense of It

First, let's kill off the implicit pathing, and use MAKE FILE!

depends: reduce [
    either user-config/main
        [gen-obj/main user-config/main]
        [gen-obj/dir file-base/main make file! '(src-dir)/main/]
]

It's...slightly better. Now let's go with the idea of inert-based picking of members with dots, to make it more obvious where the function calls are:

depends: reduce [
    either user-config.main
        [gen-obj/main user-config.main]
        [gen-obj/dir file-base.main make file! '(src-dir)/main/]
]

Now we can discern that /MAIN is (probably) a refinement to GEN-OBJ, while MAIN is a field in both user-config and file-base.

Breaking this apart and adding some comments might help (despite the fact some people seem allergic to writing comments). :-/

 main-obj-spec: either user-config.main [
     ;
     ; Config specified a main .c filename, tell GEN-OBJ via /MAIN
     ; to put it in a derived location relative to that filename's path.
     ;
     gen-obj/main user-config.main
 ][
     ; If there's no explicit config main override, then use the main file
     ; from %file-base.r.  Assume its /DIR location is in the %/main/
     ; subdirectory of wherever the rest of the source code is.
     ;
     main-c-file-dir: make file! '(src-dir)/main/
     gen-obj/dir file-base.main main-c-file-dir
 ]

 depends: reduce [ensure object! main-obj-spec]

It actually turns out that it's not returning an obj FILE!, but a Rebmake OBJ file descriptor object. I really think ENSURE helps in cases like this.

Really This Was About MAKE FILE!...

@giuliolunati will back me up when I say Rebmake is a beast. But makefile systems always are. The good news is that since it's written in Ren-C, there's weapons for attacking it... so we can see just how much dialecting can be brought to bear upon it. It needs rethinking from the most basic premises, but that will take time.

In any case, I just wanted to show some arguments for why no one should mourn the loss of implicit pathing for filenames. It's cool to be able to pun on PATH! to make file paths--it's made for that. But when that is tied in implicitly to evaluation we see what kind of a mess it makes.

This also gives a pretty good argument for why the dotted access pattern helps you see what's going on, by knowing they're not refinements.

Please Help with MAKE FILE! (!!!)

Ideas and testing are going to be important. I'll commit the source to the beginnings soon.

2 Likes

Uhm... file-base.main looks like a filename with extension "main" :frowning:

How does it look "more like a file" than "append/only" looks like a directory?

This is the way it is, so the difference is whether something is evaluative or not.

Remember that %file-base.main is available for non-structured files, just as %append/only is available for filenames.

So the trick with using PATH!s or TUPLE!s is when that's what you want in your dialect. This is why I'm pointing out that MAKE FILE! from a PATH! is important...you were able to do this before in your dialects, e.g. see %file-base.r. (I'll point out that notation for file-base of using PATH!s was Carl's invention).

Some people might want to avoid ever using NewPath style MAKE FILE! mechanics. They can always use FILE! and live in the string world. That's fine, though I think they'll be missing out...losing on structure and having their dialects be "messy" by needing % in slots where there's no contention with plain paths. Dialects are supposed to let you be clever, and it seems a waste to not exploit it, but...

Generally speaking, I don't see how file-base.main is any more confusing as a TUPLE! than as a WORD!...and you have actual structural capability with it.

1 Like

Yes, you're right. Better if I thought before I wrote... :-/

1 Like

It's hard to know what to think about a lot of these things.

The first time I saw the PATH!s in %file-base.r I thought "well that seems wrong, there's a datatype for FILE!, these should be FILE!s instead of being confused with PATH!".

When you start trying to separate everything into its "role" then I think that misses the idea. Where the idea is that you have generic parts and you do what you want with them.

The language kind of caters to the data format... not vice-versa. If you look at it as "data first, code second" then you see it differently. What you're hoping to do is spend a little bit of time working up each dialect, and then get to put most of your expression in the dialect...

1 Like