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

Comments

Projects
None yet
6 participants
@xdudi
Copy link

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Member

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.

@faho faho added the enhancement label Aug 24, 2016

@floam floam modified the milestones: fish-tank, next-major Aug 25, 2016

@ridiculousfish

This comment has been minimized.

Copy link
Member

ridiculousfish commented Aug 28, 2016

Yep, makes sense @faho

@krader1961

This comment has been minimized.

Copy link
Contributor

krader1961 commented Jul 20, 2017

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment