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

Variable passing to ruleset by a mixin contain a loop #2098

Closed
oltodo opened this issue Jul 8, 2014 · 3 comments
Closed

Variable passing to ruleset by a mixin contain a loop #2098

oltodo opened this issue Jul 8, 2014 · 3 comments

Comments

@oltodo
Copy link

oltodo commented Jul 8, 2014

Hi,

This is my parametric mixin contain a loop who set a @width variable and provide to ruleset :

.foo (@ruleset) {
    .loop(1);

    .loop (@index) when (@index < 4) {
        @width: 30px * @index;

        .bar {
            @ruleset();
        }

        .loop(@index + 1);
    }
}

When I call this mixin twice like that :

.foo({
    width: @width;
});
.foo({
    width: @width;
});

I have this output :

.bar {
  width: 30px;
}
.bar {
  width: 60px;
}
.bar {
  width: 90px;
}

.bar {
  width: 30px;
}
.bar {
  width: 30px;
}
.bar {
  width: 30px;
}

The first three are correct but the last three stay on 30px width.

Strangely, the following example has no problem :

.first {
    .foo({
        width: @width;
    });
}

.second {
    .foo({
        width: @width;
    });
}

An idea ?
Thanks.

@seven-phases-max
Copy link
Member

That's because the second call is equal to

@width: 30px;
.foo({width: @width;});

since the first call exposes its top-level @width to the global scope and then this global @width overrides local @widths defined in the second call loops. I.e. the issue can be simplified to:

@width: 50px;
@ruleset: {width: @width};

.bar {
    @width: 30px;
    @ruleset(); // -> 50px
}

And this way it seems to be very close to #1316 (i.e. "global scope" > "caller scope" in certain cases).
Actually I was not sure it's #1316 (because the {width: @width} itself is "defined" at the global scope so I thought it just may pick up global variables before any other) but this:

@width: 50px;
@ruleset: {width: @width};

.-;.-() {
.bar {
    @width: 30px;
    @ruleset(); // -> 30px
}}

makes it less or more evident.


Workarounds for your example:

[1]. Isolating .foo calls from global scope:

& {.foo({width: @width})}
& {.foo({width: @width})}

This is basically the same as your second example and not very useful.

[2]. Same as [1] but hiding the fix inside the mixin:

.foo(@ruleset) {
    & {.loop(1)}
    .loop (@index) when (@index < 4) {
        @width: 30px * @index;
        .bar {@ruleset();}
        .loop(@index + 1);
    }
}

.foo({width: @width});
.foo({width: @width});

... better now, but still if you occasionally have global @width variable it will override everything.

@SomMeri
Copy link
Member

SomMeri commented Oct 2, 2015

I think that this is not really a bug, the scopes here are working as designed. Since variables are returned, first call introduces @width into the global scope. Detached ruleset then uses @width as defined in his own (global) scope.

Maybe we should close this?

@seven-phases-max
Copy link
Member

Closing as expected behaviour.

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

No branches or pull requests

5 participants
@lukeapage @oltodo @SomMeri @seven-phases-max and others