Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Oct 24 09:58

    dockimbel on interp-events

    FIX: compiler crashing in error… (compare)

  • Oct 24 09:50

    dockimbel on interp-events

    FIX: allows paren! series as ar… FIX: improper error reporting o… (compare)

  • Oct 24 08:11

    qtxie on interp-events

    FIX: Win: gets WM_PAINT event i… (compare)

  • Oct 24 06:35

    qtxie on master

    Fix NetBSD compilation and rpath (compare)

  • Oct 24 06:35
    qtxie closed #4987
  • Oct 24 06:32

    qtxie on master

    Fix 'about' word in FreeBSD con… (compare)

  • Oct 24 06:32
    qtxie closed #4986
  • Oct 24 06:02
    vazub edited #4987
  • Oct 24 06:01
    vazub opened #4987
  • Oct 23 18:53
    greggirwin commented #4986
  • Oct 23 18:17
    vazub synchronize #4986
  • Oct 23 18:14
    vazub synchronize #4986
  • Oct 23 18:08
    vazub opened #4986
  • Oct 23 17:43

    dockimbel on interp-events

    FEAT: integrates interpreter ev… (compare)

  • Oct 23 16:57

    dockimbel on interp-events

    FEAT: implements a simple profi… (compare)

  • Oct 23 16:34
    hiiamboris labeled #4985
  • Oct 23 16:33
    hiiamboris opened #4985
  • Oct 23 09:29

    dockimbel on interp-events

    FIX: minor fixes to profiler. (compare)

  • Oct 23 01:48

    qtxie on master

    Fix compilation and run on Free… Merge pull request #4984 from v… (compare)

  • Oct 23 01:48
    qtxie closed #4984
hardkorebob
@hardkorebob
I was about to ask. :)
Gregg Irwin
@greggirwin
Welcome @hardkorebob !
hiiamboris
@hiiamboris

We were discussing string interpolation with Gregg, and would like others input.

Preliminary design was #composite macro and composite function. Both are described here, but TL;DR is #composite turns a string into a rejoin with block and composite does it internally and returns rejoined string:

>> probe expand-directives [#composite {"(player)" "(vfile)" --audio-file "(afile)"}]
[rejoin [{"} (player) {" "} (vfile) {" --audio-file "} (afile) {"}]]

The latter as you can see gets very ugly at times. So first purpose of it is readability. Second purpose is localization (see on the same page).

There are however some issues.

  • #composite is a long thing to type. I found myself writing macro wrappers around it: #print for print #composite, ERROR for do make error! #composite and so on.
  • #composite can't accept strings indirectly (being a macro), e.g. strings conditionally fetched or built at runtime.
  • composite (func) requires runtime binding, and that we provide it every time (see the above page for details). Which is a bag of gotchas for everyone not deeply familiar with Red.
  • What escape syntax should be preferred? Current implementation uses (\ to denote literal (, which is backwards ☻

My stats so far are:

  • ERROR is a very common use case, probably 50-70% of my use of composite.
  • #print is most of the rest.
  • other #composite uses are present (e.g. composing file content) but not very numerous.
  • composite (function) I only used once.

Some recent ideas:

  • Replace #composite "value=(v)" with a shorter macro, e.g. `"value=(v)"` . Backtick does not stick to strings and tags, but stick to files and raw-strings (though it can be fixed). No need for wrappers anymore. Such triple quotes are harder to count visually though.
  • Most languages reserve some quotation format for this (very common) use. We could code backticks directly in the lexer to transform strings like `value=(v)` into rejoin ["value=" (v)] (or just into blocks?) on load. That however harms localization, as we don't get the string form anymore and need some kludges to extract it.
  • We can build and expand macros at runtime as shown above, so there really is no strict need for composite function and we may even abandon it, or make it a wrapper around the macro: build the macro pattern, expand, bind and evaluate.

What do you guys think? Any ideas on how to best support interpolation? Have you used it (or wanted to use) in your code?

gtzip
@gtzip
Value for templating?
I've used rejoin and compose rejoin as a common pattern for some templates.
At first i wished for it, but rejoin with a block is essentially bizzaro string interpolation. The inverse sort of.
Its a must for string heavy languages, but for red?
Gregg Irwin
@greggirwin
Another question is the markers for placeholders. In mine I used :( ... ): (what @hiiamboris refers to as the sad eomji format. :^) @giesse pointed out in another chat the main binding problem, which Boris also covers. Basically, the simple case where you use it in a func, but then it needs a context given because it's not a block to begin with.
Greg T
@gltewalt
log-info compstr "Started worker <%name%> PID: (<%pid%>)"
Is there something against the rebol choice of <%..%> ?
I know that folks are used to parens for compose
Sad emoji isn't bad until you throw in set-words or get words
Greg T
@gltewalt
And forgive me if I've forgotten if backticks make for an illegal word
Those would be fairly clean
I suppose going by the boris breakdown, I'd prefer \var\ ^\text\, then (var) (\text)
Greg T
@gltewalt
And would vote for macro
hiiamboris
@hiiamboris

Is there something against the rebol choice of <%..%> ?

So unreadable IMO as if it was not designed at all ;)

hardkorebob
@hardkorebob
Im not a developer per se. I do work with the command line a lot in Linux and I would consider myself a PowerUser than anything else. Readability is definitely very nice but maybe the whole thing needs to relooked at. I dunno. Just my 2 cents.
I am very new to Red and the whole Rebol/Forth family. But I love to learn and I am willing to share my insights.
Boleslav Březovský
@rebolek
Comon format for the delimiters is also {{ and }} (see Mustache)
And of course I would welcome an option to override default delimiters.
5 replies
Galen Ivanov
@GalenIvanov
While working on the Red functions for Python programmers article, I wrote a simple format function that uses a tiny formatting DSL. I find it slightly related to the composite function and that's why I'm posting it here.
Boleslav Březovský
@rebolek
@GalenIvanov nice!
Galen Ivanov
@GalenIvanov
Thanks!
hiiamboris
@hiiamboris
Comparison of short macro formats as currently possible to lex:
string alt string tag file note
`"value=(v)"` `{value=(v)}` `<value=(v)>` ` %"value=(v)" `
@"value=(v)" @{value=(v)} @<value=(v)> @%"value=(v)" 1
&"value=(v)" &{value=(v)} &<value=(v)> & %"value=(v)" 2
/"value=(v)"/ /{value=(v)}/ / <value=(v)> / /%"value=(v)"/
="value=(v)"= ={value=(v)}= =<value=(v)>= = %"value=(v)" =
^"value=(v)"^ ^{value=(v)}^ ^<value=(v)>^ ^ %"value=(v)" ^
  1. similar to reshape
  2. & can't be an operator then
gltewalt (The other Greg)
@gltewalt:matrix.org
[m]
Well I can say you've done the work and provided examples and justifications, which is normally an Irwin requirement. Aesthetically, parens are not my favorite but I'm sure I would get used to it.
Greg T
@gltewalt
First short macro format would be my pick
Gregg Irwin
@greggirwin
@hiiamboris knows how to sway me. I'm on to him though.
Gregg Irwin
@greggirwin

@gtzip the question of value in Red is a good one. We tend to think in terms of little strings, and bits of code we compose or rejoin. While we don't have measurements, we do have evidence that non-developers understand, and can effectively use, templates (e.g. mail merge). Where blocks of code are normal for us, they are foreign to others, flipping the model on its head. No longer are there placeholders within a string of text, but there are interspersed bits of text and expressions. In my own work, I've used external templates more than internal, not counting rejoin/reform cases where devs are the only consumer.

I also noted to @hiiamboris that a key elements is the WYSIWYG aspect. Rejoin/reform make you look at every text snippet to make sure you have leading trailing spaces right. That's probably one of my most common mistakes in formatting. The other place that's huge is in multiline string formatting. e.g. templated email bodies. Compare this R2 build-markup example

        body {
            The <%PROCESS_NAME%> process sent DISKPART the following commands:

                <%mold MARKUP_1%>

            The DISKPART result was:

                <%mold MARKUP_2%>
        }

with something like

        body [
            "The " <%PROCESS_NAME%> " process sent DISKPART the following commands:^/^/"

            tab   <%mold MARKUP_1%>

            "^/^/The DISKPART result was:^/^/"

            tab    <%mold MARKUP_2%>
        ]

We can put the former in a user's hands, and if errors aren't dangerous, e.g. malformed fields, they can still deal with it. The latter, based on my experience, is not user friendly. It can be especially confusing because the blank lines in the template do not affect the output.

hiiamboris
@hiiamboris
I can add that first time I saw Gregg's #composite my reaction was "why would we ever want that?". But then with every print or rejoin I was using in my code I had this thought "what if..". Then I started using my experimental implementation, and after some time I believe it's a total must have.
zentrog
@zentrog:matrix.org
[m]

I think this Red version is a little closer to the R2 example

        body rejoin [{
            The } PROCESS_NAME { process sent DISKPART the following commands:

                } mold MARKUP_1 {

            The DISKPART result was:

                } mold MARKUP_2 {
        }]

The direction that the 'delimiters' point around the code parts feels a little odd to me, but I don't know if it's good or bad. You do get accurate syntax-highlighting this way, which is nice.

Gregg Irwin
@greggirwin
Indeed. Users won't have syntax highlighting, more than likely, but this is something we should absolutely consider, as we support people writing more tools to help their users.
hiiamboris
@hiiamboris
Why not have it?
Gregg Irwin
@greggirwin
I mean end users, who might be given "merge files". They'll have Notepad.
GiuseppeChillemi
@GiuseppeChillemi
Will there be a way in Red to create a context where some words are refinements? It is needed to replicate the function's context exactly.
Gregg Irwin
@greggirwin
Not likely. Refinements do not support set syntax, like set-words. Accessing them via path syntax would also lead to a double slash syntax, which is problematic. Why not use a separate context within the context for them, which is sort of what Red does internally.
Gregg Irwin
@greggirwin

Composite syntax :point_up:

On the chance that we want to support @"..." syntax for ref! someday, let's not do that.

Double sigils, head+tail are unattractive to me, and those with spaces required are problematic from a general "whitespace separates values" standpoint.

If it's a macro, I don't mind it looking like one, with a leading # sigil. The editorial "change/insert" mark is ^, which is a problem in Red. #^^ seems...icky ~ is close to "transpose", but that meaning isn't a great match for "substitute".

I still like aspects of the backtick, but #` is pretty subtle. #`` less so.

The number of bracketed string types in Red makes the other options quite ugly. As a more traditional macro it could also work for composing blocks at compile time. More thought required.

8 replies
Gregg Irwin
@greggirwin
The worst-looking syntax with leading/trailing backticks is for regular strings, which are likely the most common case.
GiuseppeChillemi
@GiuseppeChillemi

@greggirwin Let's see, I am currently working on Rebol on a way to send remotely the current command and start it there from inside the called function:


get-command-line: func [
    "Returns a block ready to be transmitted that replicates the current function start parameters"
    fname [word!] "The name of the functions"
    args [block!] "The argument words inside a block"
    refinements-block [block!] "The refinement block in the form [/refname [arg1 arg2] /refname [arg3 arg4]]"
    bound-word [word!] "A word of the caller function context"
    /specs
    the-specs
    /local
    out-data
    remote-command
    refs
    argument-refs
    arguments
    argg
    command-line
    in-block;  block with refinements

] [
            args: copy args
            refinements-block: copy refinements-block

            remote-command: to-path fname

            ;--- Here we neutralize functions in words on reduce
            ;
            forall args [
                if word? first args [change args to-get-word pick args 1]
            ]

            ;--- Here we neutralize functions in words on reduce
            ;
            forall refinements-block [
                if block? in-block: first refinements-block [
                    forall in-block [
                        if word? first in-block [change in-block to-get-word pick in-block 1]
                    ]
                ]
            ]

            refs: copy []
            arguments-ref: copy []

            arguments: reduce append copy [] args

            parse refinements-block [
                any [
                    set ref refinement! set argg block!  (
                        if true = first reduce [get in bound? bound-word ref]  [
                            append remote-command to-word ref  
                            append arguments :argg
                        ]
                    ) 
                    |
                    set ref refinement! (
                        if true = first reduce [get in bound? 'server ref] [
                            append remote-command to-word ref]
                    ) 
                    | 
                    skip
                ] 
            ]
    command-line: mold/all reduce compose [remote-command (arguments)]
]



afunction: func [a b /c d e] [
    probe get-command-line 'afunction [a b] [/c [d e]]    'a
]

>> afunction/c 1 2 3 does []
"[afunction/c 1 2 3 #[function! [][]]]"

Many things are still not there in Red to redo this but it is maturing from day to day.

Gregg Irwin
@greggirwin
By far my most common case for filenames is date-naming them, which isn't a good match for composite and handled better by format.
GiuseppeChillemi
@GiuseppeChillemi
Note, in Rebol I could have parsed third bound? 'a to get the needed argument for get-command-line but there is a terrible bug: if you ask the context of a local word of a function, it is returned without the first word of the context.
>> a: func [b c][probe bound? 'b]
>> a 1 2
make object! [
    c: 2
]
GiuseppeChillemi
@GiuseppeChillemi

While in Red:

>> a: func [b c][probe context? 'b]
== func [b c][probe context? 'b]
>> a 1 2
func [b c][probe context? 'b]

I get the whole function definition.

Gregg Irwin
@greggirwin
I'm not clear what you're trying to accomplish @GiuseppeChillemi. e.g. bound? behavior. I've posted my refine experiments in the past, which may be applicable. It looks like you're trying to bind parts of a remote call to different contexts, but I don't know why you'd do that. If you're making remote calls, you shouldn't know anything about the server side.
GiuseppeChillemi
@GiuseppeChillemi
Bound? on Rebol is Buggy, as you can see: :point_up: 27 giugno 2021 00:52
Gregg Irwin
@greggirwin
My instinct says you're making this harder than it needs to be, but I don't know enough about what you're trying to do to know for sure.
GiuseppeChillemi
@GiuseppeChillemi
I want to execute code on the remote side. I am passing commands together with their arguments. They are terminals values, words are used as symbols and no context is sent. I will try later to make remote work contexts for the lines I am passing.
There is a reason I am choosing this way:

I am experimenting into creating commands that can be run either locally or remotely:

A command could be run as

command/ref arg1 arg2 refarg1

but if you write

server: HTTP://192.168.0.22
command/ref/remote arg1 arg2 refarg1 server

Then command creates a block with its name and parameter, and executes it remotely. Then it receives the result from the remote server.

GiuseppeChillemi
@GiuseppeChillemi
(Remotely, the same command exists and it is avaliable inside the execution context)
Gregg Irwin
@greggirwin

Using a refinement to make it remote seems to be the complicating factor. As far as you're concerned, a call is complete (command/ref arg1 arg2 refarg1), correct? So you can store that internally as a block, and make the remote part separate if it's used.

my-call: [command/ref arg1 arg2 refarg1]
do my-call ; local
RPC reduce [my-call 'on server] ; remote, semi-dialected block for fun.

RPC does all the magic and the func is none the wiser.