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

Fixes #2270 - Adds each() function to Less functions #3263

Merged
merged 10 commits into from
Jul 11, 2018

Conversation

matthew-dean
Copy link
Member

@matthew-dean matthew-dean commented Jul 4, 2018

Fixes #2270

Copy link
Member

@calvinjuarez calvinjuarez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failed Travis CI build for Node 8?

return items;
};

functionRegistry.addMultiple({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the movement of the functions into the file where they're most relevant!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

key = new Dimension(i);
value = item;
}
newRules.push(new Declaration('@value',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are special reserved variables now, I wonder if we make them less likely to conflict with variable names developers might be using? Like @__value or @VALUE? Is there precedent for reserved variable names?

On a related note, I know "key" and "index" have subtle flavor differences, but I wonder if we minimize reserved variables by just using either one or the other. Is there a case where we'd need both that I'm overlooking?

Copy link
Member Author

@matthew-dean matthew-dean Jul 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well:

a) These vars are only bound specifically within the context of this function, so how would this possibly conflict?
b) Less already binds an @arguments in the context of mixins, so it would be strange to start suddenly namespacing injected vars in that way.

On a related note, I know "key" and "index" have subtle flavor differences, but I wonder if we minimize reserved variables by just using either one or the other. Is there a case where we'd need both that I'm overlooking?

You can iterate an each() over a ruleset, which will then have, for each entry (declaration), a @key (property or var name), @value (value), and @index (numerical position). Unless it should be @name instead of @key ?

Copy link
Member

@calvinjuarez calvinjuarez Jul 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Less already binds an @arguments in the context of mixins...

Precedent wins for me.

I think @name is probably more likely to have some global value assigned to it by authors, so I think @key is probably better. This would be the only kind of conflict I could see happening with any of these reserved variables.

Would there be any value in warning an author when s/he assigns a value to a variable that shares its name with a "reserved" var? Nothing that would block compiling, but just to make the dev aware?

TL;DR: I'm convinced. No changes needed here. My only other thought would be @i instead of @index, maybe.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Along similar lines, I think better to be explicit (@index vs @i, and also precedent of full names)

Copy link
Contributor

@rjgotten rjgotten Jul 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides; if an author desperately wants a short-hand because their loop-body contains long lines of code they want to condense: nothing is preventing them from doing a quick @i : @index, right?

And for formal parameters, it's better to have formal names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And for formal parameters, it's better to have formal names.

Yep.

@i: (@index - 1);

each(@value; {
@a: extract(@alpha, (@i * 2 + @key));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having trouble following this test. Is it to test calculations with index and key? Maybe we split it into 2 tests, one to test loops in loops, and another to test calculations? Or we could just add comments to clarify what's being tested.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that actually threw me when I went back and saw it, even though I wrote it (a couple years ago). Basically it's just demoing that you can get a reference the scoped index of parent in a nested loop. So in an loop of a loop, you can get parent values / indexes along with local by assigning them to a different var in the parent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... 🤔 this won't actually work the way I had it before, because of lazy evaluation. If you do @i: @index for example, it's evaluated when called.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I'm wondering what to do about this. Technically you can nest each(), but if you can't specify your var names, and vars are lazy evaluated, then you can't reference the "parent" index/key/value. Does that matter?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm...yeah, loops would need to expose them as different variables...maybe we expose each as a list/map?

each(@list1, {
  @value-loop1: @each[@1][value]; // or @each[@1][]
  @key-loop1: @each[@1][key];
  @index-loop1: @each[@1][index]; // or @i-loop1: @each[@1][i];

  each(@list2, {
    @value-loop2: @each[@2][value]; // or @each[@2][]
    @key-loop2: @each[@2][key];
    @index-loop2: @each[@2][index]; // or @i-loop2: @each[@2][i];
  })
})

Copy link
Contributor

@rjgotten rjgotten Jul 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you need to go the generic route and add a function that can be used to selectively force in-place/eager evaluation? Would maybe help with the &() feature as well, since that also needs to be eager.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you need to go the generic route and add a function that can be used to selectively force in-place/eager evaluation? Would maybe help with the &() feature as well, since that also needs to be eager.

Can you clarify? Note that I wrote this comment before defining / implementing the anonymous mixin syntax. I really don't think we want to change the behavior of scoped vars.

Copy link
Contributor

@rjgotten rjgotten Jul 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just something that I was musing about.

There is - in a way - a method already to force eager evaluation of a variable; it has to be done before offering the variable's value to the function in a function call node. The 'problem' there is that the evaluation of the actual function to which the variable is passed, is still lazy.

i.e. in @a: foo(@b) @b might be eagerly evaluated when foo executes, but the execution of foo itself is still lazy and depends on tapping / accessing @a.

But if there were a way to force the evaluation of a function like foo to be internally eager and just cache its evaluated value until its pulled for by a lazy execution of a larger expression or chain of variable assignments in which foo(@b) partakes, then in effect @b would have been evaluated eagerly.

It means you would be able to force-eval loop variables at the correct time and possibly support other interesting / complex scenarios that have problems with lazy evaluation right now.

Ofcourse; with custom parameter names now introduced to each(), these problems should be resolved already. There is no longer a lazy chain of @index (or @key or @value) variable-aliasing assignments to walk through. So the point - atleast for this PR - no longer applies.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, yeah for this one, it's no longer an issue once you can name vars.

Do you approve of this PR as written then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@calvinjuarez Also it would be good to get your sign-off if good too, since it's a new syntax construct for Less. If there's hesitation about it, let me know.

@matthew-dean
Copy link
Member Author

@calvinjuarez

See new tests and parser updates.

  // nested each
  each(10px 15px, 20px 25px; { 
    // demonstrates nesting of each()
    each(@value; #(@v, @k, @i) {
      nest-@{i}-@{index}: @v @k;
    });
  });

produces:

  nest-1-1: 10px 1;
  nest-2-1: 15px 2;
  nest-1-2: 20px 1;
  nest-2-2: 25px 2;

Copy link
Member

@calvinjuarez calvinjuarez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do nested .() {} loops work? If so, we should add a test testing that .() defines unique mixins each time you nest.

nest-@{i}-@{index}: @v @k;
});
});

This comment was marked as outdated.

nest-1-2: 20px 1;
nest-2-2: 25px 2;
padding: 10px 20px 30px 40px;
}

This comment was marked as outdated.

@calvinjuarez
Copy link
Member

calvinjuarez commented Jul 11, 2018

This is ready. My final question is just whether the reserved variables @value, @index, and @key are necessary at this point?

To be clear, though, this isn't a blocking comment/discussion by any means. This is good to go.

@matthew-dean matthew-dean merged commit 3f82ef5 into less:master Jul 11, 2018
@matthew-dean
Copy link
Member Author

@calvinjuarez I think the injected vars are nice to have? It just limits the amount of boilerplate you have to write.

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

Successfully merging this pull request may close these issues.

3 participants