I run this Sass code:
$a: 1;
#if 2 + 2 == 4 {
$a: 2;
}
#debug $a;
I expect to see 2. The output, however, is:
Line 5 DEBUG: 1
I understand that Sass creates a new $a variable inside the #if scope. How can I change this behaviour and assign a value to the global $a?
I use Sass 3.4.0.
As you're using Sass 3.4+, you should append the !global flag to your variable declaration:
$a: 1;
#if 2 + 2 == 4 {
$a: 2 !global;
}
#debug $a; // will output 2
The original SASS_REFERENCE on variable declaration stated:
"Variables are only available within the level of nested selectors
where they're defined. If they're defined outside of any nested
selectors, they're available everywhere.
but the SASS_CHANGELOG of 3.4+ shows that this behaviour has changed:
All variable assignments not at the top level of the document are now
local by default. If there’s a global variable with the same name, it
won’t be overwritten unless the !global flag is used.
For example, $var: value !global will assign to $var globally. This behavior can be detected using feature-exists(global-variable-shadowing).
By trial-and-error, I found a solution: I have to add !global in the assignment.
$a: 1;
#if 2 + 2 == 4 {
$a: 2 !global;
}
#debug $a;
Related
How will Kotlin work the following code?
Will a collection of 5000000 integers be created as temporary collection or will the filter feed its result immediately to the forEach which means, that only 20 integers will be looked at?
If not, how would I be able to avoid the intermediate collection?
Code:
class Tests {
#Test
fun test() {
var counter = 0
(1..10_000_000).filter { it % 2 == 1 }.forEach {
counter++
if (counter > 10)
return
}
}
}
Your code sample uses operations on Iterable<T>, which works eagerly: the .filter { ... } call will process the whole range and produce a list storing intermediate results.
To alter that, consider using Sequence<T> (e.g. with .asSequence()) that works lazily, so that the intermediate operations such as .filter { ... } produce another lazy sequence and only do the work when items are queried by terminal operations such as .forEach { ... }:
(1..10000000).asSequence()
.filter { it % 2 == 1 }
.forEach { /* ... */ }
See: Kotlin's Iterable and Sequence look exactly same. Why are two types required?
You can actually see the answer to your question pretty quickly by just adding println(it) into filter:
//...
.filter {
println(it)
it % 2 == 1
}
//...
You'll see every number printed. That's because your processing works eagerly as explained here.
As already suggested, lazy Sequences to the rescue: (1..10_000_000).asSequence()
Now, the println(it) in filter will only print the numbers 1..21, which is definetly preferable in your example.
I would like to write a proc which can accept dict as an optional argument or create new if none was given. My attempt, however, fails with
too many fields in argument specifier "dictionary [dict create]"
proc getOpts { {dictionary [dict create]} } {
upvar $dictionary dct
for { set i 0 } { $i < $::argc } { incr i } {
set key [lindex $::argv $i]
if { [string index $key 0] == "-" } {
incr i
dict set dct [string trimleft $key "-"] [lindex $::argv $i]
} else {
dict set dct $key ""
}
}
}
As dictionaries are pure values, I thought this could work. It looks I might have been wrong. Still, I would like to know why it doesn’t work.
The reason it does not work is that the argument variable list is a true list, not a command evaluation context. That means the [dict create] is getting parsed as two separate words, and proc doesn't like that. Fortunately, a dict create with no other arguments is just another way of saying the empty string: use {} or "" instead.
The bigger problem is that you are using that with upvar; you probably don't want to do that. The right approach is likely to be to not do the variable binding, and instead to just return the dictionary from the procedure: the caller can save it in one of its own variables if it cares to.
I use require.js in my job, when I run jshint
it will tell me this:
line 11, col 1, 'define' is not defined.
I want to do this:
if is define not defined, ignore,
if is others not defined, tell me the error
how can I write in jshint.rc?
I suppose this is because define is actually defined, just not in that file.
You need to tell jsHint that define is a valid global symbol.
Add this line at the beginning:
/* global define */
or
/* global define,$,require,whatever */
to prime the global symbol check table.
In jshint.rc, you can set:
{
"define" : true
}
or if define is not a known library,
{
"predef" : [
"define"
]
}
(see for example this link).
In SCSS, I have a mixin that takes a list and checks its length, as follows:
#mixin foo($list){
#debug length($list);
}
When I pass a list of more than two lists ($a, $a) as follows,
$a: (1, 2, 3);
#include foo(($a, $a));
the length function counts that there are two $a-s inside of ($a, $a), and returns the result:
DEBUG: 2
but when I pass a list that consists of a single list ($a) as follows,
#include foo(($a));
it seems that the list $a is decomposed, and the length function counts the three elements in $a instead of counting the number of $a-s in ($a), and returns the result:
DEBUG: 3
It does not make difference if I embed the list further. All of the following return the same result:
#include foo($a);
#include foo(($a));
#include foo((($a)));
Is this an expected feature? Why does this happen, and is there a way to return 1 in these cases?
In Sass, parentheses are used to indicate order of operations, not to indicate that you have a list with a single element.
In Sass 3.3, adding a trailing comma will automatically turn your value into a list:
$foo: 1, ;
What you may be wanting to do instead is have your mixin take a variable number of arguments and use them as a list. That would look like this:
#mixin foo($list...){
#debug length($list);
}
.foo {
#include foo(1);
}
.foo {
#include foo(1, 2);
}
.foo {
#include foo((1, 2));
}
The console gives the desired results:
DEBUG: 1
DEBUG: 2
DEBUG: 1
If you do this, however, the list must be the last argument of the mixin (or function).
I am trying to make a variadic mixin in LESS. To this end I use the following syntax for my mixin :
.mixin (#a; #rest...) {
// #rest is bound to arguments after #a
// #arguments is bound to all arguments
}
But I don't know how to manipulate #rest and read to the last parameters of the mixin.
This is my code :
.color () { }
.color (#shade) {
#id {
background-color : rgb(#shade, #shade, #shade);
}
}
.color (#shade, #rest...) {
#id {
background-color : rgb(#shade, #shade, #shade);
}
.color(#rest);
}
.color(200, 160);
As you guess, this mixin should examinate the entire list of parameters, and colour the background of my <div id="id"> with the shade of grey corresponding to the last parameter of the mixin (in this case, rgb(160, 160, 160)).
But when I compile this code with less-1.4.1.js, I get the following error :
SyntaxError: error evaluating function `rgb`:
color functions take numbers as parameters
So how to access to the second, third, fourth... parameters of the mixin ?
Thanks a lot for your advices, and have a nice week-end !
EDIT
This works perfectly, thanks a lot !
However I would like to ask an other question. Let's say that my mixin is variadic to the extent that it requires at least one parameter which has nothing to do with the rest of the arguments (e.g. a string or an other number), but which has to be processed, so that possible calls to the previous mixin could be :
.color("first argument", 200, 160);
.color(-42, 200, 160);
.color(3, 200, 160); // 3 doesn't need to be processed in the loop
In other words, the .loop should examinate all the parameters of the mixin starting from the second and apply a different process to the first argument. So I need to change the skeleton of the mixin into something like this :
.color(...) {
...; // Handling the first parameter
.loop (#arguments); // Handling the rest of the parameters
}
But in your solution, the variable #arguments contains the entire list of arguments, including the first. How to exclude it from the list, without playing on isnumber() ?
I precise that actually in my project, each of the parameters starting from the second are processed, so that :
.loop(#list, #index: 1, #shade: NULL) when not (isnumber(#list)) and (isnumber(extract(#list, #index))) {
.loop(#list, (#index + 1), extract(#list, #index));
}
becomes
.loop(#list, #index: 1, #shade: NULL) when not (isnumber(#list)) and (isnumber(extract(#list, #index))) {
.loop(#shade);
.loop(#list, (#index + 1), extract(#list, #index));
}
and this process doesn't consist in simply changing the background color of a fixed <div> ;) But I wanted to simplify my question.
Thanks a lot for your answers and precious advices !
Edit, again : what you recommend to me works perfectly, Martin. Thanks again !
Less gets confused with your second and third .color mixin, as they can both take just one argument, and if #rest is passed to the mixin as an argument and is not numeric (i.e. a list or empty) it causes more problems. Also #rest... and ... are tricky with multiple mixins with the same name - it is better to pass the arguments to another set of mixins (as a list to a single argument) and then switch between them using guards or the number of arguments they can take.
I would structure the mixins a bit differently (and add a helper mixin .loop that does the looping according to what is passed to .color).
The two mixins would then work like this:
.color: passes all arguments in #arguments to a single argument in mixin .loop
.loop: if the argument is neither a list nor a numeric value -> no output
.loop: if multiple arguments in a list -> loop through the list until you reach the last numeric value (or rather stops when it meets the first nonnumeric argument)
.loop: when reached the last parameter return output based on its value
.loop: if parameter is a single value -> return output based on the single parameter
in Less this could be done like this:
.loop(#list, #index: 1, #shade: NULL) when not (isnumber(#list)) and not (isnumber(extract(#list, #index))) and not (isnumber(#shade)) {}
.loop(#list, #index: 1, #shade: NULL) when not (isnumber(#list)) and (isnumber(extract(#list, #index))) {
.loop(#list, (#index + 1), extract(#list, #index));
}
.loop(#list, #index: 1, #shade) when not (isnumber(#list)) and not (isnumber(extract(#list, #index))) {
.loop(#shade);
}
.loop(#shade) when (isnumber(#shade)){
#id {
background-color: rgb(#shade, #shade, #shade);
}
}
.color (...) {
.loop(#arguments);
}
and if you call now something like this:
.color(120,160);
the output CSS will look like this:
#id {
background-color: #a0a0a0;
}
which corresponds to the value of the last argument -> rgb(160,160,160)
This now has an output only for the last argument in the list. If you want to do something for each argument, you do so in the second .loop mixin (the actual loop) and can get rid of the third one that is used only to separate the last iteration step from the rest of the loop.
Edit:
To your additional question "How to deal differently with certain arguments and what to do when they are not numeric?" - > General answer: you can always adjust the guards, and add additional mixins for the specific cases.
For example, if you want to treat the first argument (or any argument) differently using the .loop, you can add an additional .loop mixin - like this:
.loop(#list) when not (isnumber(#list)) {
/* do something with the first argument */
#first_argument: extract(#list, 1);
/* start the loop at the second argument:*/
.loop(#list, 2);
}
with the rest left as is, this should do what you want:
save your "first argument" from the #arguments into a variable (or you can do with it whatever you want)
start the loop at the second argument and continue until it reaches the last numeric argument (as shown above)
As said before, this is just an example illustrating how to do what you asked ... but you will have to play with it and design the guards and mixins accordingly to your desired outcome and your specific problems.
In the loop you can do something to each argument ... and you can do different things to numeric and nonnumeric arguments (you just need to adjust the conditions in the guards), you can check also if the arguments have specific units and so on. All this is simple as you are merely iterating through a list using the extract() function and incrising the #index variable.
In the case the first argument / first couple arguments have a specific assignment you can use #rest in the same way as I show with #arguments and do something with the first argument already in the .color mixin before you send the #rest to the .loop. You would do something like this:
.color (#first, #rest...) {
/* do something with the first argument */
#first_argument: #first;
/* send the rest to the loop */
.loop(#rest);
}