Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local exported (set -lx) variables are not exported to functions #1091

Closed
xdudi opened this issue Nov 3, 2013 · 7 comments
Closed

Local exported (set -lx) variables are not exported to functions #1091

xdudi opened this issue Nov 3, 2013 · 7 comments
Assignees
Milestone

Comments

@xdudi
Copy link

@xdudi xdudi commented Nov 3, 2013

begin set -lx VERBOSE 1; make; end #it works
begin set -lx VERBOSE 1; nice make; end #it works too
but:
function my_nice #made from bash alias
nice -n 20 $argv;
end
begin set -lx VERBOSE 1; my_nice make; end #it doesn't work

@ridiculousfish
Copy link
Member

@ridiculousfish ridiculousfish commented Nov 3, 2013

Alternatively:

begin set -lx MYKEY MYVAL ; env | grep MYKEY ; end
function my_func
   env | grep MYKEY2
end
begin;  set -lx MYKEY2 MYVAL2; my_func; end

This outputs MYKEY=MYVAL but not MYKEY2=MYVAL2

This is by design. The -l flag in set -lx means "local to the current block." When you call a function, local variables are not available to that function, as in C++ or Python. Perhaps surprisingly, this applies to local exported variables: they are un-exported before invoking the function, and re-exported after the function returns.

This is problematic because it breaks encapsulation. If foo is a command, then it sees local exported variables; if foo is a wrapper function around command foo then it does not. I wonder if we should adjust the behavior of local exports in some way. Let's use this issue to track that.

@xdudi thank you for your nice test cases.

@xfix
Copy link
Member

@xfix xfix commented Nov 3, 2013

Perhaps the fix could work like Perl 4 "lexical" variables (Perl 5 variables activated using my are proper lexical variables) that simply disappeared when you left the block. In my opinion Perl 4-like lexicals should use separate flag called --temp (see temp in Perl 6).

sub call_grep {
    system 'env | grep MYKEY';
}
{
    local $ENV{MYKEY1} = 'MYVAL1';
    system 'env | grep MYKEY';
}
{
    local $ENV{MYKEY2} = 'MYVAL2';
    call_grep;
}

This outputs following result, as expected.

MYKEY1=MYVAL1
MYKEY2=MYVAL2
@xdudi
Copy link
Author

@xdudi xdudi commented Nov 3, 2013

In manpage is written: "Non-global variables disappear when the block they belong to ends",
but it works weird for me...

$ begin
    begin
        begin
            set TEST_VAR asd; #is not global
        end;
        echo 1st: $TEST_VAR;
    end;
    echo 2nd: $TEST_VAR;
    if set -q TEST_VAR
        set -e TEST_VAR;
    end
  end
1st: asd
2nd: asd
$ 

I thought that TEST_VAR variable will be visible in inside scopes and will be erased automatically on end of its own scope.

About -l parameter - you have right, like in C local stacked variable is not visible in inside called function.

@ridiculousfish
Copy link
Member

@ridiculousfish ridiculousfish commented Nov 4, 2013

@xdudi you are hitting the difference between local variables and function-scope variables. The documentation says:

If a variable is not explicitly set to be either universal, global or local and has never before been defined, the variable will be local to the currently executing function. Note that this is different from using the -l or –local flag. If one of those flags is used, the variable will be local to the most inner currently executing block, while without these the variable will be local to the function. If no function is executing, the variable will be global.

The intent is to allow code like this to work:

if foo
    set var val1
else
    set var val2
end
# do something with var

If variables were local-scoped by default, var would not be available outside of the block it was defined.

Needless to say, this is very confusing and any improvements you can suggest are welcome.

@faho faho changed the title Wrong work of set -lx during cmake compilation Local exported (set -lx) variables are not exported to functions Aug 24, 2016
@faho
Copy link
Member

@faho faho commented Aug 24, 2016

I wonder if we should adjust the behavior of local exports in some way.

@ridiculousfish: I've had some time to think about this, and I believe the cleanest thing to do would be to make a local copy of -lx variables.

So it would work like this:

  • If a variable is global or universal, all functions have access to it
  • If a variable is not global or universal but exported, called functions get a function-local copy of it defined (as if "-V $variable" had been called)

The latter is basically what happens for external commands - if we export a variable, they get a copy of it. If they modify it, we don't see it.

@floam floam modified the milestones: fish-tank, next-major Aug 25, 2016
@ridiculousfish
Copy link
Member

@ridiculousfish ridiculousfish commented Aug 28, 2016

Yep, makes sense @faho

@krader1961
Copy link
Contributor

@krader1961 krader1961 commented Jul 20, 2017

Merged into the major branch for inclusion in our fish 3.0 release.

@krader1961 krader1961 closed this Jul 20, 2017
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 17, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants