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

[Bug] Mixin matching fails in &{} blocks #2984

Closed
matthew-dean opened this issue Nov 7, 2016 · 8 comments
Closed

[Bug] Mixin matching fails in &{} blocks #2984

matthew-dean opened this issue Nov 7, 2016 · 8 comments

Comments

@matthew-dean
Copy link
Member

I would have thought this certainly would have been found by someone in the past, but I couldn't find a matching issue.

In short:

.defaults() {
  foo: bar;
}
.test1 {
  .defaults();
}

& {
  .defaults() {
    bar: foo;
  }
  .test2 {
    .defaults();
  }
}

Expected output:

.test1 {
  foo: bar;
}
.test2 {
  foo: bar;
  bar: foo;
}

Actual output:

.test1 {
  foo: bar;
}
.test2 {
  bar: foo;
}

Interestingly, it's not a mixin visibility issue, because this:

.defaults() {
  foo: bar;
}
.test1 {
  .defaults();
}

& {
  .test2 {
    .defaults();
  }
}

...produces this output:

.test1 {
  foo: bar;
}
.test2 {
  foo: bar;
}
@seven-phases-max
Copy link
Member

seven-phases-max commented Nov 8, 2016

I'd rather say it's a dark corner not really a bug. Curiously I saw this before and thought of it as a behaviour I would actually expect. I.e. a mixin call "matches all suitable mixins from the same (closest-upward) scope" and not "matches all suitable mixins from all upward scopes". The former actually makes more sense to me from the "Less have a Scope" point of view.

Or in other words: "Mixins cascade, but only mixins of the same level do this - so that no outer mixin could interfer with a local one(s)".

P.S. And no, it should not depend on if it's & {} or a-normal-selector {} block.

@rjgotten
Copy link
Contributor

rjgotten commented Nov 8, 2016

I've always thought of this as a (sadly not well-documented) feature, rather like @seven-phases-max describes as well.

All the candidate mixins are 'signatures' (in the method overloading sense) of the same 'mixin'. With proper scope overriding, if any one mixin definition is provided at a closer scope then that one definition should be considered an entirely new 'mixin' definition that contains only one 'signature' and should whole-sale replace the mixin definitions that resides in scopes that are further out.

Wouldn't you end up in a world of cross-contaminated hurt if candidate mixin signatures would be accumulated from all the way up to the global scope? You could have some very unintended side-effects that way if you have mixins with overly generic names.

@seven-phases-max
Copy link
Member

seven-phases-max commented Nov 8, 2016

Yep, yet in another words (a minimal making sense example just in case):

.foo {
    .bar();
    .bar() {
        color: red;
    }
}

// in a far far away galaxy:
.bar() {
     color: blue;
}

.foo color is expected to be red not blue.

@matthew-dean
Copy link
Member Author

matthew-dean commented Nov 15, 2016

Hmm. Okay... fair enough if this seems like expected behavior. For me, it adds to the pile of "Less scoping rules and exceptions that make my head hurt". (Although my favorite head-hurting scoping rules is: "mixins return vars unless there's a variable available in the local scope, unless it was defined in a parent scope".)

What I mean is - sure, you can argue this rule on its own and its reasoning. But.... try to figure out the underlying principles of Less scoping and you really won't find any. Each Less node seems to exist in its own scoping universe with its own set of rules. It's frustrating.

@matthew-dean
Copy link
Member Author

matthew-dean commented Nov 15, 2016

I mean, if you boiled down the behavior of mixins here, you basically end up saying: "Mixins overload, except when they don't." You can redefine a mixin, except when you can't. The core concept of mixins is that all selector matches are returned. So you're left with rules like:

  1. Do mixins overload? It depends.
  2. Are variables returned? It depends.
  3. Can you redefine mixins? It depends.
  4. Are mixins like DRs? It depends.

In my mind, Less.js should consist of some very simple rules for objects / syntax. The goal is simplicity over feature complexity. So, I really don't like this long list of one-off exceptions. IMHO mixins are way more complicated behaviourally than they need to be.

@matthew-dean
Copy link
Member Author

If you like, I could close this down in favor of the discussion of mixin scope at: less/less-meta#16

@seven-phases-max
Copy link
Member

seven-phases-max commented Apr 22, 2017

Just to not leave this unanswered to not confuse other readers.

  1. Do mixins overload? It depends.
  2. Are variables returned? It depends.
  3. Can you redefine mixins? It depends.
  4. Are mixins like DRs? It depends.

All these "It depends" translate to "Yes, it depends on Scope". And absolutely the same would apply if you consider any other scoped language. E.g. take JavaScript/C++/etc.:

  • Do variables overwrite? It depends (local vs. outer scope)
  • Do functions shadow? It depends (yet again local vs. outer scope)
  • etc. and so on...

Trolling mode on: hello ;)

@seven-phases-max
Copy link
Member

Closing in favor of less/less-meta#16.

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

3 participants