less / less.js

Less. The dynamic stylesheet language.
http://lesscss.org
Apache License 2.0
17.02k stars 3.41k forks source link

Public variables on namespaces #1848

Closed Soviut closed 8 years ago

Soviut commented 10 years ago

I realize this isn't a new topic but it I think the time has come to consider implementing public variables on namespaces. Many prominent libraries for LESS (bootstrap, hat, etc.), have emerged, each with dozens of configuration variables which could very well overlap and conflict with each other.

Currently, namespaces support private variables, the only way to get at them is via mixins within the namespace and those mixins can then be used externally; Sort of like a closure:

#ns {
    @size: 10px;
    .box() {
        width: @size;
        height: @size;
    }
}

.icon {
    #ns > .box();
}

Which yields:

.icon {
    width: 10px;
    height: 10px;
}

However, I think it would be very handy to do the following:

#ns {
    @size: 10px;
}

.icon {
    width: #ns > @size;
    height: #ns > @size;
}

As well as update those variables within the namespace:

#ns > @size: 20px;
matthew-dean commented 9 years ago

@calvinjuarez Agreed with pretty much everything you said.

One thing that hasn't entered into this conversation much is that, if you could access properties on rulesets or namespaces, you could effectively namespace variables (i.e. you could use properties as variables), like:

@colors: {
  primary: #FF0000;
};
#columns() {
  width: 20px;
}
.box {
  background: ${@colors primary};
  width: ${#columns width};
}

This would effectively resolve the conflict between @jonschlinkert's proposal for namespacing vars and the ruleset syntax.

That is: if for any reason variable namespace scoping and importing was more problematic than property namespace scoping, the latter could be done before or in place of the other.

matthew-dean commented 9 years ago

@calvinjuarez And yes, I think #columns$width would be a reasonable--and in some cases, desirable--variation for those who prefer not to use braces when they're not necessary. But you'd want to keep braces for:

.box {
   background: url("/directory/${#ns subfolder}/asset.png");
}
calvinjuarez commented 9 years ago

So, I've put up a gist summarizing ${} at https://gist.github.com/calvinjuarez/5900c072b19e45677e98.

That is: if for any reason variable namespace scoping and importing was more problematic than property namespace scoping, the latter could be done before or in place of the other.

Good point. I'll put a note about that in the gist.

Another thing I think we ought to address is namespaced variable/property setting. The questions are essentially:

For that first question, I'd say variables: yes, properties: no. I don't think setting a property after the fact makes much sense. Properties aren't overridable anywhere in Less at the moment, so there's no reason to make them overridable here. Variables, on the other hand, really ought to be overridable. It would make for really organized customizability/theming for libraries & frameworks. But maybe others feel differently?

As for the second question, I'm not sure. Given the test setup below, what's the best way to override just two of the variables in each context (namespace & detached ruleset)?

#ns {
  @foo: foo;
  @bar: bar;
  @baz: baz;
}
@rule: {
  @foo: foo;
  @bar: bar;
  @baz: baz;
};
calvinjuarez commented 9 years ago

Also, as noted by @seven-phases-max in this comment:

#abc@var is already valid statement and evaluated as #aabbcc @var.

So we'll still need to overcome that, or this is a breaking change. Although, I guess you could require the ${} until the next full version update. Then it wouldn't be a big deal; Just introduce some of the syntax sugar later on down the line.

matthew-dean commented 9 years ago

Thanks for the gist! Maybe you can include the string interpolation example as well? As far as "overriding", it's really only possible with the first part, because of how variable redefining would work. That is, consider this:

#ns {
  @foo: foo;
  @bar: bar;
  @baz: baz;
}
@rule: {
  @foo: foo;
  @bar: bar;
  @baz: baz;
};

#ns {
  @bar: grill;
}
@rule: {
  @bar: grill;
}
.example {
  p1: #ns@bar;
  p2: #ns@foo;
  p3: @rule@bar;
  p4: @rule@foo;
}

The second part could be thought of as:

.example {
    & {
        #ns();
        p1: @bar;
        p2: @foo;
    }
    & {
        @rule();
        p3: @bar;
        p4: @foo;
    }
}

However, there's immediately two problems with rulesets, and after writing this example, I think rulesets are a no-go. First: ruleset variables are clearly defined as private variables (which I didn't realize until reading ruleset documentation). So it's not supposed to be possible to access them outside of the rules, by design. (The above example will throw an error for the ruleset block.) Secondly, defining a second ruleset like that would overwrite the ruleset in its entirety. Even if you could unlock a var from the ruleset (which may be possible, not sure), it wouldn't matter, because @foo would no longer exist. @rule would have been replaced completely in the second declaration. The #ns piece works differently, since Less returns all matches.

I had a sneaking suspicion that rulesets would be a problem, and now I see that they really don't fit this model.

In contrast, namespaced vars are easy to model. #ns@var is really sugar (sort of) to say "import this mixin into an anonymous scope, and then assign the property to this variable from within that scope". There are no logical issues. And you don't really "override" so much as declare twice, and both matching mixins would be evaluated, which would import their vars, which would then override, etc.

Note that this works as of today:

#ns1 {
  @foo: one;
}
#ns2 {
  @foo: two;
}
#ns1 {
  @foo: three;
}
.example {
  & {
    #ns1();
    value: @foo;
  }
  & {
    #ns2();
    value: @foo;
  }
}

// output
.example {
  value: three;
  value: two;
}

The new syntax would really just condense the above into:

.example {
  value: ${ #ns1@foo };
  value: ${ #ns2@foo };
}

... Which is great because input (Less) more closely models output (CSS).

So, thinking a bit deeper, I think we should take rulesets off the table for this feature since they're not simply sugar (sort of) for an existing code path.

matthew-dean commented 9 years ago

Oh and about this:

Also, as noted by @seven-phases-max in this comment:

abc@var is already valid statement and evaluated as #aabbcc @var.

I think it's an excellent point. Syntactically, there has to be a way to join a namespace to a property / var. So it may be less problematic to do this:

#abc@var  // legal? or still a problem?
#abc @var // illegal
#abc > @var // legal
${ #abc @var } // all variations legal within ${}, because of non-ambiguity
matthew-dean commented 9 years ago

One more thought: because of the complexity of Less scoping, I don't think we need to reinvent the wheel and bend over backwards as far as namespaced variables. That is: it should be whatever variable is visible to the mixin scope, or visible to the mixin call. In other words, I don't think either of these references should throw an error.

@global: value;
#ns {
}
.example1 {
  prop: ${ #ns @global };
}
.example2 {
  @local: value;
  prop: ${ #ns @local };
}

@global is visible to #ns as is @local within that scope, per usual scoping rules.

seven-phases-max commented 9 years ago

For the last example, hmm, no, I don't think #ns > @local should mean "any @local visible in #ns or whatever @local visible as if we would expand #ns here". This will conflict with namespaced mixins visibility (where @ns.mixin strictly points only to a mixin(s) defined inside #ns).

In other words, yes, for now we use things like & {#ns2();value: @foo;} to emulate this feature but I don't think we should model after emulation. Namespaced variables should behave exactly like namespaced mixins do (i.e. ideally, variables/mixins visibility should match whereever possible (we don't want to explain/document/debug different "scoping rules"), and only (historical) difference in varaibles-override/mixins-stack remains).

calvinjuarez commented 9 years ago

:ballot_box_with_check: Interpolation added to the gist.

About Overriding

Yeah, in looking for overriding options, I came to essentially the same conclusion. There are a lot of things we could try (e.g. the original suggestion of @rule@foo: qux;, or ${@rule@foo}: qux;) but none of them is as clean, clear or intuitive as the direct override (i.e. #ns { @foo: qux; }).

So, yeah, I think I agree. Letting rulesets have totally private variables may be a feature that should be preserved. Although, should we really scrap access to DRs' properties?

Edit: I think this should work, even if we scrap all direct DR access:

@dr: {
  foo: bar;
};

.rule {
  .dr-properties() {
    @dr();
  }
  baz: .dr-properties$foo; // → bar
}

About #abc@var

@var: 'var';
.call {
  property: #abc@var;
}

currently compiles to

.call {
  property: #aabbcc 'var';
}

So allowing .class { property: #ns@var; } would be a breaking change, technically speaking.

About Scope

I'm torn on this one, but I think I agree with @seven-phases-max's thought that variable accessing should parallel the #ns.mixin() behavior. Especially since, in @matthew-dean's example, .example1 has direct access to @global already. Also because, if #ns also had a @local, it would be confusing which @local would be used at .example2's prop. In other words, if I'm trying to use a variable that doesn't exist where I specified, I should get an error.

@global: value;
#ns {
  @local: foo;
}
.example1 {
  prop: @global; // no need for `${}`; if I did specify `${ #ns @global }`, I'd expect an error
}
.example2 {
  @local: bar;
  prop: ${ #ns @local }; // → foo; 'cause I explicitly specified `#ns`
}
matthew-dean commented 9 years ago

In other words, yes, for now we use things like & {#ns2();value: @foo;} to emulate this feature but I don't think we should model after emulation. Namespaced variables should behave exactly like namespaced mixins do

I had, at first, written "I don't think these have to throw an error", which is more what I meant to say. i.e. whatever "fits" into the current model best. So I was speaking more pragmatically as far as feature completion instead of ideal design, so yes, I think behavior like namespaced mixins is probably ideal. You'll get no argument from me. I just wasn't sure which way increases code complexity more. Ideally, the variable would be truly namespaced and lead to less ambiguous referencing. So, sorry to make that more confusing.

@calvinjuarez

So allowing .class { property: #ns@var; } would be a breaking change, technically speaking.

Let's ditch it then. Enforcing > or ${} as a requirement for that type of reference is not a terrible burden on the developer.

should we really scrap access to DRs' properties?

Not necessarily, but it doesn't lend itself to overriding, so I wonder about its value. Unless that was the point, to have a read-only set. Let me rephrase: if it slows implementation, I don't see that much added value over accessing properties/vars in a namespace. Do you have a case where DR property access is more appropriate? DR prop access would be a good one for @seven-phases-max to weigh in on as far as complexity.

We could always do something like anonymous selectors for anonymous namespaces, similar to how Sass does placeholders.

%theme {
  primary: red;
  secondary: blue;
}
// override
%theme { primary: green; }

.block {
  color: ${ %theme primary };
}

But I digress.

calvinjuarez commented 9 years ago

if it slows implementation

I like your thinking. I think simplifying this is a good call. I don't have a specific use case, except for read-only variables. It'd be nice to have something like that that could act as a "constant" type deal, but it's not super important. Honestly, though, I think properties should be read-only, which would fill that use case (that is, ${#ns prop} would get the first instance of prop in #ns, whereas ${#ns @var} would get the latest instance of @var in #ns). Or, of course, allowing accessor's into DRs and not having a specific override syntax may be a better answer. Edit: Thinking about this, I actually think allowing #ns override & not allowing @dr override would be better, since it's pretty much built into the language. (end edit) I'll be interested to hear @seven-phases-max's input on the code complexity.

Likewise, I think ditching #ns@var is probably the right move for initial implementation, but I would like to see it in the next major version. I don't know how many people currently have #[hex]@var (w/ no space) & are depending on it's current output as #[hheexx] [@varValue] (w/ the space), but it can't be many. Even if it's super common, it doesn't seem like a huge fix to just put a space between #[hex] & @var in your Less. So I'd rather the sugar be postponed than forgotten.

As for %theme, I'm definitely in favor of invisible selectors, though I also think #theme() will probably answer most all use cases (if we ever get :extend(.mixin()) off the ground, that is :P).

matthew-dean commented 9 years ago

So I'd rather the sugar be postponed than forgotten.

I think that's reasonable. And yes, since it would be technically a breaking change, we'd need to think about a major version increment.

As for %theme, I'm definitely in favor of invisible selectors, though I also think #theme() will probably answer most all use cases (if we ever get :extend(.mixin()) off the ground, that is :P).

Yes to all of that. Consideration of invisible selectors should not be a priority until some more pieces of :extend are in place. I only brought it up to say that I think we could address some of the other edge use cases of namespaced variables in different ways, so it doesn't have to slow us down. Let's trim this issue and the action plan to what's essential to get a feature that meets 90% of use cases.

As far as properties, I know you struck it out, but you're right that referencing is not as obvious as variables. I'm inclined to treat them like variables, in that the "last value wins", because that seems the most straightforward, and, well, that's clearly how they work in CSS (except, as @seven-phases-max pointed out, when the last value is considered invalid by the browser). But... I wonder if we shouldn't trim this even more to JUST address namespaced variables. We still have a solid syntax for including properties in the future, but maybe what the prop value would be needs further discussion? Other thoughts?

calvinjuarez commented 9 years ago

that's clearly how they work in CSS

That's a really good point; It does make more sense to keep things consistent with CSS.

I also agree that, since namespaced/accessed variables have few if any questions about them, getting them up & running ASAP should be top priority. We shouldn't have to wait on a solid feature just because a sibling feature is still foggy. Plus, once we have a start & people are using ${}, we may be able to get more input on how things ought to work with properties & even DRs.

So here's a summary of the priorities. Do these look alright to you?

As soon as possible:

  1. Accessing namespaced variables with ${} (overriding should work out of the box).
  2. Accessing properties (local & namespaced) with ${} (overriding probs like vars; input).

In the next major version after at least 1. is complete:

  1. Sugar

If convenient unique use cases can be demonstrated, and after 1. (& 2.) are done:

  1. Accessing DR properties (pending input about code complexity, utility).
  2. Accessing DR variables (pending input).
matthew-dean commented 9 years ago

That seems ok. I think #1 could be a PR before #2, so both #1 and #2 wouldn't have to land simultaneously. I would leave that up to whichever developer wants to take this on.

4 / #5 - Dunno. I would say more "if necessary" than "if convenient". That is, as we've discussed it more, I feel like the burden of proof should be on demonstrating value over other namespacing in order to add to the code base.

My vote at this point would be to mark this "ready for implementation" for 1,2,3 and tabling 4/5 indefinitely. Possibly opening 4/5 after a PR would close this issue. Definitely 3 should be in its own pull request after 1/2 because it needs to come with a major version increment, and so should come with doc updates / release 3.0 discussion etc. 1 & 2 are a major win but are a minor version change, so they can land anytime (with sufficient testing yadda yadda).

matthew-dean commented 9 years ago

@calvinjuarez Looking at your gist again, I think it covers the feature quite well for what could be implemented as the first step. But at this point other core people should put in their $0.02. @less/admin

calvinjuarez commented 9 years ago

I feel like the burden of proof should be on demonstrating value over other namespacing in order to add to the code base.

I can get behind that. I've updated the comment to read more that way.

Here's the link to the gist again (so folks don't have to go looking through the thread): https://gist.github.com/calvinjuarez/5900c072b19e45677e98

cloudhead commented 9 years ago

I haven't followed all the history here, and will leave the decisions to the team, but why conflate css selectors with variable namespacing? It makes more sense to use files for that, ex:

globals.less

@foo: 12px;
@bar: 14px;

main.less

@import globals as globals;

body {
  font-size: @globals.foo;
}
seven-phases-max commented 9 years ago

@import globals as globals;

It's limited to a file namespacing only and has only single level. While #ns/.ns namespacing is unlimited and can be used for files as well. In fact we do not even invent anything really new here (beside syntax) but just extend already present feature.

matthew-dean commented 9 years ago

@cloudhead - What @seven-phases-max said.

Along with that, it wouldn't lend itself to overriding a Less library's namespaced variables as cleanly, since a file imported once, by default, will not be imported again.

As well, it limits the pattern of namespacing with depth. In my use case, I want to be able to do this.

body {
  font-size: ${ #library.themes.flat.fonts@base-size };
}

I'd already tried to build something like:

.box {
  .set-border-size(${ #library.ui.borders@size });
}

I stopped building when I realized there was no way to do what I wanted. Or.... there sort of was but not without a lot of verbosity for the library and an unfriendly amount for any end user. (I want a user to be able to set/override namespaced variables in a friendlier way than the convention of declaring globals like @libary-ui-borders-base-border-size: 2px;)

matthew-dean commented 9 years ago

To be more clear (since I wrote that in a hurry), while the referencing pattern is similar...

size: @library-ui-borders-size;
size #library.ui.borders@size;

...the library configuration (overriding) becomes MUCH cleaner.

// existing convention
@library-ui-borders-size: 2px;
@library-ui-borders-color: red;
@library-ui-borders-border-radius: 4px;

// new supported pattern
#library.ui.borders {
  @size: 2px;
  @color: red;
  @border-radius: 4px;
}

...and of course you don't have to create a new file for each sub-namespace you want to designate.

lukeapage commented 9 years ago

Whatever the syntax, i think it needs to be as unambiguous as possible.

E.g. We have bugs about being able to assign css selectors to variables - we support a few things by accident. Id like to have a special function for selector parsing rather than ~"" so we can parse. E.g. $(. selector). So getting back to the subject in hand, i prefer explicit things e.g. lookup($(. selector), '@prop'). Nicely explicit but probably too long to be useful? Or shorter as suggested @{.selector @var}. If a short syntax ambiguous with a selector is voted, lets lock it down, e.g. Only id selectors, only variables in that selector, no properties.

My worry is that css selectors and values dont mix.. Lets not add more grammar that looks cool but is too similar to everything else that we might get ambiguity in the future.

I like that @cloudhead suggestion is simple, but i agree file level might be too restrictive (but i like your nod to es6!)

@cloudhead originally implemented this in the ruby version with []

seven-phases-max commented 9 years ago

I see I'm probably alone about optional ${} for a shorter syntax... Sad... Fortunately this was not the case when arithmetic ops were decided, otherwise the code we have to write now would look like:

@var: lighten(¢{#111 + saturate(@base-color, ¢{@var - 20%})}, ¢{5 * @depth});

:see_no_evil:


Btw., thinking of it more... What about [#ns @var] instead of ${#ns @var} then? (sure, this can't be used in a selector interpolation but still...).

matthew-dean commented 9 years ago

What about [#ns @var] instead of ${#ns @var} then? (sure, this can't be used in a selector interpolation but still

Because:

[#ns @var][data-var] {
}

The first one is looking up a value and replacing it in the selector, the second is selecting an element with that attribute. If the response is "then we won't interpolate", then it's an arbitrary distinction from other variables. Or we could say "then we'll just assign it to another variable", then it's trying to workaround a problem that we've created. This keeps it consistent with variables:

${#ns@var}[data-var] {
  ${#ns @prop-name}: value;
}

We have bugs about being able to assign css selectors to variables

I think I probably said somewhere in this thread that perhaps we could solve both, but I think we can keep it simple by having ${} return values, and not references. So at this point I would agree in keeping it simple and not try to solve selector / mixin assignment to variables. That way we won't have any ambiguity, and we won't need to be restrictive about it.

Specifically:

Only id selectors, only variables in that selector, no properties.

That's probably a bit too restrictive and might cause confusion, because it would be splitting the namespace feature to work differently from mixin / selectors in a namespace. That is: we should and do define what is a namespace, so if we allow reference within a namespace, we have to still be talking about the same thing.

matthew-dean commented 9 years ago

@seven-phases-max Btw I respect what you're saying and your goal to make as clean a syntax as possible. Yet I also agree with @lukeapage that, at times, the desire for brevity in syntax has been a detriment to features or has caused confusion for users. I feel that ${} splits the difference. It doesn't conflict with other declarations, it resembles a known feature in @{} variable referencing, so it has an intuitive result, it's not ambiguous, yet it's not really verbose.

calvinjuarez commented 9 years ago

What if we extend @{} to allow accessing namespaced variables (e.g. @{#ns var}) and then propose ${} as just the property lookup (e.g. ${#ns prop})? That would mean that we could implement variable accessing without worry of any added ambiguity. A nice side-effect would be that variables will always be accessed with @, which would keep them conceptually distinct from properties.

matthew-dean commented 9 years ago

@calvinjuarez - You, my friend, are a fucking genius.

You're right, that would effectively make @ = variables, and $ = properties, and they would both match their reduced (non-namespaced) forms of @var and $prop. That would simplify the whole concept tremendously, since we're not adding a "syntax for namespacing", we would just be adding namespacing to existing syntax (although, technically, prop accessing is not added yet).

You win the Internets today. I love this idea.

calvinjuarez commented 9 years ago

Well, this thread has seen essentially that suggestion before. :P #fullCircle I'll update the gist.

seven-phases-max commented 9 years ago

@{#ns var} ${#ns prop}

Ok, but what would be a syntax for accessing/defining just selector then? (E.g. @var: ?{#ns div};).

matthew-dean commented 9 years ago

@seven-phases-max I think that's a separate issue. To quote myself:

I think I probably said somewhere in this thread that perhaps we could solve both [accessing values and selectors], but I think we can keep it simple by having ${} return values, and not references. So at this point I would agree in keeping it simple and not try to solve selector / mixin assignment to variables. That way we won't have any ambiguity, and we won't need to be restrictive about it.

I think @lukeapage had a good comment about not trying to be over-clever with syntax to the point of ambiguity. So if accessing just selector is needed (and I'm not convinced it is), that should be tracked as a separate issue with its own solution.

matthew-dean commented 9 years ago

Well, this thread has seen essentially that suggestion before

Ha, yes, true. I know Luke had suggested that very thing with variables, but then properties got in and confused things. That is, we started to debate if @{} would access vars and properties, which didn't really make sense either. Later, separately, we brought in the idea of $ for properties, and then that made it into this thread, which was important in order to figure out the balance between the two, but then I was suggesting it for more than one thing, including vars, which seemed a little muddy. It was the reverse problem we had in 2014.

So yes, I didn't mean to suggest it was entirely your idea--there are a lot of brilliant people here--just that you simplified and clarified 3 different threads made over a year with one simple suggestion. In the end, you brought it all together, so I'm giving you credit for that. :-)

@seven-phases-max Just so that I don't totally discard your question, I think at this point I would lean towards selector() over $() (or ${}) for selector references for the sake of clarity.

seven-phases-max commented 9 years ago

So if accessing just selector is needed (and I'm not convinced it is), that should be tracked as a separate issue with its own solution.

Yes, but if you take $ symbol solely for a property we'll have to invent another one for selectors too... Hence what I'm concerned of: so far $ was also mentioned as a solution syntax for selectors too and it's not quite clear which one is actually in favour. Hence was my question, reserving some syntax for a feature w/o taking into account other features that pretend for exactly the same syntax is a bit...

Technically, originally for the selector stuff, the sketching syntax proposal was something like $(#ns > div) (i.e. function-like call parens), so there's still room for both, but having:

@a: ${#ns > something}; // `something` is a property
@b: $(#ns > something); // `something` is a tag selector

is exactly what goes against those things you quoted above.

matthew-dean commented 9 years ago

Right. It would go against what I quoted. So I'm saying I'm against it. That is, I would be against $() for selectors, because it would sit too close to ${}.

And, I'm saying assigning selectors to variables seems like much less of a problem. I'm not sure we need it. So the potential future conflict against a desire to write $() seems like a non-issue at this point. I think it's a good direction to not mix returning references and returning values within the same syntax.

seven-phases-max commented 9 years ago

I'm not sure we need it.

So you mean you don't need a hypothetical each to invoke an arbitrary parametric mixin as its callback? ;)

matthew-dean commented 9 years ago

Touché. Not necessarily. I think, in that example, the assignment to a variable was just to allow the variable to be passed to the each(), but that's not a requirement. For instance, we don't require :extend() to surround the selector portion with another selector designation before the keyword. In other words, we didn't require:

:extend(selector(#ns > something) all);

Another way to put it, if we have a core function in which we're inputting a selector, we should find a way to pass that selector without specially wrapping it or assigning it to a variable, just for the purpose of passing it into the function. If we do, it's just extra syntax that we've forced ourselves to create.

Yes, the outcome of this issue may shift a few of those other pending issues, but I think that's okay. I think this is the more valuable one to get right.

calvinjuarez commented 9 years ago

I don't like $() for selector parsing. It very plainly resembles the jQuery convention, which would be fine, except that jQuery's $() works very differently to how (I understand) the selector function is meant to. What Less needs (and what #1421 is about) is a way to assign a CSS selector to a variable, and not to access an existing entity. jQuery's $('.selector'), though, is all about getting an existing entity. So, if you've been in a jQuery file all day, and then you come across this, you're gonna have a conceptual collision.

.selector {
  min-height: 1px;
  width: 100%;
}

@var: $(.selector);

As such, to my mind, the similarity to jQuery is a big reason not to use $() for selector parsing, and instead to define something distinct and fresh.

And speaking of distinct and fresh, I think the only symbols as "safe" as $ would be ^ or |. Both are also only used in CSS attribute selectors and don't (afaik) have a specific meaning in Less yet. Though if not $, I think parse-selector() or a whole other syntax would be better.

matthew-dean commented 9 years ago

@calvinjuarez Agree for the same reasons. It looks like jQuery, but isn't. But, as I said, my recommendation is that we move that discussion to issue... #2270 ? And narrow the scope of this issue back to accessing within namespaces.

calvinjuarez commented 9 years ago

:+1: sounds good. Sorry about that.

matthew-dean commented 9 years ago

No need to be sorry. Hey, if at the end, we get something cool done, it's all good. :smile:

rjgotten commented 9 years ago

@calvinjuarez And speaking of distinct and fresh, I think the only symbols as "safe" as $ would be ^ or |.

What about &?

It's already being used as a template token to indicate 'previous selector set' when used inside a selector declaration. Might as well make that go full-circle and create a &(<selector>) function to capture a (list of) selector(s) into a (list of) string(s)...

matthew-dean commented 9 years ago

@rjgotten Can you move selector access discussion to #2270 or #2481 so that we can finalize this one (namespaced vars)? I think this is otherwise pretty close to ready.

calvinjuarez commented 9 years ago

@matthew-dean I think #1328 #1421 would be the best place for the selector parsing discussion (or a new, consolidated issue).


For this thread, are there any objections to the following for namespaced variable accessing?

@{#ns var} // and `@{#ns > var}` (w/ `#ns@var` as sugar in the next major version)

Then this can be marked as "ready", and we can move the property access discussion (${#ns prop}) to #2433 (#76, #6).

matthew-dean commented 9 years ago

No objections to those variants. I also think prepending @ to the var name inside the braces (as in @{#ns @var}) could be optional if it feels more logical to a particular developer. It doesn't change the meaning, so it seems nice as an option, in case they want to see the variable referenced as it was written within the namespace. But if there are objections to that form within this thread, I'm not attached to it. It was brought up at some point.

chharvey commented 9 years ago

this feature would be very similar to maps in Sass. hopefully the syntax for retrieving a value will be better than map-get().

matthew-dean commented 8 years ago

Despite this seeming close to final syntax, I think this syntax needs to be revisited, based on discussion in #2767 and less/less-meta#10.

But not a total revisiting. @seven-phases-max's arguments in this thread toward #ns[prop] and @dr[prop] as aligning under a single behavior make sense is we move towards aligning all the behavior of rulesets in terms of scoping.

That is, if you support DR variable access (which aligning ruleset behavior may allow), then @{@dr@var} starts to not make any sense.

And @lukeapage's concerns about mixins introducing constants within scope might be lessened if we make scoping rules a bit more robust.

In short, I would say this should be part of a larger syntax review in 3.0 (as part of the roadmap proposal) to make sure all these pieces together make sense.

matthew-dean commented 8 years ago

As I mentioned in the comment above, this discussion got reset a bit because of changes that are part of some syntax and behavior clean-up discussions for 3.0. Because the discussion about syntax covers more than just this issue (but consistency with other 3.0 proposals), I'm going to close this issue in favor of the discussion here: https://github.com/less/less-meta/issues/12.

It would be great if anyone involved in this discussion could give their 2 cents on that issue.