Fish-shell: Script-local variables not correctly substituted when functions are called

Created on 18 Jun 2018  ·  3Comments  ·  Source: fish-shell/fish-shell

I'll preface this right off the bat with "I don't know if this is by design, but I sure am confused."

set -l foo

function print_foo
    echo "Evaluating print_foo"
    echo "inner foo: $foo"
end

set foo "foo"
echo "setting foo to \"$foo\""
print_foo

This prints the following:

setting foo to "foo"
Evaluating print_foo
inner foo: 

As I understand it, the first line of the script defines a variable local to the script named foo. While a function block defines a scope, the declaration of a new scope does not wipe out variables defined in the parent scope.

I can understand if the variable foo is not defined if I were to call print_foo from outside this script (after sourcing it), though I would consider that a bug since a "reference" to that variable still exists and therefore it shouldn't be garbage cleaned. But I don't understand why when print_foo is called from within the same script file that print_foo is defined in, the value is not retained.

Additionally, I am vexed because the behavior below differs:

set -l foo "foo"
for i in ""
    echo "Inner foo: \"$foo\""
end

prints Inner foo: "foo", even though the for block also defines a new scope just like the function block does.

question

All 3 comments

See flag --no-scope-shadowing in man function. This is by design. The fact you defined foo with local rather than global scope means it is equivalent to this:

function bar
    set -l foo baz
    print_foo
end

Whether the design is sensible is a different question :smile:

Yes, this is by design.

@mqudsi: If you want the function to inherit a copy of the variable, use function --inherit-variable or export the variable. If you want it to be able to modify the variable, you should make it global instead.

Awesome, thanks guys.

Was this page helpful?
0 / 5 - 0 ratings