• About the "nameref" feature in bash...

    From Kenny McCormack@21:1/5 to All on Sun Dec 8 12:51:05 2024
    Bash has a "nameref" attribute on variables, that basically makes them like "pointers" in languages like C. That is, the nameref variable has a value, which is the name of another variable, and any/all references to the
    nameref are, in fact, references to the other variable (with 2 exceptions
    as discussed below). So, it works like this:

    # Create a nameref variable and give it the value "foo"
    declare -n MyNameRef=foo
    foo=bar
    echo $MyNameRef
    (prints bar)
    MyNameRef="Not bar"
    echo $foo
    (prints Not bar)

    Now, the docs present this feature as being primarily useful with
    functions. That is, something like:

    foo() {
    local -n MyNameRef=$1
    # Function manipulates MyNameRef, but is, in fact, manipulating
    # the variable whose name was passed as an arg to the function.
    }

    So, if we call foo as: foo bar
    then references to MyNameRef inside foo() are, in fact, references to the global variable "bar".

    This is all well and good, but it leaves open the question of "How do I
    assign a value to the nameref itself, given that any reference to the
    nameref gets converted to a reference to whatever the nameref points to?"

    The answer, as far as I can tell, is that there are exactly 2 exceptions to
    the "always dereference" rule (for setting the value):
    1) Use "declare" (or one of its synonyms, e.g., "local") to do the
    assignment. This works, but is somewhat unappealing, since you may
    end up declaring a variable more than once (which seems intuitively
    wrong).
    2) Use a "for" loop, like this:

    for MyNameRef in one two three; do echo $MyNameRef; done

    This magically assigns MyNameRef the values one, two, and three and
    displays the values of those variables. Note that is different in
    effect from the seemingly equivalent:

    MyNameRef=one; echo $MyNameRef
    MyNameRef=two; echo $MyNameRef
    MyNameRef=three; echo $MyNameRef

    Note: There is a syntax for reading the value of the nameref, but this
    cannot be used to set the value. The syntax is: echo ${!MyNameRef}

    In conclusion, my "reason for posting" is to confirm that I've got it right that there are only 2 ways to set the value. Am I missing anything?

    --
    "We are in the beginning of a mass extinction, and all you can talk
    about is money and fairy tales of eternal economic growth."

    - Greta Thunberg -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Kenny McCormack on Sun Dec 8 14:57:25 2024
    On 08.12.2024 13:51, Kenny McCormack wrote:
    Bash has a "nameref" attribute on variables,

    Is that a newer feature of bash? (My version doesn't support -n with
    'local' or with 'declare'.) My response is based on the ksh feature.
    The underlying ideas of the feature might be reflected in both shells
    in similar ways.

    that basically makes them like
    "pointers" in languages like C. That is, the nameref variable has a value, which is the name of another variable, and any/all references to the
    nameref are, in fact, references to the other variable (with 2 exceptions
    as discussed below). So, it works like this:

    # Create a nameref variable and give it the value "foo"
    declare -n MyNameRef=foo
    foo=bar
    echo $MyNameRef
    (prints bar)
    MyNameRef="Not bar"
    echo $foo
    (prints Not bar)

    Yes.


    Now, the docs present this feature as being primarily useful with
    functions. That is, something like:

    foo() {
    local -n MyNameRef=$1
    # Function manipulates MyNameRef, but is, in fact, manipulating
    # the variable whose name was passed as an arg to the function.
    }

    Yes.


    So, if we call foo as: foo bar
    then references to MyNameRef inside foo() are, in fact, references to the global variable "bar".

    Yes.


    This is all well and good, but it leaves open the question of "How do I assign a value to the nameref itself, given that any reference to the
    nameref gets converted to a reference to whatever the nameref points to?"

    If used in functions - where the actual function parameter from the
    call cannot be changed from within the function ex post - it makes
    sense to not "overwrite" the calling parameter.

    I consider it as a reference (or name?) parameter, so it makes (as I
    perceive it) no sense to redeclare/re-use it as a local variable, or
    reassign a new name to it. - To emphasize my point; it's more like
    the '&' in C++'s function parameter declaration. - But, that said,
    it's possible [in ksh] to reassign it by another parameter(-name),
    like

    function foo {
    typeset -n nr=$1
    typeset -n nr=$2
    nr=42
    }

    (where 'typeset -n' is the ksh equivalent of bash's form). That code
    might make sense if there's some conditional between the two typeset.

    A loop like

    one=1 two=2 three=3
    typeset -n nr
    for nr in one two three
    do (( nr = --count ))
    done

    would affect the variables one, two, and three, respectively. (This is documented for ksh namerefs.)

    After the loop 'nr' still points to variable 'three' and an assignment
    would affect that variable. Re-assigning 'nr' to a new variable name
    requires [in ksh] to explicitly re-declare it, e.g.

    typeset -n nr=zero

    (now 'nr' being quasi an alias-name to the variable 'zero').

    Maybe some ideas here may be conveyed to the bash's implementation and
    its behavior.

    Janis


    The answer, as far as I can tell, is that there are exactly 2 exceptions to the "always dereference" rule (for setting the value):
    1) Use "declare" (or one of its synonyms, e.g., "local") to do the
    assignment. This works, but is somewhat unappealing, since you may
    end up declaring a variable more than once (which seems intuitively
    wrong).
    2) Use a "for" loop, like this:

    for MyNameRef in one two three; do echo $MyNameRef; done

    This magically assigns MyNameRef the values one, two, and three and
    displays the values of those variables. Note that is different in
    effect from the seemingly equivalent:

    MyNameRef=one; echo $MyNameRef
    MyNameRef=two; echo $MyNameRef
    MyNameRef=three; echo $MyNameRef

    Note: There is a syntax for reading the value of the nameref, but this
    cannot be used to set the value. The syntax is: echo ${!MyNameRef}

    In conclusion, my "reason for posting" is to confirm that I've got it right that there are only 2 ways to set the value. Am I missing anything?


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kenny McCormack@21:1/5 to janis_papanagnou+ng@hotmail.com on Sun Dec 8 14:41:31 2024
    In article <vj48k5$3r1bq$1@dont-email.me>,
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    On 08.12.2024 13:51, Kenny McCormack wrote:
    Bash has a "nameref" attribute on variables,

    Is that a newer feature of bash? (My version doesn't support -n with
    'local' or with 'declare'.) My response is based on the ksh feature.
    The underlying ideas of the feature might be reflected in both shells
    in similar ways.

    I think I read somewhere that it came in at bash 4.3 (c. 2014/2015) - which
    is rather old now. So, I wouldn't call it "new".

    --
    Reading any post by Fred Hodgin, you're always faced with the choice of:
    lunatic, moron, or troll.

    I always try to be generous and give benefit of the doubt, by assuming troll.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Kenny McCormack on Sun Dec 8 15:54:57 2024
    On 08.12.2024 15:41, Kenny McCormack wrote:
    In article <vj48k5$3r1bq$1@dont-email.me>,
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    On 08.12.2024 13:51, Kenny McCormack wrote:
    Bash has a "nameref" attribute on variables,

    Is that a newer feature of bash? (My version doesn't support -n with
    'local' or with 'declare'.) My response is based on the ksh feature.
    The underlying ideas of the feature might be reflected in both shells
    in similar ways.

    I think I read somewhere that it came in at bash 4.3 (c. 2014/2015) - which is rather old now. So, I wouldn't call it "new".

    Yeah - "newer" is a very subjective and context specific term.

    It's my [deliberately frozen] standard box I use regularly that
    is still running bash 2.4; so some, erm.., "newer" features of
    bash I cannot test [on that system] (without manual changes).
    I see a downloaded "bash 5.0" package lying around on the file
    system (not installed), but that's it. :-)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kenny McCormack@21:1/5 to janis_papanagnou+ng@hotmail.com on Mon Dec 9 12:38:39 2024
    In article <vj4c02$3rrc3$1@dont-email.me>,
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    On 08.12.2024 15:41, Kenny McCormack wrote:
    In article <vj48k5$3r1bq$1@dont-email.me>,
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    On 08.12.2024 13:51, Kenny McCormack wrote:
    Bash has a "nameref" attribute on variables,

    Is that a newer feature of bash? (My version doesn't support -n with
    'local' or with 'declare'.) My response is based on the ksh feature.
    The underlying ideas of the feature might be reflected in both shells
    in similar ways.

    I think I read somewhere that it came in at bash 4.3 (c. 2014/2015) - which >> is rather old now. So, I wouldn't call it "new".

    Yeah - "newer" is a very subjective and context specific term.

    Yup.

    It's my [deliberately frozen] standard box I use regularly that
    is still running bash 2.4; so some, erm.., "newer" features of
    bash I cannot test [on that system] (without manual changes).
    I see a downloaded "bash 5.0" package lying around on the file
    system (not installed), but that's it. :-)

    I'm a fan of "retro" software, too, and I'm skeptical of the sort of people
    you often see who act as if if you aren't running the absolute latest and greatest, then your input is useless.

    Most of my systems are running a pretty old spin of Debian and the bash
    on these systems is of the 4.3 vintage.

    OTOH, I am kind of a fanboy of bash and I do follow the developments there.
    I usually self-compile the latest version for some subset of my systems. I just d/l'd the 5.3.alpha tarball (which is from April 2024). Haven't
    gotten around to compiling it yet. I'm wondering "how alpha is alpha?"

    --
    "Remember when teachers, public employees, Planned Parenthood, NPR and PBS crashed the stock market, wiped out half of our 401Ks, took trillions in
    TARP money, spilled oil in the Gulf of Mexico, gave themselves billions in bonuses, and paid no taxes? Yeah, me neither."

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kenny McCormack@21:1/5 to janis_papanagnou+ng@hotmail.com on Mon Dec 9 13:57:55 2024
    In article <vj48k5$3r1bq$1@dont-email.me>,
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    ...
    This is all well and good, but it leaves open the question of "How do I
    assign a value to the nameref itself, given that any reference to the
    nameref gets converted to a reference to whatever the nameref points to?"

    If used in functions - where the actual function parameter from the
    call cannot be changed from within the function ex post - it makes
    sense to not "overwrite" the calling parameter.

    To clarify, my actual use case does not involve functions at all. That's
    why, in my OP, I made it clear that "the docs" talk mostly in terms of
    using it with functions - implying that that was not my use case.

    My use case is in mainline code, where I need to load up a bunch of
    shell variables from a database. Like this:

    mapfile -t < <(sqlite3 ...)
    idx=0
    for MyNameRef in var1 var2 var3 ...
    do MyNameRef="${MAPFILE[idx++]}"
    done

    It all works fine; it all works just like the docs say it would.

    I just find it a little strange; that's all. There is another (non-Unix) scripting language with which I am familiar, where they implemented
    "pointers" late-in-development; they followed the C idiom more closely,
    where an unadorned instance of the pointer variable refers to the pointer itself and to dereference it, you stick a * in front. This may be a little more verbose, but it makes more sense to me.

    Anyway, it seems clear at this point that the only 2 ways to assign to the pointer itself (in "mainline code") are as described in the OP. I'm OK
    with that.

    --
    1/20/17: A great day for all those people who are sick of being told
    they don't know how to spell "you're" (or "there").

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Kenny McCormack on Mon Dec 9 16:00:24 2024
    On 09.12.2024 13:38, Kenny McCormack wrote:
    [...]

    I'm a fan of "retro" software, too, and I'm skeptical of the sort of people you often see who act as if if you aren't running the absolute latest and greatest, then your input is useless.

    There's often some simplicity and good usability/ergonomy in older
    [legacy] software that (strangely) a lot newer software, especially
    GUI-based, is lacking.

    I'm regularly verbally "attacked" by me not updating (for "security
    reasons") all my systems to the newest version. (Thereby completely disregarding all the problems [including security] you buy with new
    versions.) But meanwhile they accepted my unconventional habits here.
    Sadly, a lot of things just don't work with systems older than a few
    years, especially Web/HTML based serviced.

    [...] I'm wondering "how alpha is alpha?"

    Concerning Bash questions I can just contribute what I heard by the
    way, or by inference from Kornshell (which is in many features a
    paragon for Bash features). Sorry.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)